OSS-SMS(注册)

目录

一、OSS

1.开通阿里云服务

2.进入OOS对象存储的主页面

3.相关术语介绍

 4.创建Bucket

 5.在阿里云中直接操作文件上传

 6.阿里云图片访问问题

7.阿里云API使用

7.1使用前准备

7.2案例使用

7.3springboot项目:

 7.4spring-cloud项目

7.4.1图片的上传方式

7.4.2第三方公共服务中搭建OSS

​编辑

8.OSS跨域问题

 二、SMS

1.短信验证码接口

2.原始java调试代码 

3.拆解配置相应需要的变量 

4.完整代码模块 以及调用关系

5.调试代码 

6.微服务中远程Feign调用 

7.验证码的存储-Redis   时间间隔处理

8.验证码的校验

9.后端整合验证码发送与用户注册

10.注册时的JSR303数据校验 

11.远程用户注册服务密码加密等 


一、OSS

1.开通阿里云服务

阿里云服务地址: 阿里云-计算,为了无法计算的价值

2.进入OOS对象存储的主页面

 相关文档:OSSAPI的介绍以及资源术语说明_对象存储(OSS)-阿里云帮助中心

3.相关术语介绍

 4.创建Bucket

 5.在阿里云中直接操作文件上传

 

 6.阿里云图片访问问题

原因1:因为在OSS的Bucket权限设置为私有

原因2:没有对HTTP头进行设置,但是在阿里云2020年新发布的通知中需要自定义域名,使用默认域名时为下载,设置了inline貌似也不管用。

自定义域名:参考文档配置访问OSS文件时是预览行为_对象存储(OSS)-阿里云帮助中心

7.阿里云API使用

7.1使用前准备

 

Java操作的API文档地址:OSS Java SDK 兼容性和示例代码_对象存储(OSS)-阿里云帮助中心

7.2案例使用

 @Test
    public void testUploadFile() throws FileNotFoundException {
        // yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
        String endpoint = "oss-cn-guangzhou.aliyuncs.com";
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        String accessKeyId = "LTAI5tBPqoroToQNyrHpYJLR";
        String accessKeySecret = "3GnWaRhcBW3gUDhNSVr23fSrM6A0Q4";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        InputStream inputStream = new FileInputStream("C:\\Users\\dpb\\Downloads\\1111.jpg");
        // 依次填写Bucket名称(例如examplebucket)和Object完整路径(例如exampledir/exampleobject.txt)。Object完整路径中不能包含Bucket名称。
        ossClient.putObject("mashibing-mall", "1111.jpg", inputStream);

        // 关闭OSSClient。
        ossClient.shutdown();
        System.out.println("长传图片成功...");
    }

7.3springboot项目:

这里:

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>

<dependencies>
        <!--阿里云核心API-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.5.3</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>dysmsapi20170525</artifactId>
            <version>2.0.1</version>
        </dependency>
        <!--阿里云oss存储API-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.10.2</version>
        </dependency>
        <!--阿里云人识别-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>facebody20191230</artifactId>
            <version>1.0.10</version>
        </dependency>
        <!--百度人脸识别API-->
        <dependency>
            <groupId>com.baidu.aip</groupId>
            <artifactId>java-sdk</artifactId>
            <version>4.8.0</version>
        </dependency>
        <!--springboot基础起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.easemob.im</groupId>
            <artifactId>im-sdk-core</artifactId>
            <version>0.2.5</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-green</artifactId>
            <version>3.6.1</version>
        </dependency>
    </dependencies>
@Data
@ConfigurationProperties(prefix = "tanhua.oss")
public class OssProperties {

    private String accessKey;
    private String secret;
    private String url;//域名
    private String endpoint;
}
public class OssTemplate {

    private OssProperties properties;

    public OssTemplate (OssProperties properties){
        this.properties=properties;
    }

    /**
     *  文件上传
     *         1.文件名称
     *         2.输入流
     * @param fileName
     * @return
     */
     * @param inputStream
    public String upload(String fileName, InputStream inputStream) {
        //3.拼写图片名称--
        fileName = new SimpleDateFormat("yyy/MM/dd").format(new Date())
                + "/" + UUID.randomUUID().toString() + fileName.substring(fileName.lastIndexOf("."));
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = properties.getEndpoint();
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        String accessKeyId = properties.getAccessKey();
        String accessKeySecret = properties.getSecret();
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.putObject("tanhua-study-images", fileName, inputStream);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        String url=properties.getUrl()+"/"+fileName;
        return url;
    }
}
//使得properties生效-自动装备
@EnableConfigurationProperties({
        SmsProperties.class,
        OssProperties.class,
        AipFaceProperties.class,
        HuanXinProperties.class,
        GreenProperties.class
})
public class TanhuaAutoConfiguration {

