生成如下的验证码
有两种工具生成验证码: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"); } }