目录
一、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代码进行修改
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("手机号已经存在");
}
}
}