Java 验证码生成工具类-泣血版

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_26486347/article/details/102599884
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.util.Random;

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

/**
 * 验证码生成工具类
 *
 * zkh
 * 2019年8月27日 下午3:28:50
 */
public class ValidCodeUtils {

	// 验证码存放在session中的key
	public static final String CODE_SESSION_KEY = "297ef5196ca786a0016ca789abc60000acbd";
	// 随机产生数字与字母组合的字符串
	private static final String RANDOM_STRING = "23456789ABCDEFGHJKMNPQRSTUVWXYZ";
    // 白色(用于背景)
	private static final Color BG_COLOR = new Color(255, 255, 255);
    // 随机数
	private static final Random RANDOM = new Random();
    // 验证码字体
    private static final String FONT_FAMILY = "宋体";

    /**
     * 生成一个4位数,长100像素,宽30像素的验证码
     */
    public static String generateValidCode(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(4, 100, 30, null, null, null, request, response);
    }
    
    /**
     * 生成一个指定字符串大小的验证码
     */
    public static String generateValidCode(int stringLength, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(stringLength, 100, 30, null, null, null, request, response);
    }
    
    /**
     * 生成一个指定自定义随机字符范围的验证码
     */
    public static String generateValidCode(String randString, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(4, 100, 30, randString, null, null, request, response);
    }
    
    /**
     * 生成一个指定背景色的验证码
     */
    public static String generateValidCode(Color bgColor, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(4, 100, 30, null, bgColor, null, request, response);
    }
    
    /**
     * 生成一个指定字符串大小及自定义随机字符范围的验证码
     */
    public static String generateValidCode(int stringLength, String randString, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(stringLength, 100, 30, randString, null, null, request, response);
    }
    
    /**
     * 生成一个指定字符串大小及背景色的验证码
     */
    public static String generateValidCode(int stringLength, Color bgColor, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(stringLength, 100, 30, null, bgColor, null, request, response);
    }
    
    /**
     * 生成一个指定长宽的验证码
     */
    public static String generateValidCode(int width, int height, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(4, width, height, null, null, null, request, response);
    }
    
    /**
     * 生成一个指定字符串大小及自定义随机字符范围及背景色的验证码
     */
    public static String generateValidCode(int stringLength, String randString, Color bgColor, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(stringLength, 100, 30, randString, bgColor, null, request, response);
    }
    
    /**
     * 生成一个指定长宽及背景色的验证码
     */
    public static String generateValidCode(int width, int height, Color bgColor, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(4, width, height, null, bgColor, null, request, response);
    }
    
    /**
     * 生成一个指定字符串大小及长宽的验证码
     */
    public static String generateValidCode(int stringLength, int width, int height, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(stringLength, width, height, null, null, null, request, response);
    }
    
    /**
     * 生成一个指定字符串大小及长宽及背景色的验证码
     */
    public static String generateValidCode(int stringLength, int width, int height, Color bgColor, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(stringLength, width, height, null, bgColor, null, request, response);
    }
    
    /**
     * 生成一个指定长宽及字体的验证码
     */
    public static String generateValidCode(int width, int height, String fontFamily, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(4, width, height, null, null, fontFamily, request, response);
    }
    
    /**
     * 生成一个指定字符串大小及长宽及字体的验证码
     */
    public static String generateValidCode(int stringLength, int width, int height, String fontFamily, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	return generateValidCode(stringLength, width, height, null, null, fontFamily, request, response);
    }
    
    /**
     * 生成一个指定字符串大小同时指定长宽及自定义字符范围的验证码
     */
    public static String generateValidCode(int stringLength, int width, int height, String randString, Color bgColor, String fontFamily, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	/**
    	 * 1-参数接收
    	 */
    	// 随机字符串及背景色及字体
    	randString = randString == null ? ValidCodeUtils.RANDOM_STRING : randString;
    	bgColor = bgColor == null ? ValidCodeUtils.BG_COLOR : bgColor;
    	fontFamily = fontFamily == null ? ValidCodeUtils.FONT_FAMILY : fontFamily;
        
        /**
         * 2-生成验证码
         */
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        // 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
        Graphics2D g = image.createGraphics();
        // 消除文字锯齿
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); 
        // 消除画图锯齿
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 设置背景色
        g.setColor(bgColor);
        // 图片大小
        g.fillRect(0, 0, width, height);
        // 绘制干扰线-粗线/贯穿线(两条)
        drowLine(g, width, height);
        // 绘制干扰线-细线(千分之一)
        for (int i = 0, len = (int) (0.001 * width * height); i < len; i++) {
            drowLine2(g, width, height);
        }
        // 添加噪点(千分之五)
 		for (int i = 0, len = (int) (0.005 * width * height); i < len; i++) {
 			image.setRGB(RANDOM.nextInt(width), RANDOM.nextInt(height), RANDOM.nextInt(255));
 		} 		
 		// 绘制随机字符
        String randomString = "";
        for (int i = 1; i <= stringLength; i++) {
        	randomString = drowString(g, randomString, stringLength, i, width, height, randString, fontFamily);
        }
        // 使图片扭曲
        shear(g, width, height, bgColor);
        // 清除/销毁Graphics2D,避免内存溢出
        g.dispose();
        
        /**
         * 3-将生成的随机字符串保存到session
         */
        HttpSession session = request.getSession();
        session.removeAttribute(CODE_SESSION_KEY);
        session.setAttribute(CODE_SESSION_KEY, randomString);
        
        /**
         * 4-设置响应头部,并将验证码以流的形式返回给客户端
         */
    	// 设置相应类型,告诉浏览器输出的内容为图片
    	response.setContentType("image/jpeg");
    	// 设置响应头信息,告诉浏览器不要缓存此内容
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expire", 0);
        try {
            // 将内存中的图片通过流形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            System.out.println("======验证码生成异常-->将内存中的图片通过流动形式输出到客户端失败======");
        }
        
