java发送验证码的代码,短信验证代码怎么实现

  java发送验证码的代码,短信验证代码怎么实现

  

目录

项目需求需求来由代码实现发送验证码方法注册方法忘记密码前端代码编码中遇到的问题如何改进短信验证码相信大家都不陌生吗,但是短信验证码怎么生成的你真的了解吗,本文揭示本人项目中对短信验证码的。

 

  

项目需求

用户注册/忘记密码添加短信验证码

 

  

需求来由

登录注册页面需要确保用户同一个手机号只关联一个账号确保非人为操作,避免系统用户信息紊乱增加系统安全性

 

  

代码实现

同事提供了服务接口,很好,之前没调过,又增加了困难。

 

  这边用的阿里云的短信服务,废话少说上图,呸,上代码—

  

发送验证码方法

公共Ajax结果sendVerificationCode(log in body log in body){//拼装存储的密钥字符串redisCodeKey=常量RECRUIT _ CODE _ KEY登录正文。获取用户名();//通过判断过期时间检验是否发送过验证码如果发送直接返回if(redis缓存。get expire(redisCodeKey)=0){返回Ajax结果。错误(提示常量.YZM _ SEND _ ALREADY);} //生成随机6位验证码string redis代码值=verifycodeutils。generatessmcode();//验证码类型这是根据同事给的服务的文档单独封装的目前先这么写了;判断其是注册还是忘记密码验证码类型验证码类型=验证码类型通过代码获取(登录正文。getverificationcodetype());字符串templateCode=nullswitch(验证码类型){ case register : template code=验证码类型.注册。get code();打破;case FORGET _ password :模板代码=验证码类型.忘记密码。get code();打破;默认:破;} //webservice接口需要数据格式的参数JSON对象JSON对象=new JSON对象();JSON对象。put(web服务常量.CODE,redisCodeValue);MapString,字符串结果map=SMS utils。sendmessage(登录正文。get username()、templateCode、JSON对象);//判断服务接口返回的结果如果(!结果图。获取(web服务常量.发送短信结果)。等于(常数成功){ logger。信息(结果图。获取(web服务常量.OUT _ MSG));伐木工。信息(结果图。获取(web服务常量.BIZ _ ID));返回AjaxResult.error(TipsConstants .消息_服务器_错误);} //存储到存储设置过期时间,这里设置了60年代,根据需求来redis缓存。setcache对象(redis code key,redisCodeValue,60,TimeUnit .秒);返回Ajax结果。success();}

 

  

注册方法

公共AjaxResult寄存器(LoginBody loginBody) { //拼装存储密钥字符串redisCodeKey=常量。招聘_代码_密钥登录包

 

  y.getUserName(); //redisCache封装了redis的方法; //获取验证码判断验证码是否为空;输入的验证码与短信验证码是否一致 String redisCodeValue = redisCache.getCacheObject(redisCodeKey); if (StringUtils.isEmpty(redisCodeValue) !loginBody.getVerificationCode().equals(redisCodeValue)) { return AjaxResult.error(TipsConstants.YZM_ERROR); } //查表校验用户是否注册 SysUser existUser = sysUserMapper.checkPhoneUnique(loginBody.getUserName()); if (!ObjectUtil.isEmpty(existUser)) { return AjaxResult.error(TipsConstants.EXIST_USER_ERROR); } //对象copy,创建SysUser对象 SysUser sysUser = BeanUtil.copyProperties(loginBody, SysUser.class, UserConstants.PASSWORD); sysUser.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword())); //插入用户信息 sysUserMapper.insertUser(sysUser); return AjaxResult.success(TipsConstants.REGISTER_SUCCESS);}

 

  

忘记密码

public AjaxResult forgetPwd(LoginBody loginBody) { //拼装redis的key String redisCodeKey = Constants.RECRUIT_CODE_KEY + loginBody.getUserName(); //获取验证码 String redisCodeValue = redisCache.getCacheObject(redisCodeKey); if (!loginBody.getVerificationCode().equals(redisCodeValue)) { return AjaxResult.error(TipsConstants.YZM_ERROR); } //查表查询用户是否存在 SysUser sysUser = sysUserMapper.checkPhoneUnique(loginBody.getUserName()); if (ObjectUtil.isEmpty(sysUser)) { return AjaxResult.error(TipsConstants.NO_USER); } //密码加密 loginBody.setPassword(SecurityUtils.encryptPassword(loginBody.getPassword())); //重置密码 sysUserMapper.resetUserPwd(loginBody.getUserName(), loginBody.getPassword()); return AjaxResult.success();}

 

  

前端代码

这里只粘贴了发送验证码改变按钮的方法

 

  

sendCode(type) { this.$refs.registerForm.validateField(phone,(phoneError)=> { if(!phoneError){ this.registerForm.verificationCodeType = type //短信验证码最大请求次数校验 getSmsCode(this.registerForm).then(response => { if (response.code !== 200) { this.requestMax = true } else { this.msgSuccess(发送成功,请注意查收短信) this.requestMax = false } //发送验证码按钮修改 if (!this.requestMax) { let time = 60 this.buttonText = 已发送 this.isDisabled = true if (this.flag) { this.flag = false let timer = setInterval(() => { time-- this.buttonText = time + 秒 if (time === 0) { clearInterval(timer) this.buttonText = 重新获取 this.isDisabled = false this.flag = true } }, 1000) } } }) } })},

 

  

编码中遇到的问题

1.webservice如何调用?

 

  一开始导了很多关于webservice的相关依赖,结果掉不通没办法只能用Hutool了,send返回的是一个xml,再用documet将其解析就ok了。

  

SoapClient soapClient = SoapClient.create(WebServiceConfig.getMsgUrl()) .setMethod(WebServiceMethod.SendSms.getCode(), WebServiceConfig.getNamespaceUri()) .setParams(map, false);String result = soapClient.send()

2.不能让用户无限制的请求发送验证码

 

  据说短信平台有验证逻辑,为了安全还是给系统封了一层;这里通过注解,aop配合redis计数器进行最大请求次数验证。

  代码如下

  注解

  

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface CheckRequestTimes { /** * 最大请求次数 */ String maxTimes() default "10"; /** * 整个系统最大请求次数 */ String maxSystermTimes() default "1000"; /** * 请求类型 */ RequestEnums reqType() default RequestEnums.COMMON; /** * 请求次数上限错误信息提示 */ String errorMsg() default TipsConstants.REQUEST_TIMES_MAX}

Aspect

 

  这部分代码我个人认为设计比较巧妙,可供读者思考,多利用设计模式思想去开发代码,让代码更优雅、更健壮、更可用,crud也有编出自己的骨气!!!(本实例涵盖了单例,模板方法)

  

@Aspect@Component@Order(2)public class CheckRequestAspect {    @Autowired    RedisService redisService;    @Autowired    TokenService tokenService;    private static Logger logger = LoggerFactory.getLogger(CheckRequestAspect.class);    //防止并发,添加关键字实现共享    private volatile ConcurrentHashMap<RequestEnums, RequestTimesAbstract> reqTimesProcessMap;        @PostConstruct    public void initExcelProcessorFactory() {        //dcl 双重检查锁,也可进行懒散加载。因为现在基于spring容器单例,此锁可适当调整        if (MapUtil.isNotEmpty(reqTimesProcessMap)) {            return;        }        //眼熟不这叫懒汉式单例        synchronized (this) {            if (ObjectUtil.isNull(reqTimesProcessMap)) {                reqTimesProcessMap = new ConcurrentHashMap(8);            }            //这里其实可以采用工厂方法去改造,由于业务没有太多类型所以就不设计工厂了            reqTimesProcessMap.put(RequestEnums.COMMON, new UserCommReqTimes());            reqTimesProcessMap.put(RequestEnums.SMS, new SMSCodeReqTimes());        }    }    /**     * 切入点     */    @Pointcut("@annotation(com.fuwai.hr.common.annotation.CheckRequestTimes)")    public void checkPoint() {    }    /**     * 环绕获取请求参数     *     * @param proceedingJoinPoint     * @return     */    @Around("checkPoint()")    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint) {        //获取方法上的注解        CheckRequestTimes checkRequestTimes = getAnnotation(proceedingJoinPoint);        Object[] args = proceedingJoinPoint.getArgs();        //判断是否到达最大请求次数,这里为了应对不同请求类型的处理方式写了一个抽象类,        //便于扩展维护,沿用了了模板方法设计模式的思想        if(!reqTimesProcessMap.get(checkRequestTimes.reqType()).judgeMaxTimes(args, checkRequestTimes, redisService)){            return AjaxResult.error(HttpStatus.REQUEST_MAX, checkRequestTimes.errorMsg());        }        //执行请求方法        Object proceed = null;        try {            proceed = proceedingJoinPoint.proceed();        } catch (Throwable throwable) {            logger.error(throwable.getMessage(), throwable);        }        return proceed;    }    /**     * 获取方法上的注解以便拿到对应的值     *     * @param proceedingJoinPoint     * @return     */    private CheckRequestTimes getAnnotation(ProceedingJoinPoint proceedingJoinPoint) {        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();        Method method = signature.getMethod();        if (method != null){            return method.getAnnotation(CheckRequestTimes.class);        }        return null;    }}

抽象模板类

 

  

public abstract class RequestTimesAbstract { /** * 判断是否到达请求最大次数 * @param object 参数 * @param checkRequestTimes 注解 * @param redisService redis服务 * @return */ public abstract boolean judgeMaxTimes(Object object, CheckRequestTimes checkRequestTimes, RedisService redisService);}

短信模板子类

 

  

public class SMSCodeReqTimes extends RequestTimesAbstract { @Override public boolean judgeMaxTimes(Object object, CheckRequestTimes checkRequestTimes, RedisService redisService) { Object[] objects= (Object[])object; LoginBody loginBody = JSONObject.parseObject(JSONObject.toJSONString(objects[0]), LoginBody.class); String phone = Constants.RECRUIT_CODE_TIMES_KEY + loginBody.getUserName() + Constants.NUM; //本地只有一个服务器,拼接一个ip的key;如果是分布式这种方式就不太可取了根据需求来吧 StringBuilder ip = new StringBuilder(); ip.append(Constants.RECRUIT_CODE_TIMES_KEY).append(LocalHostUtil.getLocalIp()).append(Constants.DELIVERY).append(Constants.NUM); //判断本地系统的最大请求方式和用户的请求次数 if (StringUtils.isNotEmpty(ip) && StringUtils.isNotEmpty(phone)) { return redisService.judgeMaxRequestTimes(ip.toString(), checkRequestTimes.maxSystermTimes()) && redisService.judgeMaxRequestTimes(phone, checkRequestTimes.maxTimes()); } return false; }}

RedisService判断请求方法

 

  这里实现了一简单redis计数器自己随手写的也不知道对不对;rediscache封装的redis一些操作

  

/** * 判断最大请求次数 * * @param key 缓存对象key键 * @param max 最大请求次数 * @return */@Overridepublic Boolean judgeMaxRequestTimes(String key, String max) { //获取key值,值为null插入值 //不为null进行,判断是否到最大值,更新数值 String value = redisCache.getCacheObject(key); if (StringUtils.isEmpty(value)) { //key存在的话不对齐进行操作,存在的话就他设置值 redisCache.setIfAbsent(key, RecruitNumberConstants.NUMBER_1.toString(), RecruitNumberConstants.NUMBER_24, TimeUnit.HOURS); return true; } //最大次数 <= 当前访问次数 if (Integer.valueOf(max).compareTo(Integer.valueOf(value)) <= RecruitNumberConstants.NUMBER_0) { return false; } //这里获取的是当前key的过期时间 //(因为这边更新值的话,更新要不得设置过期时间要不不设置更新那ttl就变成了永久的了 //两种方案都不合理那就只能获取他当前的剩余时间去更新了) Long expire = redisCache.getExpire(key); //key存在的话对其进行更新,不存在不对其进行操作 return redisCache.setIfPresent(key, String.valueOf(Integer.parseInt(value) + RecruitNumberConstants.NUMBER_1), expire, TimeUnit.SECONDS);}

 

  

如何改进

个人感觉这应该是不支持并发的,关于计数的操作可以用原子类去操作;我感觉我写的这玩意分布式估计也支持不了,有时间自己搭个环境再验证吧,懒得搞了。

 

  到此这篇关于Java实现短信验证码的示例代码的文章就介绍到这了,更多相关Java 短信验证码内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • qq短信验证码发送失败怎么回事,qq验证码失败是怎么回事
  • ,,使用阿里大于(大鱼)平台进行发送手机验证码的流程
  • ,,SpringSceurity实现短信验证码登陆
  • android读取短信验证码,
  • android读取短信验证码,,Android使用MobSDK短信验证
  • android自动获取短信验证码功能在哪,安卓自动获取短信验证码
  • android自动获取短信验证码功能在哪,android自动获取短信验证码功能失效,Android自动获取短信验证码功能
  • android实现短信验证码自动填写功能是什么,安卓短信验证码自动填充 实现
  • android实现短信验证码自动填写功能是什么,安卓短信验证码自动填充 实现,Android实现短信验证码自动填写功能
  • android如何通过手机自动获取短信验证码信息,安卓自动获取短信验证码
  • android如何通过手机自动获取短信验证码信息,安卓自动获取短信验证码,Android如何通过手机自动获取短信验证码
  • ,,python网络爬虫实现发送短信验证码的方法
  • ,,Python实现滑块拼图验证码详解
  • ,,python3 破解 geetest(极验)的滑块验证码功能
  • 发验证码不在桌面显示,验证码能收到桌面上不显示怎么回事
  • 留言与评论(共有 条评论)
       
    验证码: