JAVA使用BASE64生成验证码

public void createImage(HttpServletResponse resp, HttpServletRequest request,String xcode) throws IOException {
        TraceLoggerUtil.info("执行微信端图片验证码接口请求参数:xcode{}",xcode);
        switch (random.nextInt(5)) {
            case 0:
                cs.setFilterFactory(new CurvesRippleFilterFactory(cs.getColorFactory()));
                break;
            case 1:
                cs.setFilterFactory(new MarbleRippleFilterFactory());
                break;
            case 2:
                cs.setFilterFactory(new DoubleRippleFilterFactory());
                break;
            case 3:
                cs.setFilterFactory(new WobbleRippleFilterFactory());
                break;
            case 4:
                cs.setFilterFactory(new DiffuseRippleFilterFactory());
                break;
        }
        HttpSession session = request.getSession(false);
        if (session == null) {
            session = request.getSession();
        }
        if (ChkUtil.isEmpty(xcode)) {
            return;
        }

        setResponseHeaders(resp);
        String token = EncoderHelper.getChallangeAndWriteImage(cs, "png", resp.getOutputStream());
        redisService.setex(xcode, token, 5*60);

        session.setAttribute(PubVariable.VERIFICATION_CODE_SESSION, token);
    }

    protected void setResponseHeaders(HttpServletResponse response) {
        response.setContentType("image/png");
        response.setHeader("Cache-Control", "no-cache, no-store");
        response.setHeader("Pragma", "no-cache");
        long time = System.currentTimeMillis();
        response.setDateHeader("Last-Modified", time);
        response.setDateHeader("Date", time);
        response.setDateHeader("Expires", time);
    }

今天遇到一个需求需要将生成验证码的接口修改为可以返回状态的接口。之前的代码是以流的形式直接返回后台,返回值为void。使用的是com.github.bingoohuang的jar包。

但是出现问题是现在需要返回带有状态的json串,然后将图片信息放在参数内,给前端在status为200的时候才展示图片信息。这时候可以将随机验证码图片进行Base64编码之后前端使用。

以下贴代码:

