• SpringBoot实战系列之图形验证码开发并池化Redis6存储


    大家好,我是 ??

    一个正在努力学习的小博主,期待你的关注

    作业侠系列最新文章??

    Java实现聊天程序

    SpringBoot实战系列??

    SpringBoot实战系列之图形验证码开发并池化Redis6缓存

    一起刷算法与数据结构最新文章??

    一起刷算法与数据结构-树篇1

    环境搭建大集合

    环境搭建大集合(持续更新)


    在本栏中,我们之前已经完成了:
    SpringBoot实战系列之发送短信验证码
    SpringBoot实战系列之从Async组件应用实战到ThreadPoolTaskExecutor?定义线程池


    内容速览:
    1.Kaptcha 框架介绍与配置类开发
    2.池化思想应?-Redis6.X配置连接池实战连接池好处
    3.实战图形验证码接口编写
    4.结果测试

    Kaptcha 框架介绍 歌开源的个可度配置的实验证码成具

    验证码的字体//颜
    验证码内容的范围(数字,字,中汉字!)
    验证码图的,边框,边框粗细,边框颜
    验证码的扰线
    验证码的样式(眼样式、3D、普通模糊)

    聚合程依赖添加(使国内baomidou次封装的springboot整合starter)

    
     
     com.baomidou
     kaptcha-spring-bootstarter
     1.1.0
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    配置类

    @Configuration
    public class CaptchaConfig {
        @Bean
        @Qualifier("captchaProducer")
        public DefaultKaptcha kaptcha() {
            DefaultKaptcha kaptcha = new DefaultKaptcha();
            Properties properties = new Properties();
    //
            properties.setProperty(Constants.KAPTCHA_BORDER, "yes");
    //
            properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "220,220,220");
    //
    //properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "38,29,12");
    //
            properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "147");
    //
            properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "34");
    //
            properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "25");
    //
    //properties.setProperty(Constants.KAPTCHA_SESSION_KEY, "code");
            //验证码个数
    
            properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
    //
            properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Courier");
            //字体间隔
    
            properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE,"8");
            //?扰线颜?
    //
            properties.setProperty(Constants.KAPTCHA_NOISE_COLOR, "white");
            //?扰实现类
    
            properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
            //图?样式
    
            properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple");
            //?字来源
    
            properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789");
            Config config = new Config(properties);
            kaptcha.setConfig(config);
            return kaptcha;
        }
    }
    
    • 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

    池化思想应-Redis6.X配置连接池实战连接池好处

    使连接池不每次都三次握、每次都关闭Jedis相对于直连,使相对麻烦,在资源管理上需要很多参数来保证,规划不合理也会出现问题
    如果pool已经分配了maxActive个jedis实例,则此时pool的状态就成exhausted了

    Redis6部署请见环境搭建大集合

    Maven

    
     
     
    org.springframework.boot
     spring-boot-starter-data-redis
     
     
     io.lettuce
     lettuce-core
     
     
     
     
     redis.clients
     jedis
     
     
     org.apache.commons
     commons-pool2
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    配置Redis连接

    redis:
        client-type: jedis
        host: 127.0.0.1
        password: 123456
        port: 6379
        jedis:
          pool:
    
        # 连接池最?连接数(使?负值表示没有限制)
            max-active: 100
        # 连接池中的最?空闲连接
            max-idle: 100
        # 连接池中的最?空闲连接
            min-idle: 100
        # 连接池最?阻塞等待时间(使?负值表示没有限制)
            max-wait: 60000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    注意将配置里的host和password改为你自己的

    序列化配置

    @Configuration
    public class RedisTemplateConfiguration {
        @Bean
        public RedisTemplate
        redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate redisTemplate = new RedisTemplate<>();
    
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            // 使?Jackson2JsonRedisSerialize 替换默认序列化
                    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
    
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
            // 设置key和value的序列化规则
            redisTemplate.setKeySerializer(new StringRedisSerializer());
    
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            // 设置hashKey和hashValue的序列化规则
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
            return redisTemplate;
        }
    }
    
    • 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

    实战图形验证码接口编写:

    @RestController
    @RequestMapping("/api/v1/notify")
    @Slf4j
    public class NotifyController {
    
    
        public static final int CAPTCHA_CODE_EXPIRED = 60 * 1000 * 10;
        @Autowired
        private Producer captchaProduce;
    
      
    
        @Autowired
        private StringRedisTemplate redisTemplate;
    
        /**
         * 图形验证码生成流程
         * 1.用captcha创建文本 String captchaText = captchaProduce.createText();
         * 2.生成文本图像  BufferedImage bufferedImage = captchaProduce.createImage(captchaText);
         * 3.用流写出 try(ServletOutputStream outputStream = response.getOutputStream();) {
         *          ImageIO.write(bufferedImage,"jpg",outputStream);
         *          outputStream.flush();
         * @param request
         * @param response
         */
        @GetMapping("captcha")
        public void getCaptcha(HttpServletRequest request, HttpServletResponse response){
            String captchaText = captchaProduce.createText();
            log.info("验证码内容{}",captchaText);
            redisTemplate.opsForValue().set(getCaptchaKey(request),captchaText,CAPTCHA_CODE_EXPIRED, TimeUnit.SECONDS);
            BufferedImage bufferedImage = captchaProduce.createImage(captchaText);
         try(ServletOutputStream outputStream = response.getOutputStream();) {
             ImageIO.write(bufferedImage,"jpg",outputStream);
             outputStream.flush();
         }catch (Exception e){
             log.info("图形验证码异常");
         }
    
    
        }
        /**
        使用用户ip加user-agent并用md5进行加密
        **/
        private String getCaptchaKey(HttpServletRequest request){
            String ip = CommonUtil.getIpAddr(request);
            String userAgent = request.getHeader("User-Agent");
            String key = "account-service:captcha:"+CommonUtil.MD5(ip+userAgent);
            log.info("key{}",key);
            return key;
        }
    
    }
    
    • 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

    CommonUtil工具类,直接cv即可,在工作中也是这样:

    @Slf4j
    public class CommonUtil {
    
        /**
         * 获取ip
         *
         * @param request
         * @return
         */
        public static String
        getIpAddr(HttpServletRequest request) {
            String ipAddress = null;
            try {
                ipAddress = request.getHeader("x-forwarded-for");
                if (ipAddress == null ||
                        ipAddress.length() == 0 ||
                        "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress =
                            request.getHeader("Proxy-Client-IP");
                }
                if (ipAddress == null ||
                        ipAddress.length() == 0 ||
                        "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getHeader("WL-Proxy-Client-IP");
                }
                if (ipAddress == null ||
                        ipAddress.length() == 0 ||
                        "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getRemoteAddr();
                    if (ipAddress.equals("127.0.0.1")) {
                        // 根据?卡取本机配置的IP
                        InetAddress inet = null;
                        try {
                            inet =
                                    InetAddress.getLocalHost();
                        } catch (UnknownHostException e)
                        {
                            log.warn("[]",e);
                        }
                        ipAddress =
                                inet.getHostAddress();
                    }
                }
                // 对于通过多个代理的情况,第?个IP为客户端真实IP,多个IP按照','分割
                if (ipAddress != null &&
                        ipAddress.length() > 15) {
                    // "***.***.***.***".length()
                    // = 15
                    if (ipAddress.indexOf(",") > 0) {
                        ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                    }
                }
            } catch (Exception e) {
                ipAddress = "";
            }
            return ipAddress;
        }
        /**
         * 获取全部请求头
         * @param request
         * @return
         */
        public static Map
        getAllRequestHeader(HttpServletRequest request){
            Enumeration headerNames = request.getHeaderNames();
            Map map = new HashMap<>();
            while (headerNames.hasMoreElements()) {
                String key = (String)headerNames.nextElement();
                //根据名称获取请求头的值
                String value = request.getHeader(key);
                map.put(key,value);
            }
            return map;
        }
        /**
         * MD5加密
         *
         * @param data
         * @return
         */
        public static String MD5(String data) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] array = md.digest(data.getBytes("UTF-8"));
                StringBuilder sb = new StringBuilder();
                for (byte item : array) {
                    sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
                }
                return sb.toString().toUpperCase();
            } catch (Exception exception) {
            }
            return null;
        }
        /**
         * 获取验证码随机数
         *
         * @param length
         * @return
         */
        public static String getRandomCode(int length) {
            String sources = "0123456789";
            Random random = new Random();
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < length; j++) {
    
                sb.append(sources.charAt(random.nextInt(9)));
            }
            return sb.toString();
        }
        /**
         * 获取当前时间戳
         *
         * @return
         */
        public static long getCurrentTimestamp() {
            return System.currentTimeMillis();
        }
        /**
         * ?成uuid
         *
         * @return
         */
        public static String generateUUID() {
            return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        }
        /**
         * 获取随机?度的串
         *
         * @param length
         * @return
         */
        private static final String ALL_CHAR_NUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        public static String getStringNumRandom(int length) {
            //?成随机数字和字?,
            Random random = new Random();
            StringBuilder saltString = new
                    StringBuilder(length);
            for (int i = 1; i <= length; ++i) {
    
                saltString.append(ALL_CHAR_NUM.charAt(random.nextInt(ALL_CHAR_NUM.length())));
            }
            return saltString.toString();
        }
        /**
         * 响应json数据给前端
         *
         * @param response
         * @param obj
         */
        public static void
        sendJsonMessage(HttpServletResponse response, Object obj) {
            response.setContentType("application/json;charset=utf-8");
            try (PrintWriter writer =
                         response.getWriter()) {
                writer.print(JsonUtil.obj2Json(obj));
                response.flushBuffer();
            } catch (IOException e) {
                log.warn("响应json数据给前端异常:{}",e);
            }
        }
    
    }
    
    • 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
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162

    浏览器访问结果如下:
    在这里插入图片描述
    同时控制台打印:
    在这里插入图片描述
    redis可视化工具查看:
    在这里插入图片描述本篇完!

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    2022-11-30 mysql-Tuning InnoDB Primary Keys
    svn的常规使用
    criu简单例子
    Flink 1.13(八)CDC
    掌动智能:云可观测性的主要特点及应用场景
    2022暑期训练题单(基本算法)Day1~2
    VK1056B/C计算器,跑步机,电子秤LCD驱动方案,段码液晶显示芯片IC技术资料
    初次邂逅 EasyExcel
    微服务之网关路由
    一个匹配html标签的正则表达式
  • 原文地址:https://blog.csdn.net/m0_67401660/article/details/126114581