    /**
     * 初始化SmsTemplate的对象
     * 发送短信 传入阿里云的模板与签名
     * @param properties
     * @return
     */
    @Bean
    public SmsTemplate smsTemplate(SmsProperties properties){
       return new SmsTemplate(properties);
    }

    /**
     * 初始化OssTemplate的对象  --保存图片等对象
     * @param properties
     * @return
     */
    @Bean
    public OssTemplate ossTemplate(OssProperties properties){

        return new OssTemplate(properties);

    }

    /**
     * 初始化FaceTemplate的对象  --人脸检测
     *
     * @return
     */
    @Bean
    public AipFaceTemplate aipFaceTemplate(){
        return new AipFaceTemplate();
    }

    /**
     * 环信云通讯
     * @param properties
     * @return
     */
    @Bean
    public HuanXinTemplate huanXinTemplate(HuanXinProperties properties){
        return new HuanXinTemplate(properties);
    }

    /**
     *  阿里内容审核
     * @param properties
     * @return
     */
    @Bean
    //检测配置文件中是否具有tanhua.green开头的配置 enable属性=true才回去装配对象
    @ConditionalOnProperty(prefix = "tanhua.green",value = "enable", havingValue = "true")
    public AliyunGreenTemplate aliyunGreenTemplate(GreenProperties properties) {
        return new AliyunGreenTemplate(properties);
    }
}

 7.4spring-cloud项目

直接通过阿里云提供的API操作相对的复杂一些,这时我们可以通过SpringCloudAlibaba OSS服务来简化开发,添加对应的依赖

<!--        阿里云OSS服务依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>

在属性文件中配置对应的AccessKey,SecurtKey和Endpoint

然后我们在业务代码中就可以直接从容器中获取OSSClient对象

 

7.4.1图片的上传方式

第一种方式:表单提交同步将表单数据和图片都提交到后端服务器中,然后在后端服务器中将图片再上传到阿里云服务中。

 但是这种方式的缺点是要做两次上传操作,还有就是将图片和正常的表单信息一起提交影响正常业务的效率。

第二种方式就是在客户端直接将图片上传到阿里云服务器中,返回访问的url地址,然后将url访问地址传递到后端服务进而保存在数据库中。

这种方式的缺点是在客户端需要获取AccessKey和SecuretKey,这样将相关的核心数据暴露在前端不安全。

第三种方式就是客户端向服务器获取阿里云的防伪签名,然后直接将图片通过防伪签名上传到阿里云服务器中。这样既提高了效率又保证了安全。

7.4.2第三方公共服务中搭建OSS

客户端需要从服务器中获取服务防伪签名信息,同时我们后面还有很多其他的第三方服务,比如发送短信等,这时我们可以专门创建一个第三方的服务来处理这些请求。

修改pom文件中的SpringBoot的版本和SpringCloud的版本使其和其他模块的版本保持一致,然后同步注册中心和配置中心的操作。引入阿里云OSS服务的相关API,并测试即可

属性文件:application.yml

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.56.100:8848
    alicloud:
      access-key: LTAI5tBPqoroToQNyrHpYJLR
      secret-key: 3GnWaRhcBW3gUDhNSVr23fSrM6A0Q4
      oss:
        endpoint: oss-cn-guangzhou.aliyuncs.com
        bucket: mashibing-mall
    application:
      name: mall-third
server:
  port: 8090

bootstrap.property  

spring.application.name=mall-third
spring.cloud.nacos.config.server-addr=192.168.56.100:8848

服务端生成签名:

生成签名地址:如何进行服务端签名直传_对象存储(OSS)-阿里云帮助中心

直接通过案例代码改造即可:如何通过Java在服务端签名直传并设置上传回调_对象存储(OSS)-阿里云帮助中心

@RestController
public class OSSController {

