likes
comments
collection
share

我是怎样完成开源系统中的验证码的功能的?

作者站长头像
站长
· 阅读数 15

写在前面:

最近有一个想法,做一个程序员师徒系统。因为在大学期间的我在学习java的时候非常地迷茫,找不到自己的方向,也没有一个社会上有经验的前辈去指导,所以走了很多的弯路。后来工作了,想把自己的避坑经验分享给别人,但是发现身边都是有经验的开发者,也没有机会去分享自己的想法,所以富贵同学就想做一个程序员专属的师徒系统,秉承着徒弟能够有人指教少走弯路,师傅能桃李满天下的目的,所以开始做这个师徒系统,也会同步更新该系统所用到的技术,并且作为教程分享给大家,希望大家能够关注一波。

我是怎样完成开源系统中的验证码的功能的?

这里推荐使用gitee.com/ele-admin/E… 作为工具来实现验证码的功能,因为它好用,简单,可以作为系统的验证模块使用

第一步,导入jar包

		 <!--Redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--Redis-->
          <!--验证码-->
        <dependency>
            <groupId>com.github.whvcse</groupId>
            <artifactId>easy-captcha</artifactId>
            <version>1.6.2</version>
        </dependency>
        <!--验证码-->

之所以用redis的原因是用来存储验证码

第二步,编写redis配置文件

package com.wangfugui.apprentice.common.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

/**
 * RedisUtils:redis工具类
 */
@Component
public class RedisUtils {

    @Autowired
    @Qualifier("getRedisTemplate")
    private RedisTemplate redisTemplate;

    @Autowired
    @Qualifier("getStringRedisTemplate")
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 设置键值
     *
     * @Param: [key, value]
     * @return: boolean
     * @Author: MaSiyi
     * @Date: 2021/11/20
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 设置键值(string)
     *
     * @Param: [key, value]
     * @return: boolean
     * @Author: MaSiyi
     * @Date: 2021/11/20
     */
    public boolean setStr(final String key, String value) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 设置键值(string)
     *
     * @Param: [key, value]
     * @return: boolean
     * @Author: MaSiyi
     * @Date: 2021/11/20
     */
    public boolean setStrEx(final String key, String value,long timeout, TimeUnit unit) {
        boolean result = false;
        try {
            stringRedisTemplate.opsForValue().set(key, value, timeout, unit);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 写入缓存设置失效时间
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setEx(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 设置key-value
     * <p>
     * 注: 若已存在相同的key, 那么原来的key-value会被丢弃
     *
     * @param key     key
     * @param value   key对应的value
     * @param timeout 过时时长
     * @param unit    timeout的单位
     * @date 2020/3/8 15:40:59
     */
    public void setEx(String key, String value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 批量删除对应的value
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 删除对应的value
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断缓存当中是否有对应的value
     *
     * @param key
     * @return
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 根据key,获取到对应的value值
     *
     * @param key key-value对应的key
     * @return 该key对应的值。
     * 注: 若key不存在, 则返回null。
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 根据key,获取到对应的value(string)值
     *
     * @param key key-value对应的key
     * @return 该key对应的值。
     * 注: 若key不存在, 则返回null。
     */
    public String getStr(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }


}

这里注入两个模板的原因是用来区分string类型和object的值

第三步,编写配置类

package com.wangfugui.apprentice.config;

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    /**
     * 重写Redis序列化方式,使用Json方式: * 当我们的数据存储到Redis的时候,我们的键(key)和值(value)
     * 都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,
     * StringRedisTemplate默认使用的是StringRedisSerializer。
     * Spring Data JPA为我们提供了下面的Serializer:
     * GenericToStringSerializer、Jackson2JsonRedisSerializer、JacksonJsonRedisSerializer、
     * JdkSerializationRedisSerializer、OxmSerializer、StringRedisSerializer。
     * 在此我们将自己配置RedisTemplate并定义Serializer。
     *
     * @param redisConnectionFactory * @return
     */
    @Bean("getRedisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        /**
         * 配置连接工厂
         */
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        /**
         * 使用FJackson2JsonRedisSerializer序列化工具
         */
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        /**
         * 指定要序列化的域Field、set、get,以及修饰符范围
         * ANY是都有,包括private、public
         */
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        /**
         * 指定序列化输入的类型,类必须是非final修饰的,
         * final修饰的类,比如
         * public final class User implements Serializable{},会包异常
         */
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);


        /**
         *设置键(key)的序列化采用StringRedisSerializer。
         */
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        /**
         * 设置值(value)的序列化采用jackson2JsonRedisSerializer。
         */
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 配置stringRedisTemplate序列化方式
     *
     * @param redisConnectionFactory
     * @return
     */
    @Bean("getStringRedisTemplate")
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}

配置类这里设置了两个模板,分别对应了第二步的模板需求

第四步,编写controller类

package com.wangfugui.apprentice.controller;

import com.wangfugui.apprentice.common.util.RedisUtils;
import com.wangfugui.apprentice.common.util.ResponseUtils;
import com.wf.captcha.SpecCaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Api(tags = "验证码")
@RestController
@RequestMapping("captcha")
public class CaptchaController {

    @Autowired
    private RedisUtils redisUtil;
    
    @ResponseBody
    @ApiOperation("生成验证码")
    @GetMapping("/makeCaptcha")
    public ResponseUtils makeCaptcha() {
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
        String verCode = specCaptcha.text().toLowerCase();
        String key = UUID.randomUUID().toString();
        // 存入redis并设置过期时间为30分钟
        redisUtil.setStrEx(key, verCode, 30, TimeUnit.MINUTES);
        // 将key和base64返回给前端
        HashMap<String, Object> map = new HashMap<>();
        map.put("key", key);
        map.put("image", specCaptcha.toBase64());
        return ResponseUtils.success(map);
    }
    
    @ResponseBody
    @ApiOperation("校验验证码")
    @PostMapping("/getCaptcha")
    public ResponseUtils getCaptcha(String verCode,String verKey){
        // 获取redis中的验证码
        String redisCode = redisUtil.getStr(verKey);
        // 判断验证码
        if (verCode==null || !redisCode.equals(verCode.trim().toLowerCase())) {
            return ResponseUtils.error("验证码不正确");
        }
        return ResponseUtils.success("验证成功");
    }  
}

之后测试就行啦,生成样式举例: 我是怎样完成开源系统中的验证码的功能的?

说在之后

师徒系统我会一直更新,因为是开源的项目,所以我也希望有更多的小伙伴加入进来!! 这是程序员师徒管理系统的地址: 程序员师徒管理系统 我是怎样完成开源系统中的验证码的功能的?