• 常用工具类之使用easy-captcha生成验证码


    引入依赖

    captcha一款超简单的验证码生成,还挺好玩的.还有中文验证码,动态验证码. 。在项目中pom.xml配置文件中添加依赖,如下:

    1. <!--验证码-->
    2. <dependency>
    3. <groupId>com.google.guava</groupId>
    4. <artifactId>guava</artifactId>
    5. <version>18.0</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>com.github.whvcse</groupId>
    9. <artifactId>easy-captcha</artifactId>
    10. <version>1.6.2</version>
    11. </dependency>

    实现思路

    把生成的验证码结果保存到redis缓存中,并设置过期时间。

    前端通过提交验证码和key,其中key就是保存到redis中的键,通过这个键获取到对应的值,再与前端提交的值对比,相同就通过验证。

    新建验证码枚举类

    由于captcha这款验证码提供了好几种验证码方法,有中文验证码,动态验证码,算术验证码等等,新建一个验证码每周类存放这几种验证码类型。代码如下:

    1. public enum LoginCodeEnum {
    2. /**
    3. * 算数
    4. */
    5. ARITHMETIC,
    6. /**
    7. * 中文
    8. */
    9. CHINESE,
    10. /**
    11. * 中文闪图
    12. */
    13. CHINESE_GIF,
    14. /**
    15. * 闪图
    16. */
    17. GIF,
    18. SPEC
    19. }

    定义验证码配置信息

    该类是定义验证码的基本信息,例如高度、宽度、字体类型、验证码类型等等、并且我们把它转成通过SpringBoot配置文件类型来定义更加方便。

    1. @Data
    2. public class LoginCode {
    3. /**
    4. * 验证码配置
    5. */
    6. private LoginCodeEnum codeType;
    7. /**
    8. * 验证码有效期 分钟
    9. */
    10. private Long expiration = 2L;
    11. /**
    12. * 验证码内容长度
    13. */
    14. private int length = 2;
    15. /**
    16. * 验证码宽度
    17. */
    18. private int width = 111;
    19. /**
    20. * 验证码高度
    21. */
    22. private int height = 36;
    23. /**
    24. * 验证码字体
    25. */
    26. private String fontName;
    27. /**
    28. * 字体大小
    29. */
    30. private int fontSize = 25;
    31. /**
    32. * 验证码前缀
    33. * @return
    34. */
    35. private String codeKey;
    36. public LoginCodeEnum getCodeType() {
    37. return codeType;
    38. }
    39. }

    把配置文件转换Pojo类的统一配置类

    1. @Configuration
    2. public class ConfigBeanConfiguration {
    3. @Bean
    4. @ConfigurationProperties(prefix = "login")
    5. public LoginProperties loginProperties() {
    6. return new LoginProperties();
    7. }
    8. }

    定义验证逻辑生成类

    1. @Data
    2. public class LoginProperties {
    3. private LoginCode loginCode;
    4. /**
    5. * 获取验证码生产类
    6. * @return
    7. */
    8. public Captcha getCaptcha(){
    9. if(Objects.isNull(loginCode)){
    10. loginCode = new LoginCode();
    11. if(Objects.isNull(loginCode.getCodeType())){
    12. loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
    13. }
    14. }
    15. return switchCaptcha(loginCode);
    16. }
    17. /**
    18. * 依据配置信息生产验证码
    19. * @param loginCode
    20. * @return
    21. */
    22. private Captcha switchCaptcha(LoginCode loginCode){
    23. Captcha captcha = null;
    24. synchronized (this){
    25. switch (loginCode.getCodeType()){
    26. case ARITHMETIC:
    27. captcha = new FixedArithmeticCaptcha(loginCode.getWidth(),loginCode.getHeight());
    28. captcha.setLen(loginCode.getLength());
    29. break;
    30. case CHINESE:
    31. captcha = new ChineseCaptcha(loginCode.getWidth(),loginCode.getHeight());
    32. captcha.setLen(loginCode.getLength());
    33. break;
    34. case CHINESE_GIF:
    35. captcha = new ChineseGifCaptcha(loginCode.getWidth(),loginCode.getHeight());
    36. captcha.setLen(loginCode.getLength());
    37. break;
    38. case GIF:
    39. captcha = new GifCaptcha(loginCode.getWidth(),loginCode.getHeight());
    40. captcha.setLen(loginCode.getLength());
    41. break;
    42. case SPEC:
    43. captcha = new SpecCaptcha(loginCode.getWidth(),loginCode.getHeight());
    44. captcha.setLen(loginCode.getLength());
    45. default:
    46. System.out.println("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
    47. }
    48. }
    49. if(StringUtils.isNotBlank(loginCode.getFontName())){
    50. captcha.setFont(new Font(loginCode.getFontName(),Font.PLAIN,loginCode.getFontSize()));
    51. }
    52. return captcha;
    53. }
    54. static class FixedArithmeticCaptcha extends ArithmeticCaptcha{
    55. public FixedArithmeticCaptcha(int width,int height){
    56. super(width,height);
    57. }
    58. @Override
    59. protected char[] alphas() {
    60. // 生成随机数字和运算符
    61. int n1 = num(1, 10), n2 = num(1, 10);
    62. int opt = num(3);
    63. // 计算结果
    64. int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
    65. // 转换为字符运算符
    66. char optChar = "+-x".charAt(opt);
    67. this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
    68. this.chars = String.valueOf(res);
    69. return chars.toCharArray();
    70. }
    71. }
    72. }

    在控制层上定义验证码生成接口

    1. @ApiOperation(value = "获取验证码", notes = "获取验证码")
    2. @GetMapping("/code")
    3. public Object getCode(){
    4. Captcha captcha = loginProperties.getCaptcha();
    5. String uuid = "code-key-"+IdUtil.simpleUUID();
    6. //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型
    7. String captchaValue = captcha.text();
    8. if(captcha.getCharType()-1 == LoginCodeEnum.ARITHMETIC.ordinal() && captchaValue.contains(".")){
    9. captchaValue = captchaValue.split("\\.")[0];
    10. }
    11. // 保存
    12. redisUtils.set(uuid,captchaValue,loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
    13. // 验证码信息
    14. Map<String,Object> imgResult = new HashMap<String,Object>(2){{
    15. put("img",captcha.toBase64());
    16. put("uuid",uuid);
    17. }};
    18. return imgResult;
    19. }
    20. /**
    21. * Local Cache 5分钟过期
    22. */
    23. Cache<String, String> localCache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterAccess(5, TimeUnit.MINUTES).build();
    24. /**
    25. * 生成验证码
    26. * @param response
    27. * @param uuid
    28. * @throws IOException
    29. */
    30. @GetMapping("captcha")
    31. public void captcha(HttpServletResponse response, String uuid)throws IOException {
    32. response.setContentType("image/gif");
    33. response.setHeader("Pragma", "No-cache");
    34. response.setHeader("Cache-Control", "no-cache");
    35. response.setDateHeader("Expires", 0);
    36. //生成验证码
    37. SpecCaptcha captcha = new SpecCaptcha(150, 40);
    38. captcha.setLen(5);
    39. captcha.setCharType(Captcha.TYPE_DEFAULT);
    40. captcha.out(response.getOutputStream());
    41. //保存到缓存
    42. localCache.put(uuid, captcha.text());
    43. }
    44. /**
    45. * 校验验证码
    46. * @param uuid
    47. * @param captcha
    48. * @return
    49. */
    50. @PostMapping("validateCaptcha")
    51. public Boolean validateCaptcha(String uuid, String captcha) {
    52. //获取缓存中的验证码
    53. String cacheCaptcha = localCache.getIfPresent(uuid);
    54. //删除验证码
    55. if(cacheCaptcha != null){
    56. localCache.invalidate(uuid);
    57. }
    58. //效验成功
    59. if(captcha.equalsIgnoreCase(cacheCaptcha)){
    60. return true;
    61. }else {
    62. return false;
    63. }
    64. }

    效果体验

    在前端调用接口

    1. <template>
    2. <div class="login-code">
    3. <img :src="codeUrl" @click="getCode">
    4. </div>
    5. </template>
    6. <script>
    7. methods: {
    8. getCode() {
    9. getCodeImg().then(res => {
    10. this.codeUrl = res.data.img
    11. this.loginForm.uuid = res.data.uuid
    12. })
    13. },
    14. }
    15. created() {
    16. // 获取验证码
    17. this.getCode()
    18. },
    19. </script>

  • 相关阅读:
    杰理之TIMER0 用默认的 PA13 来检测脉宽【篇】
    grafana结合Skywalking追踪Trace(一)
    Vim基础
    《J2EE开发技术》教学上机实验报告
    智能交通信号灯控制策略
    C语言 - 汉诺塔详解(最简单的方法,进来看看就懂)
    数据库设计详细教程上篇(数据库设计流程)
    点成分享 | 微流控技术集成系统的应用
    新库上线 | CnOpenData欧洲专利局专利数据
    有效的字母异位词(C++解法)
  • 原文地址:https://blog.csdn.net/weixin_53998054/article/details/127831507