上文我们使用Kaptcha定制验证码 ,但是样式有些low,甚至很难看清。测试的小伙伴纷纷抗议。。。
解决方案:1:定制验证码的样式,如字体,字号,间隔,颜色等
2:使用数字运算代替字母
之前的验证码
更改后的验证码
废话不多说 上代码:
KaptchaImageCodeConfig
Kaptcha配置 重点代码为properties.setProperty("kaptcha.textproducer.impl", "com.core.code.KaptchaTextCreator"); 含义是指定生成验证码的逻辑
@Configuration public class KaptchaImageCodeConfig { @Bean public DefaultKaptcha getDefaultKaptcha() { DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); // 是否有边框 默认为true 我们可以自己设置yes,no properties.setProperty("kaptcha.border", "yes"); // 边框颜色 默认为Color.BLACK properties.setProperty("kaptcha.border.color", "105,179,90"); // 验证码图片宽度 默认为200 properties.setProperty("kaptcha.image.width", "200"); // 验证码图片高度 默认为50 properties.setProperty("kaptcha.image.height", "36"); // 验证码文本字符颜色 默认为Color.BLACK properties.setProperty("kaptcha.textproducer.font.color", "red"); // 验证码文本字符大小 默认为40 properties.setProperty("kaptcha.textproducer.font.size", "36"); // 验证码文本生成器(生成验证码规则类的位置) 重点!!!! properties.setProperty("kaptcha.textproducer.impl", "com.core.code.KaptchaTextCreator"); // 验证码文本字符间距 默认为2 properties.setProperty("kaptcha.textproducer.char.space", "3"); // 验证码文本字符长度 默认为5 properties.setProperty("kaptcha.textproducer.char.length", "6"); // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize) properties.setProperty("kaptcha.textproducer.font.names", "彩云,宋体,楷体,微软雅黑"); // 验证码噪点颜色 默认为Color.BLACK properties.setProperty("kaptcha.noise.color", "white"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; } }
KaptchaTextCreator
也就是上文对应的验证码逻辑类,该类的逻辑为 生成10以内的运算
public class KaptchaTextCreator extends DefaultTextCreator { private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(","); @Override public String getText() { Integer result = 0; Random random = new Random(); int x = random.nextInt(10); int y = random.nextInt(10); StringBuilder suChinese = new StringBuilder(); int randomoperands = (int) Math.round(Math.random() * 2); if (randomoperands == 0) { result = x * y; suChinese.append(CNUMBERS[x]); suChinese.append("*"); suChinese.append(CNUMBERS[y]); } else if (randomoperands == 1) { if (!(x == 0) && y % x == 0) { result = y / x; suChinese.append(CNUMBERS[y]); suChinese.append("/"); suChinese.append(CNUMBERS[x]); } else { result = x + y; suChinese.append(CNUMBERS[x]); suChinese.append("+"); suChinese.append(CNUMBERS[y]); } } else if (randomoperands == 2) { if (x >= y) { result = x - y; suChinese.append(CNUMBERS[x]); suChinese.append("-"); suChinese.append(CNUMBERS[y]); } else { result = y - x; suChinese.append(CNUMBERS[y]); suChinese.append("-"); suChinese.append(CNUMBERS[x]); } } else { result = x + y; suChinese.append(CNUMBERS[x]); suChinese.append("+"); suChinese.append(CNUMBERS[y]); } suChinese.append("=?@" + result); return suChinese.toString(); } }
CustomCreatImage
当传入验证码之后,随机生成每个字符的颜色,样式。
@Component public class CustomCreatImage { private static final long serialVersionUID = 1L; //给定范围获得随机颜色 public Color getRandColor(int fc, int bc) { Random random = new Random(); if (fc > 255) { fc = 255; } if (bc > 255) { bc = 255; } int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } public BufferedImage creatImage(String code) { int width = 200, height = 40; //生成随机类 Random random = new Random(); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); //获取图形上下文 Graphics g = image.getGraphics(); // 设定背景色 g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); //设定字体 第二个参数为字体为加粗 g.setFont(new Font("Times New Roman", Font.BOLD, 45)); // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到 g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } // 取随机产生的认证码(4位数字) for (int i = 0; i < code.length(); i++) { String rand = code.substring(i, i + 1); // 将认证码显示到图象中 g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); //调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成 g.drawString(rand, 30 * i + 18, 35); } // 图象生效 g.dispose(); return image; } }
CodeController
验证码调用的接口
@Controller public class CodeController { Logger logger = LoggerFactory.getLogger(getClass()); @Autowired CustomCreatImage customCreatImage; @Autowired private DefaultKaptcha defaultKaptcha; @RequestMapping("/code/image") public void imageCode(HttpServletRequest request, HttpServletResponse response) throws IOException { // 1. 获取验证码 String capStr = null; String code = null; //此处调用的是KaptchaTextCreator规则 String capText = defaultKaptcha.createText(); // 显示的验证码 capStr = capText.substring(0, capText.lastIndexOf("@")); // 运算结果 code = capText.substring(capText.lastIndexOf("@") + 1); logger.info("生成的图形验证码是:" + code); // 2. 字符串把它放到session中 request.getSession().setAttribute(CODE_SESSION_KEY, code); // 3. 获取验证码图片 BufferedImage image = customCreatImage.creatImage(capStr); // 4. 将验证码图片把它写出去 ServletOutputStream out = response.getOutputStream(); ImageIO.write(image, "jpg", out); } }