java前后端分离怎么生成图形验证码

本文详细介绍了如何在Java环境中使用commons-codec库生成图形验证码,包括验证码的图片生成、字符集选择、颜色随机化以及如何将验证码图片转换为Base64字符串发送给前端。同时,文章还展示了如何在Spring框架下通过RESTful API提供验证码图片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图形验证码作用:防止机器模拟实现接口调用

1.maven中引入commons-codec.jar

	<dependency>
		<groupId>commons-codec</groupId>
		<artifactId>commons-codec</artifactId>
		<version>1.9</version>
	</dependency>

2.控制层

/** 
	 * 响应图形验证码页面 
	 * @return 
	 */  
	@RequestMapping(value="/createValidateCode", method = RequestMethod.GET)  
	@ResponseBody
	public ResponseVO createValidateCode(HttpServletRequest request,HttpServletResponse response){  
	    // 设置响应的类型格式为图片格式  
	    response.setContentType("image/jpeg");  
	    ValidateCode vCode = new ValidateCode(120,40,4,100); 
	    byte[] buff = imageToBytes(vCode.getBuffImg(), "png");
	    //生成图片验证码并将其放入缓存中
	    String uuid = IdGen.uuid();
	    JedisUtils.set(uuid, vCode.getCode(), 10*60);
	    //将图片转换陈字符串给前端
	    Base64 base64 = new Base64();
	    String encode = base64.encodeAsString(buff);
	    //封装数据
	    Map<String, Object> result = new HashMap<String, Object>();
	    result.put("image", "data:image/png;base64,"+encode);
	    result.put("uuid", uuid);
	    return ResponseCode.buildEnumResponseVO(ResponseCode.RESPONSE_CODE_SUCCESS, result);
	}

3.ValidateCode

package com.sml.sz.utils;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.bind.annotation.RequestMapping;

public class ValidateCode {
	
	 // 图片的宽度。  
    private int width = 160;  
    // 图片的高度。  
    private int height = 40;  
    // 验证码字符个数  
    private int codeCount = 4;  
    // 验证码干扰线数  
    private int lineCount = 150;  
    // 验证码  
    private String code = null;  
    // 验证码图片Buffer  
    private BufferedImage buffImg = null;  
  
    // 验证码范围,去掉0(数字)和O(拼音)容易混淆的(小写的1和L也可以去掉,大写不用了)  
    private char[] codeSequence = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',  
            'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',  
            'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9'};  
  
    /** 
     * 默认构造函数,设置默认参数 
     */  
    public ValidateCode() {  
        this.createCode();  
    }  
  
    /** 
     * @param width  图片宽 
     * @param height 图片高 
     */  
    public ValidateCode(int width, int height) {  
        this.width = width;  
        this.height = height;  
        this.createCode();  
    }  
  
    /** 
     * @param width     图片宽 
     * @param height    图片高 
     * @param codeCount 字符个数 
     * @param lineCount 干扰线条数 
     */  
    public ValidateCode(int width, int height, int codeCount, int lineCount) {  
        this.width = width;  
        this.height = height;  
        this.codeCount = codeCount;  
        this.lineCount = lineCount;  
        this.createCode();  
    }  
  
    public void createCode() {  
        int x = 0, fontHeight = 0, codeY = 0;  
        int red = 0, green = 0, blue = 0;  
  
        x = width / (codeCount + 2);//每个字符的宽度(左右各空出一个字符)  
        fontHeight = height - 2;//字体的高度  
        codeY = height - 4;  
  
        // 图像buffer  
        buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  
        Graphics2D g = buffImg.createGraphics();  
        // 生成随机数  
        Random random = new Random();  
        // 将图像填充为白色  
        g.setColor(Color.WHITE);  
        g.fillRect(0, 0, width, height);  
        // 创建字体,可以修改为其它的  
        Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);  
