生成如下的验证码
有两种工具生成验证码:Captcha 和 kaptcha
二、Captcha验证码的代码 2.1 pom2.2 生成验证码com.ramostear Happy-Captcha1.0.1
只需要添加一行代码即可生成验证码图片,request和response是必须提供的参数。
NUMBER 数字
CHINESE 中文
DEFAULT 数字加英文
WORD 英文
ARITHMETIC 计算
@GetMapping("/captcha")
@ApiOperation(value = "登录模块生成验证码接口")
public void happyCaptcha(HttpServletRequest request, HttpServletResponse response){
System.out.println("======生成一次验证码======");
HappyCaptcha.require(request,response).type(CaptchaType.NUMBER).build().finish();
}
2.3 校验验证码
对验证码进行的校验也是十分简单,也只需要几行代码就可解决。
@PostMapping("/verify")
public String verify(String code,HttpServletRequest request){
//Verification Captcha
boolean flag = HappyCaptcha.verification(request,code,true);
if(flag){
// 校验通过
}
}
2.4 清理验证码
当验证码被使用后,可以通过HappyCaptcha类种的remove()方法将Session中存放的验证码清理掉,避免出现一次验证码多次使用的情况。
@GetMapping("/remove/captcha")
public void removeCaptcha(HttpServletRequest request){
HappyCaptcha.remove(request);
}
三、kaptcha验证码的代码
3.1 pom
3.2 配置类com.github.penggle kaptcha2.3.2
package com.example.demo001.config;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class KaptchaConfig {
@Bean
public DefaultKaptcha getDefaultKaptcha() {
DefaultKaptcha defaultKaptcha=new DefaultKaptcha();
Properties properties=new Properties();
//是否有边框
properties.setProperty(Constants.KAPTCHA_BORDER,"yes");
//验证码文本颜色
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR,"blue");
//验证码图片宽度
properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH,"160");
//验证码图片高度
properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT,"60");
//文本字符大小
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE,"38");
//验证码session的值
properties.setProperty(Constants.KAPTCHA_SESSION_CONFIG_KEY,"kaptchaCode");
//验证码文本长度
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH,"4");
//字体
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体,楷体,微软雅黑");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
3.3 生成验证码
@Resource
private Producer kaptchaProducer;
@GetMapping("verifyCode")
public void createVerifyCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
//响应立即过期
response.setDateHeader("Expires", 0);
//不缓存任何图片数据
response.setHeader("Cache-Control", "no-store,no-cache,must-revalidate");
response.setHeader("Cache-Control", "post-check=0,pre-check=0");
response.setHeader("Pragma", "no-cache");
response.setContentType("image/png");
//生成验证码字符文本
String verifyCode = kaptchaProducer.createText();
request.getSession().setAttribute("kaptchaVerifyCode", verifyCode);
System.out.println(request.getSession().getAttribute("kaptchaVerifyCode"));
BufferedImage image = kaptchaProducer.createImage(verifyCode);//创建验证图片
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "png", out);
//输出和关闭输出
out.flush();
out.close();
}
3.4 校验验证码
public static boolean validate(String registerCode) {
// 获取Session中验证码
Object captcha = ServletUtils.getAttribute(Constants.KAPTCHA_SESSION_KEY);
// 判断验证码是否为空
if (StringUtils.isEmpty(registerCode)) {
return false;
}
// 校验验证码的正确与否
boolean result = registerCode.equalsIgnoreCase(captcha.toString());
if (result) {
// 正确了后,将验证码从session中删掉
ServletUtils.getRequest().getSession().removeAttribute(Constants.KAPTCHA_SESSION_KEY);
}
// 返回验证结果
return result;
}
四、点击验证码的代码
4.1 验证码实体类
import java.io.Serializable;
public class AnchorPoint implements Serializable {
private static final long serialVersionUID = 2L;
private Integer x_iv = 26;
private Integer y_iv = 21;
private Integer x;
private Integer y;
public AnchorPoint(){
this.x = 0;
this.y = 0;
}
public AnchorPoint(Integer x, Integer y){
this.x = x;
this.y = y;
}
public Integer getX() {
return x;
}
public Integer getY() {
return y;
}
public void setX(Integer x) {
this.x = x;
}
public void setY(Integer y) {
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AnchorPoint that = (AnchorPoint) o;
//当X位置小于偏移量进行判段Y轴的偏移量
if(this.x+this.x_iv > that.getX() || this.x - this.x_iv < that.getX()){
//当Y轴的偏移量符合安全距离 判断锚点有效
if(this.y+this.y_iv < that.getY() || this.y-this.y_iv > that.getY()){
return false;
}
}else{
//两个对象的X点保持在偏移量之外无需比较Y轴位置,判定锚点有效
return false;
}
return true;
}
@Override
public int hashCode() {
return 1;
}
@Override
public String toString() {
return "AnchorPoint{" +
"x=" + x +
", y=" + y +
'}';
}
}
4.2 图片生成工具类实现
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.*;
public class DrawCaptchaUtil {
private static int canvasWidth = 300;
private static int canvasHeight = 150;
private static int imgWidth = 300;
private static int imgHeight = 150;
private static int charNumber = 5;
private static int fontSize = 18;
private static int charImgWidth = 20;
private static int charImgHeight = 25;
public static BufferedImage drawImg(LinkedHashMap checkCode,String bkDirPath) throws IOException {
BufferedImage imgCanvas = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_BGR);
Graphics graphics = imgCanvas.getGraphics();
//绘制图形
// graphics.setColor(new Color(0,0,0,0));
graphics.fillRect(0,0,imgWidth,imgHeight);
File bkPath = randomBackGroundImage(bkDirPath);
BufferedImage read = ImageIO.read(Files.newInputStream(Paths.get(bkPath.getAbsolutePath())));
graphics.drawImage(read,0,0,null,null);
//绘制字体
// graphics.setColor(getRandomColor());
//随机在图片中生成5个绘制点每个绘制点半径能不能重叠
Set point = new HashSet<>();
addPoint(point);
Object[] pointArr = point.toArray();
List charList = new ArrayList<>();
for (int i = 0; i < charNumber; i++) {
AnchorPoint p = (AnchorPoint)pointArr[i];
graphics.drawImage(getCharImg(getRandomColor(),charList),p.getX(),p.getY(),null,null);
}
//随机获取3个字符串作为校验对象
Object[] charArr = charList.toArray();
Random random = new Random();
for (int i = 0; i < 3; i++) {
int num = random.nextInt(pointArr.length-i);
String key = (String) charArr[num];
AnchorPoint value = (AnchorPoint) pointArr[num];
checkCode.put(key,value);
//置换位置
Object a = pointArr[num];
pointArr[num] = pointArr[pointArr.length - 1 - i];
pointArr[pointArr.length - 1 - i] = a;
a = charArr[num];
charArr[num] = charArr[charArr.length - 1 - i];
charArr[charArr.length - 1 - i] = a;
}
return imgCanvas;
}
private static File randomBackGroundImage(String dir){
File file = new File(dir);
if(file.isDirectory()){
File[] files = file.listFiles();
Random random = new Random();
int i = random.nextInt(files.length);
return files[i];
}else{
return file;
}
}
private static void addPoint(Set point){
Random random = new Random();
//避免因为坐标点过于特殊导致无法获取下一个坐标点进入死循环,到100置空重新获取
int clearNumber = 0;
//生成前2个点坐标
while (point.size() < 2){
//添加X坐标点
point.add(new AnchorPoint(random.nextInt(canvasWidth/3),random.nextInt(canvasHeight-charImgWidth)));
if(clearNumber == 100){
point.clear();
clearNumber = 0;
}
clearNumber++;
}
clearNumber = 0;
//生成后3个点坐标
while (point.size() < charNumber){
//添加X坐标点
point.add(new AnchorPoint(random.nextInt(canvasWidth-charImgWidth),random.nextInt(canvasHeight-charImgHeight)));
if(clearNumber == 100){
point.clear();
clearNumber = 0;
addPoint(point);
break;
}
clearNumber++;
}
}
private static BufferedImage getCharImg(Color fontColor, List charList) throws UnsupportedEncodingException {
BufferedImage fillRect = new BufferedImage(charImgWidth, charImgHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = fillRect.createGraphics();
g.setColor(new Color(0,0,0,0));
g.fillRect(0,0,charImgWidth,charImgHeight);
g.setColor(fontColor);
Font font = new Font("微软雅黑", Font.BOLD, fontSize);
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(30),0,0);
font.deriveFont(affineTransform);
g.setFont(font);
String charStr = getChineseCharacters();
charList.add(charStr);
g.drawString(charStr,0,charImgHeight-5);
g.dispose();
return fillRect;
}
private static Color getRandomColor(){
Random random = new Random();
return new Color(
random.nextInt(255),
random.nextInt(255),
random.nextInt(255));
}
private static String getChineseCharacters() throws UnsupportedEncodingException {
Integer hightPos, lowPos; // 定义高低位
Random random = new Random();
hightPos = (176 + Math.abs(random.nextInt(39)));
lowPos = (161 + Math.abs(random.nextInt(93)));
byte[] bytes = new byte[2];
bytes[0] = hightPos.byteValue();
bytes[1] =lowPos.byteValue();
return new String(bytes,"GBK");
}
}
五、滑动拼图验证码



