自定义验证码 - kaptcha
1 2 3 4 5 6 7 8 9 10 11 | <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version> 2.6 . 0 </version> </dependency> <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version> 2.3 . 2 </version> </dependency> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | package org.example.captcha; import javax.servlet.http.HttpServletRequest; import java.awt.*; import java.awt.image.BufferedImage; import java.util.Random; /** * @author banjuan * @date 2021/11/30 2:48 下午 */ public class CodeUtil { /** * 将获取到的前端参数转为string类型 * @param request * @param key * @return */ public static String getString(HttpServletRequest request, String key) { try { String result = request.getParameter(key); if (result != null ) { result = result.trim(); } if ( "" .equals(result)) { result = null ; } return result; } catch (Exception e) { return null ; } } /** * 验证码校验 * @param request * @return */ public static boolean checkVerifyCode(HttpServletRequest request) { //获取生成的验证码 String verifyCodeExpected = (String) request.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); //获取用户输入的验证码 String verifyCodeActual = CodeUtil.getString(request, "verifyCodeActual" ); if ( null != verifyCodeActual) { verifyCodeActual = verifyCodeActual.toLowerCase(); } if (verifyCodeActual == null ||!verifyCodeActual.equals(verifyCodeExpected)) { return false ; } return true ; } /** * 宽高可作为参数传入 */ private static final int WIDTH = 110 ; private static final int HEIGHT = 40 ; /** * 传入BufferedImage对象,并将生成好的验证码保存到BufferedImage中 * @param bufferedImage * @return */ public static String drawRandomText(BufferedImage bufferedImage) { Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics(); // 设置画笔颜色-验证码背景色 graphics.setColor(Color.WHITE); // 填充背景 graphics.fillRect( 0 , 0 , WIDTH, HEIGHT); graphics.setFont( new Font( "宋体,楷体,微软雅黑" , Font.BOLD, 26 )); // 数字和字母的组合 String baseNumLetter = "123456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ" ; StringBuilder builder = new StringBuilder(); // 旋转原点的 x 坐标 int x = 8 ; String ch; Random random = new Random(); for ( int i = 0 ; i < 4 ; i++) { graphics.setColor(getRandomColor()); //设置字体旋转角度,角度小于30度 int degree = random.nextInt() % 30 ; int dot = random.nextInt(baseNumLetter.length()); ch = baseNumLetter.charAt(dot) + "" ; builder.append(ch); //正向旋转 graphics.rotate(degree * Math.PI / 180 , x, 24 ); graphics.drawString(ch, x, 24 ); //反向旋转 graphics.rotate(-degree * Math.PI / 180 , x, 24 ); x += 24 ; } //画干扰线 for ( int i = 0 ; i < 6 ; i++) { // 设置随机颜色 graphics.setColor(getRandomColor()); // 随机画线 graphics.drawLine(random.nextInt(WIDTH), random.nextInt(HEIGHT), random.nextInt(WIDTH), random.nextInt(HEIGHT)); } //添加噪点 for ( int i = 0 ; i < 30 ; i++) { int x1 = random.nextInt(WIDTH); int y1 = random.nextInt(HEIGHT); graphics.setColor(getRandomColor()); graphics.fillRect(x1, y1, 2 , 2 ); } return builder.toString(); } /** * 随机取色 */ private static Color getRandomColor() { Random ran = new Random(); return new Color(ran.nextInt( 256 ), ran.nextInt( 256 ), ran.nextInt( 256 )); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | package org.example.captcha; import com.google.code.kaptcha.Constants; import com.google.code.kaptcha.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.imageio.ImageIO; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.awt.image.BufferedImage; import java.io.IOException; /** * @author banjuan * @date 2021/11/30 2:45 下午 */ @Controller public class CodeController { @Autowired private Producer captchaProducer = null ; @RequestMapping ( "/kaptcha" ) public void getKaptchaImage(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpSession session = request.getSession(); response.setDateHeader( "Expires" , 0 ); response.setHeader( "Cache-Control" , "no-store, no-cache, must-revalidate" ); response.addHeader( "Cache-Control" , "post-check=0, pre-check=0" ); response.setHeader( "Pragma" , "no-cache" ); response.setContentType( "image/jpeg" ); //生成验证码 String capText = captchaProducer.createText(); session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText); //向客户端写出 BufferedImage bi = captchaProducer.createImage(capText); ServletOutputStream out = response.getOutputStream(); ImageIO.write(bi, "jpg" , out); try { out.flush(); } finally { out.close(); } } @RequestMapping ( "/verification" ) public void createImageCode(HttpServletRequest request, HttpServletResponse response) throws IOException { HttpSession session = request.getSession(); //禁止缓存 response.setDateHeader( "Expires" , 0 ); response.setHeader( "Cache-Control" , "no-store, no-cache, must-revalidate" ); response.addHeader( "Cache-Control" , "post-check=0, pre-check=0" ); response.setHeader( "Pragma" , "no-cache" ); //设置响应格式为png图片 response.setContentType( "image/png" ); // 生成图片验证码 BufferedImage image = new BufferedImage( 110 , 40 , BufferedImage.TYPE_INT_RGB); String randomText = CodeUtil.drawRandomText(image); session.setAttribute(Constants.KAPTCHA_SESSION_KEY, randomText.toLowerCase()); System.out.println( "验证码->>>" +randomText); ServletOutputStream out = response.getOutputStream(); ImageIO.write(image, "png" , out); out.flush(); out.close(); } @RequestMapping ( "/hellow" ) public String Hello() { return "hello" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package org.example.captcha; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; /** * @author banjuan * @date 2021/11/30 2:59 下午 */ @RestController public class HelloWorld { @RequestMapping ( "/hello" ) public String hello(HttpServletRequest request) { if (!CodeUtil.checkVerifyCode(request)) { return "验证码有误!" ; } else { return "hello,world" ; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | package org.example.captcha; 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; /** * @author banjuan * @date 2021/11/30 3:01 下午 */ @Configuration public class KaptchaConfig { @Bean public DefaultKaptcha getDefaultKaptcha(){ // DefaultKaptcha captchaProducer = new DefaultKaptcha(); // Properties properties = new Properties(); // properties.setProperty("kaptcha.border", "no"); // //properties.setProperty("kaptcha.border.color", "105,179,90"); // properties.setProperty("kaptcha.textproducer.font.color", "black"); // properties.setProperty("kaptcha.image.width", "110"); // properties.setProperty("kaptcha.image.height", "40"); // properties.setProperty("kaptcha.textproducer.font.size", "24"); // properties.setProperty("kaptcha.session.key", "code"); // properties.setProperty("kaptcha.noise.color", "white"); // properties.setProperty("kaptcha.textproducer.char.space", "4"); // properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.FishEyeGimpy"); //// properties.setProperty("kaptcha.background.clear.from", "0,255,0"); //// properties.setProperty("kaptcha.background.clear.to", "255,255,0"); // properties.setProperty("kaptcha.textproducer.char.length", "4"); //// properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑"); // properties.setProperty("kaptcha.textproducer.font.names", "Algerian"); // Config config = new Config(properties); // captchaProducer.setConfig(config); // return captchaProducer; DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); // 图片边框 properties.setProperty( "kaptcha.border" , "no" ); // 边框颜色 //properties.setProperty("kaptcha.border.color", "105,179,90"); // 字体颜色 properties.setProperty( "kaptcha.textproducer.font.color" , "red" ); // 验证码整体宽度 properties.setProperty( "kaptcha.image.width" , "110" ); // 验证码整体高度 properties.setProperty( "kaptcha.image.height" , "40" ); // 文字个数 properties.setProperty( "kaptcha.textproducer.char.length" , "4" ); // 文字大小 properties.setProperty( "kaptcha.textproducer.font.size" , "24" ); // 文字随机字体 properties.setProperty( "kaptcha.textproducer.font.names" , "宋体,楷体,微软雅黑" ); // 文字距离 properties.setProperty( "kaptcha.textproducer.char.space" , "4" ); // 干扰线颜色 properties.setProperty( "kaptcha.noise.color" , "blue" ); // 自定义验证码背景 //properties.setProperty("kaptcha.background.impl","com.dt.springbootdemo.config.kaptcha.NoKaptchaBackhround"); Config config= new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <! DOCTYPE html> < html lang="en"> < head > < meta charset="UTF-8"> < title >Title</ title > < script type="text/javascript"> function refresh() { document.getElementById('captcha_img').src="/verification?"+Math.random(); } </ script > </ head > < body > < form action="/hello" method="post"> 验证码: < input type="text" placeholder="请输入验证码" name="verifyCodeActual"> < div class="item-input"> < img id="captcha_img" alt="点击更换" title="点击更换" onclick="refresh()" src="/verification" /> </ div > < input type="submit" value="提交" /> </ form > </ body > </ html > |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 上周热点回顾(1.20-1.26)
· 【译】.NET 升级助手现在支持升级到集中式包管理