//        Font font = new Font("Times New Roman", Font.ROMAN_BASELINE, fontHeight);  
        g.setFont(font);  
  
        for (int i = 0; i < lineCount; i++) {  
            // 设置随机开始和结束坐标  
            int xs = random.nextInt(width);//x坐标开始  
            int ys = random.nextInt(height);//y坐标开始  
            int xe = xs + random.nextInt(width / 8);//x坐标结束  
            int ye = ys + random.nextInt(height / 8);//y坐标结束  
  
            // 产生随机的颜色值,让输出的每个干扰线的颜色值都将不同。  
            red = random.nextInt(255);  
            green = random.nextInt(255);  
            blue = random.nextInt(255);  
            g.setColor(new Color(red, green, blue));  
            g.drawLine(xs, ys, xe, ye);  
        }  
  
        // randomCode记录随机产生的验证码  
        StringBuffer randomCode = new StringBuffer();  
        // 随机产生codeCount个字符的验证码。  
        for (int i = 0; i < codeCount; i++) {  
            String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);  
            // 产生随机的颜色值,让输出的每个字符的颜色值都将不同。  
            red = random.nextInt(255);  
            green = random.nextInt(255);  
            blue = random.nextInt(255);  
            g.setColor(new Color(red, green, blue));  
            g.drawString(strRand, (i + 1) * x, codeY);  
            // 将产生的四个随机数组合在一起。  
            randomCode.append(strRand);  
        }  
        // 将四位数字的验证码保存到Session中。  
        code = randomCode.toString();  
    }  
  
    public void write(String path) throws IOException {  
        OutputStream sos = new FileOutputStream(path);  
        this.write(sos);  
    }  
  
    public void write(OutputStream sos) throws IOException {  
        ImageIO.write(buffImg, "png", sos);  
        sos.close();  
    }  
  
    public BufferedImage getBuffImg() {  
        return buffImg;  
    }  
  
    public String getCode() {  
        return code;  
    }  
  
    /** 
     * 测试函数,默认生成到d盘 
     * @param args 
     */  
    public static void main(String[] args) {  
        ValidateCode vCode = new ValidateCode(160,40,5,150);  
        try {  
            String path="D:/"+new Date().getTime()+".png";  
            System.out.println(vCode.getCode()+" >"+path);  
            vCode.write(path);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
    
    /** 
     * 响应验证码页面 
     * @return 
     */  
    @RequestMapping(value="/validateCode")  
    public String validateCode(HttpServletRequest request,HttpServletResponse response) throws Exception{  
        // 设置响应的类型格式为图片格式  
        response.setContentType("image/jpeg");  
        //禁止图像缓存。  
        response.setHeader("Pragma", "no-cache");  
        response.setHeader("Cache-Control", "no-cache");  
        response.setDateHeader("Expires", 0);  
      
        HttpSession session = request.getSession();  
      
        ValidateCode vCode = new ValidateCode(120,40,4,100);  
        session.setAttribute("code", vCode.getCode());  
        vCode.write(response.getOutputStream());  
        return null;  
    } 
    
    

}

### Java 前后端分离项目中 Redis 的使用 在Java前后端分离架构下,Redis作为缓存数据库被广泛应用来提升应用性能和响应速度。对于提到的开源项目[^1]以及类似的系统[^2],Redis不仅用于存储临时数据如会话信息、配置参数等,还特别适用于验证码管理。 #### 验证码处理中的Redis运用 当涉及到验证码这类短暂存在的验证机制时,可以利用Redis快速读写的特点来进行高效管理和校验。具体实现方式如下: - **生成并保存验证码** 后台服务创建新的图形验证码之后,将其转换成Base64编码字符串形式,并连同唯一标识符一起通过HTTP接口发送至客户端显示;与此同时,在服务器端将该唯一标识符与实际验证码值组合成键值对的形式存入到Redis中,设定一定时间后的自动过期删除策略以防止内存泄漏。 ```java // 将验证码存入Redis, 设置有效时间为5分钟 string key = "captcha:" + uniqueId; string value = captchaText; // 图形验证码文本内容 jedis.setex(key.getBytes(), 300, value); ``` - **验证用户输入** 用户提交表单时携带之前获取到的唯一标识符及填写的内容回到服务器做进一步检验。此时可以从Redis里取出对应的记录进行对比判断是否匹配成功。如果发现不存在对应key或者已经超出了规定时限,则认为此次请求非法而拒绝继续处理下去。 ```java // 获取并核对验证码 String redisValue = jedis.get(("captcha:" + receivedUniqueId).getBytes()); if(redisValue != null && redisValue.equals(receivedCaptcha)){ // 验证通过逻辑... }else{ throw new RuntimeException("Invalid Captcha"); } ``` 上述过程展示了如何借助于Redis完成一次完整的验证码交互流程[^4]。值得注意的是,虽然Session也可以用来暂存此类信息,但在分布式部署场景下面临着跨域共享难题,相比之下采用独立的数据存储解决方案更加灵活可靠[^5]。 #### 关联问题探讨 除了以上提及的技术细节外,关于Java前后端分离模式下的其他方面同样值得深入研究:
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值