    @Autowired
    private OSS ossClient;

    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endpoint;
    @Value("${spring.cloud.alicloud.oss.bucket}")
    private String bucket;
    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;

    @RequestMapping("/oss/policy")
    public Map<String, String> getOssPolicy(){

        String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
        // callbackUrl为上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format+"/"; // 用户上传文件时指定的前缀。

        // 创建OSSClient实例。
        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        Map<String, String> respMap = null;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));


        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        } finally {
            ossClient.shutdown();
        }
        return respMap;
    }
}

客户端获取服务签名的时候肯定是走的网关路由,所以我们还需要在网关中添加Third服务的路由

7.4.3前端项目借助ElementUI中提供的el-upload组件来实现上传操作,我们预先准备了相关的上传代码

然后在添加修改品牌的窗口中添加上传的组件

在操作中,我们发下获取的数据是从response.data中获取的,但是我们在服务端返回的是Map数据,没有data封装,这时我们需要调整后端Thrid服务接口的返回信息通过R对象来返回

8.OSS跨域问题

出现跨域问题的解决方案

 二、SMS

1.短信验证码接口

通过阿里云的短信服务来实现。我们直接购买0元15次就可以了。(云市场)阿里云-计算,为了无法计算的价值

进入到对应的管理控制台,查看对应的信息

通过短信供应商提供的相关的编程语言的开发模板开发即可

本次我使用的是

根据下面的java代码进行修改

【三网106短信】短信接口-短信验证码-短信通知-数字藏品短信-短信API_支持转网_自定义签名模板【最新版】_实名认证接口/API_身份证接口/API_银行卡认证-云市场-阿里云 (aliyun.com)

2.原始java调试代码 

	public static void main(String[] args) {
	    String host = "https://gyytz.market.alicloudapi.com";
	    String path = "/sms/smsSend";
	    String method = "POST";
	    String appcode = "你自己的AppCode";
	    Map<String, String> headers = new HashMap<String, String>();
	   //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
	    headers.put("Authorization", "APPCODE " + appcode);
	    Map<String, String> querys = new HashMap<String, String>();
	    querys.put("mobile", "mobile");
	    querys.put("param", "**code**:12345,**minute**:5");

//smsSignId(短信前缀)和templateId(短信模板),可登录国阳云控制台自助申请。参考文档:http://help.guoyangyun.com/Problem/Qm.html

	    querys.put("smsSignId", "2e65b1bb3d054466b82f0c9d125465e2");
	    querys.put("templateId", "908e94ccf08b4476ba6c876d13f084ad");
	    Map<String, String> bodys = new HashMap<String, String>();


	    try {
	    	/**
	    	* 重要提示如下:
	    	* HttpUtils请从\r\n\t    \t* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java\r\n\t    \t* 下载
	    	*
	    	* 相应的依赖请参照
	    	* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
	    	*/
	    	HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
	    	System.out.println(response.toString());
	    	//获取response的body
	    	//System.out.println(EntityUtils.toString(response.getEntity()));
	    } catch (Exception e) {
	    	e.printStackTrace();
	    }
	}

根据注释中的地址去下载需要的HttpUtils 

3.拆解配置相应需要的变量 

/**
 * 短信发送服务
 * @author xjx
 * @email 15340655443@163.com
 * @date 2024/2/3 19:04
 */
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Data
@Component
public class SmsComponent {

    private String host;

    private String path;

    private String appKey;

    private String appSecret;

    private String appCode;

    private String method;
}

配置文件: 

1.要么采用上面OSS读取 @Value("${spring.cloud.alicloud.oss.endpoint}")的方式

2.这里采用@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")的方式

导入依赖 

<!--        读取配置文件相应下的变量依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

配置 

看sms:因为配置了@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")和依赖则可以自行读取 下面的变量

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        #server-addr: 118.31.103.120:8848
    alicloud:
      access-key: LTAI5t6K7YgappcN5KdhWiVH
      secret-key: Jsc57LxF5iWxDONL9CMEElcnAFH72m
      oss:
        endpoint: oss-cn-beijing.aliyuncs.com
        bucket: yueluo-mall
        yuming: yueluo.top
      sms:
        host: https://gyytz.market.alicloudapi.com
        path: /sms/smsSend
        app-code: f12f956c308347afb7f6d735242f80d1
        method: POST
        template-id: bcdf803fd96e41cd93baca751f6926cd
        sms-sign-id: 2e65b1bb3d054466b82f0c9d125465e2
  application:
    name: mall-third
