zoukankan      html  css  js  c++  java
  • 移动端获取短信验证码java实现——阿里云短信服务

    需求:移动端输入手机号,获取验证码。点击登录,验证验证码是否输入错误、是否超时等情况,一旦校验通过,将用户数据保存到数据中(业务逻辑)。

    前提:注册阿里用户,开通短信服务,申请key、秘钥、签名、短信模板。参考:https://help.aliyun.com/document_detail/55284.html?spm=a2c4g.11174283.3.2.8d482c42qxWRYA

    第一部分:准备工作

    1、pom.xml文件添加阿里云短信服务的依赖

    <!--阿里云短信发送start-->
        <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>aliyun-java-sdk-core</artifactId>
          <version>4.0.6</version>
        </dependency>
        <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
          <version>1.1.0</version>
        </dependency>
    
        <!--阿里云短信发送end-->

    此处可能会报错,官网也说了,好像这个版本的不是很稳定吧。异常可能是:

    Java.lang.NoClassDefFoundError:com/aliyuncs/exceptions/ClientException
    

      解决:

    (1)方法一:检查lib文件下是否有aliyun-java-sdk-core包,没有的话就手动先添加上吧。

    (2)方法二:将版本号改为3.3.1,即低版本

    <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>aliyun-java-sdk-core</artifactId>
          <version>3.3.1</version>
        </dependency>

    2、下载官方demo,这个是发送短信的工具。

    package com.alicom.dysms.api;
    
    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.IAcsClient;
    import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
    import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
    import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
    import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
    import com.aliyuncs.dysmsapi.transform.v20170525.SendSmsResponseUnmarshaller;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.FormatType;
    import com.aliyuncs.http.HttpResponse;
    import com.aliyuncs.profile.DefaultProfile;
    import com.aliyuncs.profile.IClientProfile;
    
    import java.nio.charset.Charset;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.UUID;
    
    /**
     * Created on 17/6/7.
     * 短信API产品的DEMO程序,工程中包含了一个SmsDemo类,直接通过
     * 执行main函数即可体验短信产品API功能(只需要将AK替换成开通了云通信-短信产品功能的AK即可)
     * 工程依赖了2个jar包(存放在工程的libs目录下)
     * 1:aliyun-java-sdk-core.jar
     * 2:aliyun-java-sdk-dysmsapi.jar
     *
     * 备注:Demo工程编码采用UTF-8
     * 国际短信发送请勿参照此DEMO
     */
    public class SmsDemo {
    
        //产品名称:云通信短信API产品,开发者无需替换
        static final String product = "Dysmsapi";
        //产品域名,开发者无需替换
        static final String domain = "dysmsapi.aliyuncs.com";
    
        // TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
        static final String accessKeyId = "yourAccessKeyId";
        static final String accessKeySecret = "yourAccessKeySecret";
    
        public static SendSmsResponse sendSms() throws ClientException {
    
            //可自助调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
    
            //初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);
    
            //组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            //必填:待发送手机号
            request.setPhoneNumbers("15000000000");
            //必填:短信签名-可在短信控制台中找到
            request.setSignName("云通信");
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode("SMS_1000000");
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            request.setTemplateParam("{"name":"Tom", "code":"123"}");
    
            //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
            //request.setSmsUpExtendCode("90997");
    
            //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
            request.setOutId("yourOutId");
    
            //hint 此处可能会抛出异常,注意catch
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
    
            return sendSmsResponse;
        }
    
    
        public static QuerySendDetailsResponse querySendDetails(String bizId) throws ClientException {
    
            //可自助调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
    
            //初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);
    
            //组装请求对象
            QuerySendDetailsRequest request = new QuerySendDetailsRequest();
            //必填-号码
            request.setPhoneNumber("15000000000");
            //可选-流水号
            request.setBizId(bizId);
            //必填-发送日期 支持30天内记录查询,格式yyyyMMdd
            SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
            request.setSendDate(ft.format(new Date()));
            //必填-页大小
            request.setPageSize(10L);
            //必填-当前页码从1开始计数
            request.setCurrentPage(1L);
    
            //hint 此处可能会抛出异常,注意catch
            QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);
    
            return querySendDetailsResponse;
        }
    
        public static void main(String[] args) throws ClientException, InterruptedException {
    
            //发短信
            SendSmsResponse response = sendSms();
            System.out.println("短信接口返回的数据----------------");
            System.out.println("Code=" + response.getCode());
            System.out.println("Message=" + response.getMessage());
            System.out.println("RequestId=" + response.getRequestId());
            System.out.println("BizId=" + response.getBizId());
    
            Thread.sleep(3000L);
    
            //查明细
            if(response.getCode() != null && response.getCode().equals("OK")) {
                QuerySendDetailsResponse querySendDetailsResponse = querySendDetails(response.getBizId());
                System.out.println("短信明细查询接口返回数据----------------");
                System.out.println("Code=" + querySendDetailsResponse.getCode());
                System.out.println("Message=" + querySendDetailsResponse.getMessage());
                int i = 0;
                for(QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO : querySendDetailsResponse.getSmsSendDetailDTOs())
                {
                    System.out.println("SmsSendDetailDTO["+i+"]:");
                    System.out.println("Content=" + smsSendDetailDTO.getContent());
                    System.out.println("ErrCode=" + smsSendDetailDTO.getErrCode());
                    System.out.println("OutId=" + smsSendDetailDTO.getOutId());
                    System.out.println("PhoneNum=" + smsSendDetailDTO.getPhoneNum());
                    System.out.println("ReceiveDate=" + smsSendDetailDTO.getReceiveDate());
                    System.out.println("SendDate=" + smsSendDetailDTO.getSendDate());
                    System.out.println("SendStatus=" + smsSendDetailDTO.getSendStatus());
                    System.out.println("Template=" + smsSendDetailDTO.getTemplateCode());
                }
                System.out.println("TotalCount=" + querySendDetailsResponse.getTotalCount());
                System.out.println("RequestId=" + querySendDetailsResponse.getRequestId());
            }
    
        }
    }

    第二部分:创建自己的MySessionContext

    注意:由于移动端没有sessionId,我们需要自己传输sessionId获取session值。但出于安全性考虑,jdk现在去掉了通过sessionId获取session的方法。

    解决:自建工具类,通过sessionId获取session。

    1、创建一个MySessionContext.java类

    public class MySessionContext {  
            private static MySessionContext instance;  
            private HashMap<String,HttpSession> sessionMap;  
    
            private MySessionContext() {  
                sessionMap = new HashMap<String,HttpSession>();  
            }  
    
            public static MySessionContext getInstance() {  
                if (instance == null) {  
                    instance = new MySessionContext();  
                }  
                return instance;  
            }  
    
            public synchronized void addSession(HttpSession session) {  
                if (session != null) {  
                    sessionMap.put(session.getId(), session);  
                }  
            }  
    
            public synchronized void delSession(HttpSession session) {  
                if (session != null) {  
                    sessionMap.remove(session.getId());  
                }  
            }  
    
            public synchronized HttpSession getSession(String sessionID) {  
                if (sessionID == null) {  
                    return null;  
                }  
                return sessionMap.get(sessionID);  
            }  
    
        }  

    2、然后建立session监听,要实现HttpSessionListener接口

    public class SessionListener implements HttpSessionListener {  
    
            private MySessionContext myc = MySessionContext.getInstance();  
    
            public void sessionCreated(HttpSessionEvent httpSessionEvent) {  
                HttpSession session = httpSessionEvent.getSession();  
                myc.addSession(session);  
            }  
    
            public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {  
                HttpSession session = httpSessionEvent.getSession();  
                myc.delSession(session);  
            }  
    
        } 

    3、接着,在web.xml中配置session监听器

    <listener>  
            <listener-class>com.chinapost.manager.utils.SessionListener</listener-class>  
        </listener>  
    

    参考地址:https://blog.csdn.net/sihai12345/article/details/81098765

    第三部分:实现业务

    1、controller层

     /**
       * app登录,附加:验证码时效性
       * @param conditionStr
       * @return
       */
      @RequestMapping(value = "/anLogin", method = RequestMethod.POST)
      @ResponseBody
    
      public ResponseModel anLogin(@RequestBody String conditionStr){
        return androidLoginService.anLogin(conditionStr);
      }
    
      /**
       * 点击发送验证码
       * @param conditionStr
       * @return
       */
      @RequestMapping(value = "/getVerificationCode", method = RequestMethod.POST)
      @ResponseBody
      public ResponseModel getVerificationCode(@RequestBody String conditionStr) {
        return androidLoginService.getVerificationCode(conditionStr);
      }

    2、service实现层

    package com.test.service.androidService.impl;
    
    import com.alibaba.fastjson.JSON;
    import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
    import com.test.dao.CarDriverMapper;
    import com.test.entity.business.CarDriver;
    import com.test.entity.common. ResponseModel;
    import com.test.service.androidService.AndroidLoginService;
    import com.test.service.common.impl.BaseServiceImpl;
    import com.test.util.MySessionContext;
    import com.test.util.SessionUtil;
    import com.test.util.SmsCodeUtil;
    import com.test.util.SmsSendUtil;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpSession;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Map;
    
    @Service
    public class AndroidLoginServiceImpl extends BaseServiceImpl implements AndroidLoginService {
      public static final Logger logger = LoggerFactory.getLogger(AndroidLoginServiceImpl.class);
    
      @Resource
      private CarDriverMapper carDriverMapper;
      
    
      @Override
      public  ResponseModel anLogin(String conditionStr) {
        set ResponseModel(new  ResponseModel());
        setErrorMsg("");
        setSuccess(false);
        Map<String,Object> resultMap = new HashMap<>();
        try {
          CarDriver carDriver = JSON.parseObject(conditionStr, CarDriver.class);
          String tel_param = carDriver.getTel();
          String verificationCode_param = carDriver.getVerificationCode();
          String sessionId_param = carDriver.getSessionId();
          //1-校验手机号和验证码不能为空
          if(StringUtils.isBlank(tel_param)){
            setErrorMsg("手机号不能为空!");
            return get ResponseModel();
          }
          if(StringUtils.isBlank(verificationCode_param)){
            setErrorMsg("验证码不能为空!");
            return get ResponseModel();
          }
          //2-校验是否获取验证码
          MySessionContext myc= MySessionContext.getInstance();
          HttpSession session = myc.getSession(sessionId_param);
          //获取session中登录手机号对应的验证码
          Object verificationCode = session.getAttribute(tel_param+"driverAppLogin");
          if(verificationCode==null){
            setErrorMsg("请先获取验证码!");
            return get ResponseModel();
          }
          //3-校验验证码是否相等
          if(verificationCode_param.equals(verificationCode)){
              //4-校验验证码是否过期(1*60s)
            Object firstTime = session.getAttribute(tel_param+"driverAppLoginTime");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            boolean bool = overtimeCode(firstTime.toString(),sdf.format(new Date()),1*60);
            //bool等于true,则超时
            if(!bool){
                //5-业务逻辑
              //5-1 校验手机号在数据库中是否存在
              Integer id = this.carDriverMapper.selectByTel(carDriver);
              if(id != null){
                carDriver = this.carDriverMapper.selectByPrimaryKey(id);
                resultMap.put("name",carDriver.getName());
              }
              else{
                this.carDriverMapper.insertSelective(carDriver);
                if(carDriver.getId() == null){
                  setErrorMsg("新增驾驶员账号失败!");
                  throw new Exception(getErrorMsg());
                }
              }
              resultMap.put("id",carDriver.getId());
              resultMap.put("tel",carDriver.getTel());
              resultMap.put("level",carDriver.getLevel());
              setSuccess(true);
            }else{
              setErrorMsg("验证码获取超时,请重新获取!");
              return get ResponseModel();
            }
          }else{
            setErrorMsg("验证码输入不正确!");
            return get ResponseModel();
          }
        }catch (Exception e){
          e.printStackTrace();
          logger.error(e.getMessage());
        }finally {
          get ResponseModel().setData(resultMap);
          get ResponseModel().setSuccess(isSuccess());
          get ResponseModel().setErrorMsg(getErrorMsg());
        }
        return get ResponseModel();
      }
    
      @Override
      public  ResponseModel getVerificationCode(String conditionStr) {
        set ResponseModel(new  ResponseModel());
        setErrorMsg("");
        setSuccess(false);
        CarDriver carDriver = null;
        try {
          carDriver = JSON.parseObject(conditionStr, CarDriver.class);
          //1-校验手机号不能为空
          String tel = carDriver.getTel();
          if(StringUtils.isBlank(tel)){
            setErrorMsg("手机号不能为空!");
            return get ResponseModel();
          }
          //2-发送短信验证码
          //生成随机码
          String code = SmsCodeUtil.getRandom()+"";
          //发送验证码
          SendSmsResponse sendSmsResponse  = SmsSendUtil.sendSms(carDriver.getTel(),"app",code);
         //如果发送成功则保存验证码和时间到session中
          if(sendSmsResponse.getCode()!=null && sendSmsResponse.getCode().equals("OK")){
            HttpSession session = SessionUtil.getSession();
            session.setAttribute(tel+"driverAppLogin", code);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            session.setAttribute(tel+"driverAppLoginTime", sdf.format(new Date()));
            //获取sessionid
            String sessionId = session.getId();
            carDriver.setSessionId(sessionId);
            //设置session最长存在时间60分钟
           //SessionUtil.getSession().setMaxInactiveInterval(60*60);
            setSuccess(true);
          } else{
            setErrorMsg(sendSmsResponse.getMessage());
            return get ResponseModel();
          }
        } catch (Exception e) {
          e.printStackTrace();
          logger.error(e.getMessage());
        }
        finally {
          get ResponseModel().setData(carDriver);
          get ResponseModel().setSuccess(isSuccess());
          get ResponseModel().setErrorMsg(getErrorMsg());
        }
        return get ResponseModel();
      }
    
    
      /**
       * 短信验证码有效期,如果true则过期了
       * @param firstTime
       * @param lastTime
       * @param overtime
       * @return
       */
      private static boolean overtimeCode(String firstTime,String lastTime,long overtime){
        boolean flag=false;
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date one;
        Date two;
        try {
          one = df.parse(firstTime);
          two = df.parse(lastTime);
          long time1 = one.getTime();
          long time2 = two.getTime();
          long diff = time2 - time1;
          if(diff/1000>overtime){
            flag=true;
          }
        } catch (ParseException e) {
          e.printStackTrace();
        }
        return flag;
      }
    
    }

     附加:获取随机码工具类(我是投机取巧,拷贝腾讯云短信服务的demo中的)

    package com.test.util;
    
    import java.lang.StringBuffer;
    import java.util.Random;
    import java.util.ArrayList;
    
    import org.apache.commons.codec.digest.DigestUtils;
    
    
    public class SmsCodeUtil {
    
      public static boolean isNotEmpty(String s) {
        if (s == null || s.isEmpty()){
          return false;
        }
        return true;
      }
    
      public static long getCurrentTime() {
        return System.currentTimeMillis() / 1000;
      }
    
      public static long getRandom() {
        return (new Random(SmsCodeUtil.getCurrentTime())).nextInt(900000) + 100000;
      }
    
      public static String calculateSignature(String appkey, long random, long time,
                                              String phoneNumber) {
    
        StringBuffer buffer = new StringBuffer("appkey=")
          .append(appkey)
          .append("&random=")
          .append(random)
          .append("&time=")
          .append(time)
          .append("&mobile=")
          .append(phoneNumber);
    
        return sha256(buffer.toString());
      }
    
      public static String calculateSignature(String appkey, long random, long time,
                                              String[] phoneNumbers) {
    
        StringBuffer buffer = new StringBuffer("appkey=")
          .append(appkey)
          .append("&random=")
          .append(random)
          .append("&time=")
          .append(time)
          .append("&mobile=");
    
        if (phoneNumbers.length > 0) {
          buffer.append(phoneNumbers[0]);
          for (int i = 1; i < phoneNumbers.length; i++) {
            buffer.append(",");
            buffer.append(phoneNumbers[i]);
          }
        }
    
        return sha256(buffer.toString());
      }
    
      public static String calculateSignature(String appkey, long random, long time,
                                              ArrayList<String> phoneNumbers) {
        return calculateSignature(appkey, random, time, phoneNumbers.toArray(new String[0]));
      }
    
      public static String calculateSignature(String appkey, long random, long time) {
    
        StringBuffer buffer = new StringBuffer("appkey=")
          .append(appkey)
          .append("&random=")
          .append(random)
          .append("&time=")
          .append(time);
    
        return sha256(buffer.toString());
      }
    
      public static String calculateFStatusSignature(String appkey, long random,
                                                     long time, String fid) {
    
        StringBuffer buffer = new StringBuffer("appkey=")
          .append(appkey)
          .append("&random=")
          .append(random)
          .append("&time=")
          .append(time)
          .append("&fid=")
          .append(fid);
    
        return sha256(buffer.toString());
      }
    
      public static String calculateAuth(String appkey, long random, long time, String fileSha1Sum) {
        StringBuffer buffer = new StringBuffer("appkey=")
          .append(appkey)
          .append("&random=")
          .append(random)
          .append("&time=")
          .append(time)
          .append("&content-sha1=")
          .append(fileSha1Sum);
    
        return sha256(buffer.toString());
      }
    
      public static String sha1sum(String rawString) {
        return DigestUtils.sha1Hex(rawString);
      }
    
      public static String sha1sum(byte[] bytes) {
        return DigestUtils.sha1Hex(bytes);
      }
    
      public static String sha256(String rawString) {
        return DigestUtils.sha256Hex(rawString);
      }
    }

     SessionUtil.java

    package com.test.util;
    
    import com.test.enums.SysConstants;
    import java.util.Enumeration;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    /**
     * Created by test on 2017/9/21.
     *
     */
    public class SessionUtil {
        /**
         * 清空session
         */
        public static void cleanSession(){
            Enumeration em = getSession().getAttributeNames();
            while(em.hasMoreElements()){
                getSession().removeAttribute(em.nextElement().toString());
            }
        }
        /**
         * 获取上一个访问连接
         */
        public static String getBefUrl(){
            Enumeration e = getRequest().getHeaders("Referer");
            String befUrl;
            if(e.hasMoreElements()){
                befUrl = (String)e.nextElement();
            }else{
                befUrl = "";
            }
            return befUrl;
        }
        /**
         * 获取request
         */
        @SuppressWarnings("UnnecessaryLocalVariable")
        public static HttpServletRequest getRequest() {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    
            HttpServletRequest request = requestAttributes.getRequest();
    
            return request;
        }
        /**
         * 获取response
         */
        @SuppressWarnings("UnnecessaryLocalVariable")
        public static HttpServletResponse getResponse() {
            HttpServletResponse httpServletResponse = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    
            return httpServletResponse;
        }
    
        /**
         * 获取session
         */
        public static HttpSession getSession() {
            return getRequest().getSession();
        }
    
        /**
         * 验证是否重复提交
         */
        public static boolean checkSubmitRepeat(String jspToken) {
            String sessionToken = (String) getSession().getAttribute(SysConstants.SUBMITTOKEN.getName());
            return StringUtils.isBlank(jspToken) || StringUtils.isBlank(sessionToken)||!sessionToken.equals(jspToken);
        }
    
    }

     完毕!

     

  • 相关阅读:
    bootstrap只有遮罩层没有对话框的解决方法
    从陈坤微信号说起:微信公众平台开发者的江湖
    微信5.0绑定银行卡教程
    web.xml
    java 泛型
    Struts2
    Hibernate
    SQL Joins
    case when
    log4j
  • 原文地址:https://www.cnblogs.com/yangyuke1994/p/10240215.html
Copyright © 2011-2022 走看看