咖啡汪推荐————使用Redisson组件,缓存映射MapCache进行短信验证码失效验证

(一)开篇,本汪先讲使用Redisson的MapCache的优点

1.Redisson组件,缓存映射MapCache 可以很好地解决DB负载过高的问题,每次进行校验,只需从缓存中查询,不需再查数据库。

2.可以解决定时任务处理不及时的问题,通过实现ApplicationRunner, Ordered两个接口,可以在应用启动和运行期间,不间断监听,并执行我们所需的业务逻辑代码。

3.解决了批次查询的数据量可能过大占用过多的缓存的问题

我们使用纯sql加定时器进行短信验证码失效验证和使用redis进行短信验证码失效验证
与使用Redisson的mapCache有什么区别呢?
redisson的RMapCache,号称是redis的最佳实践,就是由于他通过层层封装,很好地将时间属性赋予了MapCache。记得本汪前段时间还写过一个基于WeakHashMap的具有时间属性的缓存,这个发布在本汪另一篇文章中,大家可以看看。

下面,请大家和本汪挚友Lucky一起,一边吹风,一边进入今天的讲解吧!、

在这里插入图片描述

( 二 ) 思维导图+源码

本汪来了:现在由本汪带大家一起看看他的思维导图,其实结合思维导图和源码,就可以解决60%的问题了
依照惯例,先上思维导图和源码链接
源码链接:https://github.com/HuskyCorps/distributeMiddleware
强烈建议下载源码,搭建环境进行学习。
在这里插入图片描述

( 三 )使用Redisson组件,缓存映射MapCache进行短信验证码失效验证

1.首先配置下Rediss集群
这是集群的配置redisson.url.cluster=redis://127.0.0.1:7100,redis://127.0.0.1:7200,redis://127.0.0.1:7300,redis://127.0.0.1:7101,redis://127.0.0.1:7201,redis://127.0.0.1:7301


/**
 * 自定义注入Redisson操作bean组件
 *
 * @author Yuezejian
 * @date 2020年 09月01日 20:10:14
 */
@Configuration
public class RedissionConfig {
    
    

    @Autowired
    private Environment env;
    
    @Bean
    public RedissonClient client() {
    
    
        Config config = new Config();
        config.useClusterServers().setScanInterval(2000)
                .addNodeAddress(StringUtils.split(env.getProperty("redisson.url.cluster"),","))
                .setMasterConnectionMinimumIdleSize(10)
                .setMasterConnectionPoolSize(64)
                .setSlaveConnectionMinimumIdleSize(10)
                .setSlaveConnectionPoolSize(64)
                .setConnectTimeout(15000);
        RedissonClient client = Redisson.create(config);
        return client;
    }
}

2.编写service


/**
 * 短信验证码失效验证
 *
 * @author Yuezejian
 * @date 2020年 09月02日 20:18:09
 */
@Service
public class MsgCodeService {
    
    

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private SendRecordMapper recordMapper;

    public String getRandomCode(final String phone) throws Exception {
    
    
        RMapCache<String, String> rMapCache = redissonClient.getMapCache(Constant.RedissonMsgCodeKey);

        String code = rMapCache.get(phone);
        if (StringUtils.isNotBlank(code)) {
    
    
            return code;
        }
        //TODO:在网络不稳定的情况下,可能手机没能接收到短信验证码,此时需要重新申请,即
        //TODO: 同个手机号多次申请验证码,如果该手机号存在着  
        //30min内有效的验证码,则直接取出发给他即可,而无需重新生成,
        //TODO: 以免造成空间和资源的浪费
        String msgCode = RandomUtil.randomMsgCode(4);
        SendRecord entity = new SendRecord(phone,msgCode);
        entity.setSendTime(DateTime.now().toDate());
        int res = recordMapper.insertSelective(entity);
        if (res > 0) {
    
    
            rMapCache.put(phone,msgCode,1, TimeUnit.MINUTES);
        }

        //调用短信供应商提供的发送短信的api - 阿里云sms、网建短信通...
        //这个的实现在SendMsg_webchineseUtil中,
        //这里不加缀余,大家可以下载源码自行研究
        return msgCode;
    }

    public boolean validateCode(final String phone,final String code) throws Exception{
    
    
        RMapCache<String,String> rMapCache = redissonClient.getMapCache(Constant.RedissonMsgCodeKey);
        String cacheCode = rMapCache.get(phone);
        return StringUtils.isNotBlank(cacheCode) && cacheCode.equals(code);

    }

}

3.Controller进行调用即可(了解统一响应模型,自行查看本汪相关博客)

/**
 * 短信验证码失效验证
 *
 * @author Yuezejian
 * @date 2020年 08月31日 19:14:59
 */
@RestController
@RequestMapping("msg/code")
public class IdentifyingCodeController extends AbstractController{
    
    

    @Autowired
    private  IdentifyingCodeService identifyingCodeService;

    @Autowired
    private MsgCodeService codeService;


    //获取验证码
    @RequestMapping("send")
    public BaseResponse sendCode(@RequestParam String phone) {
    
    
        if (StringUtils.isBlank(phone)) {
    
    
            return new BaseResponse(StatusCode.InvalidParams);
        }
        BaseResponse response = new BaseResponse(StatusCode.Success);
        try {
    
    
            response.setData(codeService.getRandomCode(phone));

        } catch (Exception e) {
    
    
            response = new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }

    //验证验证码
    @RequestMapping("validate")
    public BaseResponse validateCode(@RequestParam String phone, @RequestParam String code ) {
    
    
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(code)) {
    
    
           return new BaseResponse(StatusCode.InvalidParams);
        }
        BaseResponse response = new BaseResponse(StatusCode.Success);
        try {
    
    
              response.setData(codeService.validateCode(phone,code));
        } catch (Exception e) {
    
    
            response = new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
        }
        return response;
    }



}

4.设置程序监听器


/**
 * 短信验证码失效验证-key(其中的元素 - field)失效监听
 *
 * @author Yuezejian
 * @date 2020年 09月06日 16:36:33
 */
//实现了ApplicationRunner,Ordered后,在应用启动后可以不间断地执行监听,
// Order用来对多个自动监听进行排序,0优先级最高,bean为2147483647,优先级最低
@Service
public class RedissonMapCacheMsgCode implements ApplicationRunner, Ordered {
    
    
    private static final Logger log = LoggerFactory.getLogger(RedissonMapCacheMsgCode.class);

    @Autowired
    private RedissonClient redisson;

    @Autowired
    private SendRecordMapper recordMapper;

    @Autowired
    private CommonService commonService;

    //TODO:应用启动及运行期间,可以不间断地执行我们自定义的服务逻辑
    @Override
    public void run(ApplicationArguments args) throws Exception {
    
    
        log.info("——————应用启动期间,不间断执行短信验证失效的业务逻辑-order 0 --");
        this.listenExpireCode();
    }

    @Override
    public int getOrder() {
    
    
        return 0;
    }

    //监听器--监听mapCache里失效的验证码
    private void listenExpireCode() {
    
    
            RMapCache<String, String> rMapCache = redisson.getMapCache(Constant.RedissonMsgCodeKey);
            rMapCache.addListener(new EntryExpiredListener<String,String>() {
    
    


                @Override
                public void onExpired(EntryEvent<String, String> entryEvent) {
    
    
                    try {
    
    
                        String phone = entryEvent.getKey();
                        String msgCode = entryEvent.getValue();
                        log.info("————当前手机号:{},对应的验证码:{}", phone, msgCode);

                        if (StringUtils.isNotBlank(phone) && StringUtils.isNotBlank(msgCode)) {
    
    
                            int res = recordMapper.updateExpirePhoneCode(phone, msgCode);
                            if (res > 0) {
    
    
                                commonService.recordLog(phone + "--" + msgCode, "监听mapCache里失效的验证码,对数据库进行更新", "listenExpireCode");
                            }
                        }
                    } catch (Exception e) {
    
    
                        e.printStackTrace();
                    }
                }
            });
    }
}

大多需要说明的,本汪都在注释中说明了,下面的作为拓展了解:

rMapCache.addListener(),共可以用四种监听,分别是添加监听,失效监听,更新监听和移除监听
EntryCreatedListener(org.redisson.api.map.event)
EntryExpiredListener(org.redisson.api.map.event)
EntryRemovedListener(org.redisson.api.map.event)
EntryUpdatedListener(org.redisson.api.map.event)

如果想了解更多Redisson的信息,可以取Redisson的Github上进行学习和了解,地址为:
https://github.com/redisson/redisson/wiki/

猜你喜欢

转载自blog.csdn.net/weixin_42994251/article/details/108436520