server:
  port: 8090

4.完整代码模块 以及调用关系

import com.yueluo.mall.third.utils.HttpUtils;
import lombok.Data;
import org.apache.http.HttpResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 短信发送服务
 * @author xjx
 * @email 15340655443@163.com
 * @date 2024/2/3 19:04
 */
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Data
@Component
public class SmsComponent {

    private String host;

    private String path;

    private String appCode;

    private String method;

    private String templateId;

    private String smsSignId;

    public void sendSmsCode(String mobile,String code){
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appCode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("mobile", mobile);
        querys.put("param", "**code**:"+code+","+"**minute**:5");

//smsSignId(短信前缀)和templateId(短信模板),可登录国阳云控制台自助申请。参考文档:http://help.guoyangyun.com/Problem/Qm.html

        querys.put("smsSignId", smsSignId);
        querys.put("templateId", templateId);
        Map<String, String> bodys = new HashMap<String, String>();

        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            System.out.println(response.toString());
            //获取response的body
            //System.out.println(EntityUtils.toString(response.getEntity()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
package com.yueluo.mall.third.controller;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.yueluo.mall.third.component.SmsComponent;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 短信发送
 * @author xjx
 * @email 15340655443@163.com
 * @date 2024/2/3 17:34
 */
@Controller
@RequestMapping("third/sms")
public class SMSController {

    @Autowired
    private SmsComponent smsComponent;

    @PostMapping("/sendSmsCode")
    public void sendSmsCode(){
        smsComponent.sendSmsCode("51567894653","123456");
    }
}

5.调试代码 

    @Autowired
    private SmsComponent smsComponent;

    /**
     * 发送手机验证码
     */
    @Test
    public void sendMsg(){
        smsComponent.sendSmsCode("15340656889", "123456");
    }

6.微服务中远程Feign调用 

@EnableFeignClients(basePackages = {"com.yueluo.mall.auth.feign"})
@EnableDiscoveryClient
@SpringBootApplication
public class MallAuthServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(MallAuthServerApplication.class, args);
    }

}
/**
 * 远程调用第三方服务接口
 * @author xjx
 * @email 15340655443@163.com
 * @date 2024/2/4 15:08
 */
@FeignClient("mall-third")
public interface ThirdFeignService {

    /**
     * 远程调用第三方 短信 服务接口 发送手机验证码
     * @param map
     */
    @PostMapping("third/sms/sendCode")
    public R sendSmsCode(@RequestBody Map<String,String> map);
}

7.验证码的存储-Redis   时间间隔处理

/**
 * 前台登录页面--config中进行了批量配置
 * @author xjx
 * @email 15340655443@163.com
 * @date 2024/2/3 12:44
 */
@RestController
public class LoginController {



    @Autowired
    private ThirdFeignService thirdFeignService;


    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 给前端传过来的手机号调用第三方服务发送验证码
     * @param map
     * @return
     */
    @PostMapping("/register/sendCode")
    public R login(@RequestBody Map<String,String> map){
        String mobile = map.get("mobile");
        //60s间隔校验
        String codeAndTime = (String) redisTemplate.opsForValue().get(SMSConstant.SMS_CODE_REGISTER + mobile);
        if (StringUtils.isNotEmpty(codeAndTime)){
            //已经发过一次了
            Long lastTime=Long.parseLong(codeAndTime.split("_")[1]);
            if (System.currentTimeMillis()-lastTime<=600000){
                //说明间隔时间不足60s
                return R.error(BugCodeEnume.VALID_SMS_EXCEPTION.getCode(),BugCodeEnume.VALID_SMS_EXCEPTION.getMessage());
            }
        }
        System.out.println("发送验证码成功");
        String code = UUID.randomUUID().toString().substring(0, 5);
        map.put("code",code);
        thirdFeignService.sendSmsCode(map);
        //调用redis存储手机验证码  与时间
        code=code+"_"+System.currentTimeMillis();
        redisTemplate.opsForValue().set(SMSConstant.SMS_CODE_REGISTER+mobile,code,10, TimeUnit.MINUTES);
        return R.ok();
    }
}

8.验证码的校验

就正常在redis中取 注意String的判断用equals

完整前后端 