        return randomString;
    }
    
    /**
     * 校验验证码
     */
    public static boolean checkValidCode(String validCode, HttpSession session) {
    	// 从session中获取随机数
		String RANDOM = (String) session.getAttribute(CODE_SESSION_KEY);
		if (RANDOM == null) {
			return false;
		}
		// 忽略大小写,比较字符串是否相等
		if (RANDOM.equalsIgnoreCase(validCode)) {
			return true;
		} else {
			return false;
		}
    }
    
    /**
     * 绘制干扰线
     * 描述:绘制直线-粗直线,贯穿线
     * x1 - 第一个点的 x 坐标。
	 * y1 - 第一个点的 y 坐标。
	 * x2 - 第二个点的 x 坐标。
	 * y2 - 第二个点的 y 坐标
     */
    private static void drowLine(Graphics2D g, int width, int height) {
        int x = RANDOM.nextInt(width/10);
        int y = RANDOM.nextInt(height*6/10) + height*3/10;
        int xl = RANDOM.nextInt(width/10) + width*9/10;
        int yl = RANDOM.nextInt(height*6/10) + height*3/10;
        g.setColor(new Color(RANDOM.nextInt(101), RANDOM.nextInt(111), RANDOM.nextInt(121)));
        // 线的粗细
        g.setStroke(new BasicStroke(2f));
        g.drawLine(x, y, xl, yl);
    }

    /**
     * 绘制干扰线
     * 描述:绘制细线
     * x1 - 第一个点的 x 坐标。
	 * y1 - 第一个点的 y 坐标。
	 * x2 - 第二个点的 x 坐标。
	 * y2 - 第二个点的 y 坐标
     */
    private static void drowLine2(Graphics2D g, int width, int height) {
        int x = RANDOM.nextInt(width);
        int y = RANDOM.nextInt(height);
        int xl = RANDOM.nextInt(width/2);
        int yl = RANDOM.nextInt(height);
        g.setColor(new Color(RANDOM.nextInt(101), RANDOM.nextInt(111), RANDOM.nextInt(121)));
        g.setStroke(new BasicStroke(1f));
        g.drawLine(x, y, x + xl, yl);
    }
    
    /**
     * 绘制字符串
     */
    private static String drowString(Graphics2D graphics, String RANDOMString, int stringLength, int i, int width, int height, String randString, String fontFamily) {
    	graphics.setFont(new Font(fontFamily, Font.BOLD, height - 4));
    	graphics.setColor(new Color(RANDOM.nextInt(101), RANDOM.nextInt(111), RANDOM.nextInt(121)));
        String rand = String.valueOf(randString.charAt(RANDOM.nextInt(randString.length())));
        RANDOMString += rand;
		graphics.drawString(rand, ((width - 10) / stringLength) * (i - 1) + RANDOM.nextInt(10) + 8 - stringLength, height - 8);
        return RANDOMString;
    }

    /**
     * 使图片扭曲
     */
	private static void shear(Graphics g, int w1, int h1, Color bgColor) {
        shearX(g, w1, h1, bgColor);
        shearY(g, w1, h1, bgColor);
    }
    private static void shearX(Graphics g, int weight, int height, Color bgColor) {
        int period = RANDOM.nextInt(2), frames = 1, phase = RANDOM.nextInt(2);
        for (int i = 0; i < height; i++) {
            double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
            g.copyArea(0, i, weight, 1, (int) d, 0);
            g.setColor(bgColor);
            g.drawLine((int) d, i, 0, i);
            g.drawLine((int) d + weight, i, weight, i);
        }

    }
    private static void shearY(Graphics g, int weight, int height, Color bgColor) {
        int period = RANDOM.nextInt(20) + 5, frames = 1, phase = 7;
        for (int i = 0; i < weight; i++) {
            double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
            g.copyArea(i, 0, 1, height, 0, (int) d);
        	g.setColor(bgColor);
            g.drawLine(i, (int) d, i, 0);
            g.drawLine(i, (int) d + height, i, height);
        }
    }
   
}

生成与验证,干净不啰嗦

前端代码

有小伙伴要前端代码那就放个上来,用到了jQuery 、jQuery-Validate、bootstrap-3.3.7,凑活看吧。

<div class="form-group has-feedback">
	<div class="input-group">
		<span class="input-group-addon">验证码:</span>
		<input type="text" id="validCode" name="validCode" data-msg-required="请填写验证码" remote="${ctxPath}/api/checkValidCode" data-msg-remote="验证码不正确." aria-required="true" class="form-control" required="true">
		<span class="input-group-addon">
			<img id="validCodeImg" class="validCodeImg" title="看不清,点击图片刷新" src="${ctxPath}/api/validCode" alt="验证码" style="width:100px;">
			<button id="validCodeRefresh" class="hide" type="button"></button>
		</span>
	</div>
</div>

// 刷新验证码 
$('#validCodeRefresh').click(function(){
	var src = '${ctxPath}/api/validCode?' + new Date().getTime();
	$('#validCodeImg').attr('src', src).removeClass('hide');
});
// 刷新验证码
$('#validCodeImg').click(function(){
	$('#validCodeRefresh').click();
	$('#validCode').focus().val('');
});
// 验证码获得焦点
$('#validCode').focus(function(){
	if($('#validCodeImg').attr('src') == ''){
		$('#validCodeRefresh').click();
	}
});

效果图

猜你喜欢

转载自blog.csdn.net/qq_26486347/article/details/102599884
今日推荐