上文我们使用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);
}
}