//发送Post请求
	function httpPost(url, params) {
		return fetch(url, {
			method: "POST",
			headers: {
				"Content-Type": "application/json"
			},
			body: JSON.stringify(params)
		})
				.then(response => {
					return response.json(); // 返回 response.json() 的结果
				})
				.then(data => {
					if (data.code != 0) {
						alert(data.msg); // 弹出错误消息
						throw new Error("请求出错"); // 抛出自定义错误对象
					}
					return data;
				})
				.catch(error => {
					console.error("请求出错: ", error);
				});
	}



	$(function(){
		$("#sendcode").click(function(){
			//给指定的手机发送验证码
			//先判断是否可以点击(是否在倒计时中)
			if ($("#sendcode").hasClass("disable")){
				//说明正在倒计时 不可点击

			}else{
				//点击后 触发倒计时-并发送验证码
				var url="/register/sendCode"
				var params = {
					"mobile": $("#phoneNum").val()
				}
				httpPost(url,params);
				timeoutChangeStyle()
			}
		})
	})

	//再次发送验证码倒计时  计时器
	var Countdown=60

	//倒计时方法
	function timeoutChangeStyle(){
		//在倒计时的时候 使得它不可以再点击 控制属性(有这个属性则不可以在触发倒计时)
		$("#sendcode").attr("class","disable")
		if (Countdown==0){
			//倒计时结束 可以再次发送验证码
			$("#sendcode").text("发送验证码")
			//防止负数注意重置
			Countdown=60;
			//并使得它可以在点击
			$("#sendcode").attr("class","")
		}else {
			//倒计时未结束 继续递减(继续执行倒计时方法)
		    setTimeout('timeoutChangeStyle()',1000);//每隔一秒触发一次
			//文本变化
			$("#sendcode").text(Countdown+"s后在发送")
		}
		//进行时间递减
		Countdown--;
	}

9.后端整合验证码发送与用户注册

import com.yueluo.mall.auth.feign.MemberFeignService;
import com.yueluo.mall.auth.feign.ThirdFeignService;
import com.yueluo.mall.auth.vo.UserRegisterVo;
import com.yueluo.mall.common.constant.redis.SMSConstant;
import com.yueluo.mall.common.exception.BugCodeEnume;
import com.yueluo.mall.common.utils.R;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

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

/**
 * 前台登录页面--config中进行了批量配置
 * @author xjx
 * @email 15340655443@163.com
 * @date 2024/2/3 12:44
 */
@Controller
public class LoginController {



    @Autowired
    private ThirdFeignService thirdFeignService;

    @Autowired
    private MemberFeignService memberFeignService;


    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 给前端传过来的手机号调用第三方服务发送验证码
     * @param map
     * @return
     */
    @ResponseBody
    @PostMapping("/register/sendCode")
    public R login(@RequestBody Map<String,String> map){
        String mobile = map.get("mobile");
        //60s间隔校验
        String codeAndTime = (String) redisTemplate.opsForValue().get(SMSConstant.SMS_CODE_REGISTER + mobile);
        if (StringUtils.isNotEmpty(codeAndTime)){
            //已经发过一次了
            Long lastTime=Long.parseLong(codeAndTime.split("_")[1]);
            if (System.currentTimeMillis()-lastTime<=600000){
                //说明间隔时间不足60s
                return R.error(BugCodeEnume.VALID_SMS_EXCEPTION.getCode(),BugCodeEnume.VALID_SMS_EXCEPTION.getMessage());
            }
        }
        String code = UUID.randomUUID().toString().substring(0, 4);
        map.put("code",code);
        System.out.println("发送验证码成功:"+map);
//        thirdFeignService.sendSmsCode(map);
        //调用redis存储手机验证码  与时间
        code=code+"_"+System.currentTimeMillis();
        redisTemplate.opsForValue().set(SMSConstant.SMS_CODE_REGISTER+mobile,code,10, TimeUnit.MINUTES);
        return R.ok();
    }