public String createImage(HttpServletResponse resp, HttpServletRequest request
,String xcode,String phone,String from ) {
JSONObject resultObject = new JSONObject();
TraceLoggerUtil.info("执行微信端图片验证码接口请求参数:xcode{},phone{},from{}",xcode,phone,from);
try{
/**
* from =1 的时候需要判断当前手机号是否存在 如果存在直接返回300 手机号已存在
*/
if (!ChkUtil.isEmpty(from) && "1".equals(from)) {
JSONObject phoneJson = JSONObject.parseObject(bgCustomerService.getCustomer(phone));
if (phoneJson.get(com.zw.rule.util.weChatUtil.consts.MsgConsts.RESPONSE_CODE).equals(com.zw.rule.util.weChatUtil.consts.MsgConsts.WECHAT_ERRO_CODE)) {
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_STATUS, com.zw.base.util.MsgConsts.WECHAT_ERROR_STATUS_CODE);
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_MESSAGE, "手机号已存在");
return resultObject.toString();
}
}
/**
* from =2 的时候需要判断当前手机号是否存在 如果存在直接返回300 手机号不存在
*/
if (!ChkUtil.isEmpty(phone) && "2".equals(phone)) {
JSONObject phoneJson = JSONObject.parseObject(bgCustomerService.getCustomer(phone));
if (phoneJson.get(com.zw.rule.util.weChatUtil.consts.MsgConsts.RESPONSE_CODE).equals(com.zw.rule.util.weChatUtil.consts.MsgConsts.SUCCESS_CODE)) {
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_STATUS, com.zw.base.util.MsgConsts.WECHAT_ERROR_STATUS_CODE);
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_MESSAGE, "手机号不存在");
return resultObject.toString();
}
}
// 禁止图像缓存,使得单击验证码可以刷新验证码图片
resp.setHeader("Pragma", "nocache");
resp.setHeader("Cache-Control", "no-cache");
resp.setDateHeader("Expires", 0);
resp.setContentType("image/jpeg");
resp.setHeader("Access-Control-Allow-Origin", "*");
BufferedImage bim = new BufferedImage(100, 40,
BufferedImage.TYPE_INT_RGB);
Font f = new Font("宋体",Font.BOLD ,20);
Graphics2D gc = bim.createGraphics();
//设置字体
gc.setFont(f);
// 设置图片填充颜色
gc.setColor(Color.yellow);
gc.fillRect(0, 0, 100, 40);
// 设置边框颜色
gc.setColor(Color.pink);
gc.drawRect(0, 0, 99, 39);
// 产生4位随机数
Random rand = new Random();
StringBuffer sb = new StringBuffer();
// 设置干扰线颜色
gc.setColor(Color.cyan);
for (int j = 0; j < 30; j++) {
int x = rand.nextInt(99);
int y = rand.nextInt(39);
int x1 = rand.nextInt(6);
int y1 = rand.nextInt(6);
// 往图片里面画干扰线
gc.drawLine(x, y, x + x1, y + y1);
}
for (int i = 0; i < 4; i++) {
int m = rand.nextInt(9);
// 将生成的数字写入到图片中去,int转成string
String str = String.valueOf(m);
// 设置字体颜色
gc.setColor(Color.RED);
gc.drawString(str, i * 20 + 20, 30);
sb.append(m);
}
// 将stringbuffer转成string
String sb1 = String.valueOf(sb);
redisService.setex(xcode, sb1, 5*60);
// 将图片以流的形式输出
ServletOutputStream sos = resp.getOutputStream();
//ImageIO.write(bim, "jpg", sos);
// 创建编码对象
Base64.Encoder base64 = Base64.getEncoder();
// 创建字符流
ByteArrayOutputStream bs = new ByteArrayOutputStream();
// 写入字符流
ImageIO.write(bim, "jpg", bs);
// 转码成字符串
String imgsrc = base64.encodeToString(bs.toByteArray());
resultObject.put("imgsrc",imgsrc);
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_STATUS, com.zw.base.util.MsgConsts.WECHAT_SUCCESS_STATUS_CODE);
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_MESSAGE, com.zw.base.util.MsgConsts.WECHAT_MESSAGE_SUCCESS);
}catch (Exception e){
TraceLoggerUtil.error(e.getMessage(),e);
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_STATUS, com.zw.base.util.MsgConsts.WECHAT_ERROR_STATUS_CODE);
resultObject.put(com.zw.base.util.MsgConsts.WECHAT_RESPONSE_MESSAGE, com.zw.base.util.MsgConsts.SYS_EXCEPTION);
return resultObject.toString();
}
return resultObject.toString();
}

以下代码有变更点:

1.resp.setHeader("Access-Control-Allow-Origin", "*"); 这是由于前端使用ajax访问的时候跨域了,设置这个之后就不会跨域访问

2.Font f = new Font("宋体",Font.BOLD ,20); gc.setFont(f); 这里是由于字体偏小,所以调大字体为宋体20号

3.gc.fillRect(0, 0, 100, 40); gc.drawRect(0, 0, 99, 39); int x = rand.nextInt(99); int y = rand.nextInt(39);

个人理解这些数字都和最后返回的图片有关。返回前端图片为100*40那么 drawRect 的最后两个数字为 100-1 40-1 int x为100-1 int y 为40 -1

4.gc.drawString(str, i * 20 + 20, 30); 这个根据图片的宽和高计算,最终数字的位置为20,40,60,80 高固定在30

以上这些需要根据前端需要自行调节。

前端使用方式为:

<img src=”data:image/jpg;base64,imgcode”> imgcode 就是返回回去的base64位的imgsrc

点击后动态的赋值即可。