    @PostMapping("/register")
    public String  register(@Validated UserRegisterVo userRegisterVo, BindingResult result, Model model){
        //存储校验错误信息error
        HashMap<String, String> error = new HashMap<>();
        //校验
        if (result.hasErrors()){
            //提交的数据有不合法的值
            List<FieldError> fieldErrors = result.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
                error.put(fieldError.getField(),fieldError.getDefaultMessage());
            }
            model.addAttribute("error",error);
            return "register";
        }
        //合法---进行数据的校验(手机验证码)
        //从redis中取得code
        String codeAndTime = redisTemplate.opsForValue().get(SMSConstant.SMS_CODE_REGISTER + userRegisterVo.getPhone()).toString();
        String code = codeAndTime.split("_")[0];
        if (!code.equals(userRegisterVo.getCode())){
            //手机验证码错误  请重新输入
            error.put("code","手机验证码错误请重新输入");
            model.addAttribute("error",error);
            return "register";
        }
        //验证码验证无误--远程调用用户服务进行注册
        //删除redis中的验证码
        redisTemplate.delete(SMSConstant.SMS_CODE_REGISTER + userRegisterVo.getPhone());
        R isRegister = memberFeignService.register(userRegisterVo);
        System.out.println(isRegister);
        if (isRegister.getCode()!=0){
            //注册失败
            if (isRegister.getCode()==BugCodeEnume.MEMBER_USERNAMEEXIST_EXCEPTION.getCode()){
                error.put("name",isRegister.getMsg());
            }
            if (isRegister.getCode()==BugCodeEnume.MEMBER_PHONEEXIST_EXCEPTION.getCode()){
                error.put("phone",isRegister.getMsg());
            }
            model.addAttribute("error",error);
            return "register";
        }
        System.out.println("注册成功");
        return  "redirect:http://www.yueluo.auth.top/login.html";
    }
}

10.注册时的JSR303数据校验 

package com.yueluo.mall.auth.vo;

import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

/**
 * 注册用户的接收对象
 * @author xjx
 * @email 15340655443@163.com
 * @date 2024/2/5 8:45
 */
@Data
public class UserRegisterVo {

    //账号
    @NotEmpty(message = "账号不能为空")
    @Length(min = 3,max = 15,message = "账号必须是3~15位")
    private String userName;

    //密码
    @NotEmpty
    @Length(min = 3,max = 15,message = "密码必须是3~15位字符或数字")
    private String password;


    //手机验证码
    @NotEmpty
    @Length(min = 4,max = 4,message = "请输入4位有效验证码")
    private String code;

    //手机号码
    @NotEmpty
    @Pattern(regexp = "^[1][3-9][0-9]{9}$",message = "请输入正确的手机号码")
    private String phone;
}

11.远程用户注册服务密码加密等 


    /**
     * 会员注册
     *
     * @param registerVo
     */
    @Override
    public void register(MemberRegisterVo registerVo) throws RuntimeException {
        MemberEntity memberEntity = new MemberEntity();
        //判断用户是否已经存在
        checkExist(registerVo.getUserName(), registerVo.getPhone());
        memberEntity.setUsername(registerVo.getUserName());
        memberEntity.setNickname(registerVo.getUserName());
        //判断手机号是否已经存在
        memberEntity.setMobile(registerVo.getPhone());
        memberEntity.setStatus(1);
        memberEntity.setCreateTime(new Date());
        //密码加密处理--BCryptPasswordEncoder  加盐处理  加密处理
        String password = new BCryptPasswordEncoder().encode(registerVo.getPassword());
        memberEntity.setPassword(password);
        //设置默认的会员等级
        memberEntity.setLevelId(memberLevelService.getDefaultLevelId());

        memberDao.insert(memberEntity);
    }


 /**
     * 判断用户是否存在
     * @param name
     * @param phone
     */
    private void checkExist(String name, String phone) {
        //根据用户名或手机号进行查询用户
        List<MemberEntity> list = this.list(new QueryWrapper<MemberEntity>()
                                                .eq("username", name)
                                                .or()
                                                .eq("mobile", phone));
        //如果查询结果不为空
        if (list != null && list.size() > 0) {
            //查询结果不唯一则说明  用户名和手机号均已存在  不能重复
            if (list.size() > 1) {
                throw new RuntimeException("用户名和手机号均已存在");
            }
            //查询结果不唯一
            MemberEntity memberEntity = list.get(0);
            //判断重复字段是哪个
            if (memberEntity.getUsername().equals(name)) {
                throw new UserNameExsitException("用户名已经存在");
            }
            if (memberEntity.getMobile().equals(phone)) {
                throw new PhoneExistException("手机号已经存在");
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值