注册
技术:springcloud+rabbitMQ+redis+微服务+短信发送
前置准备:
启动mq:docker start mq
浏览器访问192.168.88.130:15672:
启动nacos:
在nacos的bin目录下输入cmd:startup.cmd -m standalone:
看到这两个面板说明启动成功。
注册流程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gQTQpgZW-1638519397073)(C:\Users\q\AppData\Roaming\Typora\typora-user-images\image-20211203155402604.png)]
前端:
main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
},
{
path: '/login',
name: 'Login',
component: () => import('../views/Login.vue')
},
{
path: '/reg',
name: 'reg',
component: () => import('../views/Register.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
Register.vue
<template>
<div style="text-align:left">
用户名:<input type="text" class="txt" v-model="user.username" name="username" />3-20位字符,可由中文、字母、数字和下划线组成<br>
密码 :<input type="password" class="txt" name="password" v-model="user.password"/>6-20位字符,可使用字母、数字和符号的组合,不建议使用纯数字、纯字母、纯符号<br>
确认密码:<input type="password" class="txt" name="password" v-model="user.repassword"/><br>
手机号码:<input type="text" class="txt" name="mobile" v-model="user.mobile" />
<button @click.prevent="sendSMS" :disabled="smsBtnDisabled">点击发送短信验证码<span v-if="smsBtnDisabled">{{second}}秒</span></button>
<br>
验证码:<input type="text" name="user.code" v-model="user.code"/><br>
<input type="submit" value="注册" @click="regist()"/>
</div>
</template>
<script>
export default {
data() {
return {
user:{},
smsBtnDisabled:false,// true 禁用按钮 false不禁用
second:5,//倒计时秒数
timer:null//倒计时对象
}
},
methods: {
// async sendSMS(){
// let res = await this.$http.get("/user/sendSms?phone="+this.user.mobile)
// // let res = await this.$http.get("/user/sendSms",{params:user.mobile})
// if(res.data.code==0){
// //发送成功
// // alert("发送成功")
// //按钮禁用
// this.smsBtnDisabled = true
// //倒计时:每个1s执行某个函数
// this.timer = setInterval(this.daojishi,1000)
// }
// },
sendSMS(){
alert(this.user.mobile)
this.$http.get("/user/sendSms?phone="+this.user.mobile)
.then(res => {
console.log(res)
if(res.data.code==0){
//发送成功
// alert("发送成功")
//按钮禁用
this.smsBtnDisabled = true
//倒计时:每个1s执行某个函数
this.timer = setInterval(this.daojishi,1000)
}
})
.catch(err => {
console.error(err);
})
},
daojishi(){
//如果second大于0,那second--
//否则停止倒计时,按钮生效
if(this.second>0){
this.second--
}else{
//停止倒计时
clearInterval(this.timer)
//恢复秒数。给下次使用
this.second=5
//按钮恢复
this.smsBtnDisabled = false
}
},
async regist(){
let res = await this.$http.post("/user/regist",this.user)
if(res.data.code==1){
alert("注册成功")
console.log(res)
this.$router.push("/login")
}else{
alert("注册失败")
}
}
},
}
</script>
<style>
</style>
后端:
jwt-parent父模块:
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>jwt-common</module>
<module>jwt-pojo</module>
<module>goods-search</module>
<module>user-service</module>
<module>jwt-auth</module>
<module>jwt-gateway</module>
<module>sms-consumer</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.czxy</groupId>
<artifactId>jwt-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>jwt-parent</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
<mybatis.starter.version>2.1.1</mybatis.starter.version>
<mapper.starter.version>1.2.3</mapper.starter.version>
<druid.starter.version>1.1.9</druid.starter.version>
<mysql.version>8.0.23</mysql.version>
<pageHelper.starter.version>1.2.3</pageHelper.starter.version>
<jjwt.version>0.7.0</jjwt.version>
<joda-time.version>2.9.6</joda-time.version>
<lombok.version>1.18.18</lombok.version>
</properties>
<!-- dependencyManagement
这个标签一般用在父项目中,他不是导入jar包的标签,只是用来限定jar包版本的标签
然后子项目依赖当前父项目,在子项目中导入需要的jar包坐标
子项目无需填入版本号,完全由父项目控制
-->
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mybatis启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.starter.version}</version>
</dependency>
<!-- 通用Mapper启动器 -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mapper.starter.version}</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pageHelper.starter.version}</version>
</dependency>
<!-- druid启动器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.starter.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${joda-time.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
jwt-common模块:
随机六位验证码util:
package com.czxy.util;
import java.util.Random;
/**
* @author shichang Zeng
* @program: jwt-parent
* @description:
* @date 2021-12-03 10:25:36
*/
public class RandomUtil {
public static String code(){
Random random = new Random();
String code = "";
for (int i=0;i<6;i++){
code+= random.nextInt(10);//产生0-9的随机验证码
}
return code;
}
}
user-service模块:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.czxy</groupId>
<artifactId>jwt-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>user-service</artifactId>
<packaging>jar</packaging>
<name>user-service</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>com.czxy</groupId>
<artifactId>jwt-pojo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.czxy</groupId>
<artifactId>jwt-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--AMQP依赖,包含RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
bootstrap.yml:
spring:
application:
name: userservice
datasource:
url: jdbc:mysql://localhost:3306/cloud_user1?useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
profiles:
active: dev
cloud:
nacos:
server-addr: localhost:8848
config:
file-extension: yaml
rabbitmq:
host: 192.168.88.130 # 主机名
port: 5672 # 端口
virtual-host: / # 虚拟主机
username: itcast # 用户名
password: 123321 # 密码
redis:
host: localhost
port: 6379
database: 0
jedis:
pool:
max-idle: 8
min-idle: 0
max-active: 8
server:
port: 8000
启动类:
package com.czxy.user;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class UserService01Application {
public static void main(String[] args) {
SpringApplication.run(UserService01Application.class, args);
}
@Bean
public Queue createSmsQueue(){
return new Queue("sms.queue");
}
}
mapper.UserMapper类:
package com.czxy.user.mepper;
import tk.mybatis.mapper.common.Mapper;
import com.czxy.pojo.User;
@org.apache.ibatis.annotations.Mapper
public interface UserMapper extends Mapper<User> {
}
service.UserService接口:
package com.czxy.user.service;
import com.czxy.pojo.User;
public interface UserService {
void insert(User user);
}
service.impl.UserServiceImpl实现接口:
package com.czxy.user.service.impl;
import com.czxy.pojo.User;
import com.czxy.user.mepper.UserMapper;
import com.czxy.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author shichang Zeng
* @program: jwt-parent
* @description:
* @date 2021-12-03 15:25:00
*/
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void insert(User user) {
userMapper.insert(user);
}
}
web.UserController类:
package com.czxy.user.web;
import com.czxy.pojo.User;
import com.czxy.user.service.UserService;
import com.czxy.util.RandomUtil;
import com.czxy.vo.BaseResult;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @author shichang Zeng
* @program: jwt-parent
* @description:
* @date 2021-11-18 09:25:00
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private UserService userService;
@Autowired
private StringRedisTemplate redisTemplate;
@PostMapping
public BaseResult addUser(@RequestBody User user) {
System.out.println("新增用户信息:" + user);
return BaseResult.ok("ok");
}
/**
* 1 产生随机码6位
* 2 保存到rabbitMQ中
* 3 保存到redis中
* 4 返回发送成功
*
* @param phone
* @return
*/
// xxxx/sendSms?phone=17602128959
@GetMapping("/sendSms")
public BaseResult sendSMS(String phone) {
// 1 产生随机码6位
String code = RandomUtil.code();
System.out.println(phone);
//拼接消息内容
String msg = phone + "%%%%%%" + code;
System.out.println(msg);
// 2 保存到rabbitMQ中
rabbitTemplate.convertAndSend("sms.queue", msg);
// 3 保存到redis中
redisTemplate.opsForValue().set(phone, code, 1, TimeUnit.MINUTES);
// 4 返回发送成功
return BaseResult.ok("成功");
}
@PostMapping("/regist")
public BaseResult regist(@RequestBody User user) {
// 1 根据手机号码去redis中取出验证码
String redisCode = redisTemplate.opsForValue().get(user.getMobile());
//2 验证码不存在,注册直接失败
if (redisCode == null) {
return BaseResult.error("失败");
}
//3 验证码存在,比较验证码
if (user.getCode().equals(redisCode)) {
// 验证码通过,比较两次密码是否一次
if (user.getPassword().equals(user.getRepassword())) {
//4 如果密码一致,注册成功,移除redis中的验证码
System.out.println("注册成功,保存到数据库" + user);
userService.insert(user);
redisTemplate.delete(user.getMobile());
return BaseResult.ok("注册成功" + user);
}
}
return BaseResult.error("失败");
}
}
jwt-gateway模块(filter过滤):
bootstrap.yml
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: goods-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://goods-service # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/search/** # 这个是按照路径匹配,只要以/user/开头就符合要求
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
- id: auth-service
uri: lb://authservice
predicates:
- Path=/auth/**
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8080"
- "http://192.168.81.27:8080"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
filters类:
package com.czxy.gateway.filters;
import com.czxy.util.JWTUtil;
import io.jsonwebtoken.Claims;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
@Order(-1)
public class JWTFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String url = exchange.getRequest().getURI().getPath();
System.out.println(url);
// 1 判断URL
if(url.toString().contains("login")||url.toString().contains("search")||url.toString().contains("sendSms")||url.toString().contains("regist")){
System.out.println("无需登录,直接放行");
return chain.filter(exchange);
}
2.获取请求参数
// MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
// // 3.获取authorization参数
// String token = params.getFirst("authorization");
String tokens = exchange.getRequest().getHeaders().getFirst("authorization");
// 4判断是否为空
if(tokens!=null&&!tokens.equals("")){
// 5 解析token
Claims claims = JWTUtil.parseToken(tokens, "user");
System.out.println(claims);
//6 判断解析是否成功
if(claims!=null){
//7 成功了,放行
return chain.filter(exchange);
}
}
// 8.拦截
// 8.1.禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 8.2.结束处理
return exchange.getResponse().setComplete();
}
}
启动类:
package com.czxy.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author shichang Zeng
* @program: jwt-parent
* @description:
* @date 2021-11-18 09:49:01
*/
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class);
}
}
sms-consumer模块(消费验证码):
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jwt-parent</artifactId>
<groupId>com.czxy</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sms-consumer</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--阿里云短信发送-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
<!-- MQ的jar包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
</project>
application.yml:
server:
port: 20000
spring:
rabbitmq:
host: 192.168.88.130 # 主机名
port: 5672 # 端口
virtual-host: / # 虚拟主机
username: itcast # 用户名
password: 123321 # 密码
启动类:
package com.czxy.sms;
import org.springframework.amqp.core.Queue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
/**
* @author shichang Zeng
* @program: jwt-parent
* @description:
* @date 2021-12-03 10:43:58
*/
@SpringBootApplication
public class SmsConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SmsConsumerApplication.class);
}
@Bean
public Queue createSmsQueue(){
return new Queue("sms.queue");
}
}
发送短信Util类:
package com.czxy.sms.util;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
/*
pom.xml
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
*/
public class AliyunSendSmsUtil {
/**
*
* @param to 手机号码
* @param code 验证码
*/
public static void send(String to, String code) {
String accessKeyId="LTAI5t8Kz6URnpkiRkJPtjGs";
String accessSecret = "Xv7U1NfgEAD5Of6dQzSS9VuxBUjlEi";
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret);
IAcsClient client = new DefaultAcsClient(profile);
CommonRequest request = new CommonRequest();
request.setSysMethod(MethodType.POST);
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendSms");
request.putQueryParameter("RegionId", "cn-hangzhou");
request.putQueryParameter("PhoneNumbers", to);
request.putQueryParameter("SignName", "老袁a洗脚6");
request.putQueryParameter("TemplateCode", "SMS_85550034");
request.putQueryParameter("TemplateParam", "{\"code\":\""+code+"\"}");
try {
CommonResponse response = client.getCommonResponse(request);
System.out.println(response.getData());
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// AliyunSendSmsUtil.send("17602128959","12396");
}
}
SmsListener监听类:
package com.czxy.sms.listener;
import com.czxy.sms.util.AliyunSendSmsUtil;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class SmsListener {
@RabbitListener(queues = "sms.queue")
public void listenerWorkQueue1(String msg) throws Exception{
String[] vals = msg.split("%%%%%%");
AliyunSendSmsUtil.send(vals[0],vals[1]);
System.out.println("sms接收到的消息:【"+msg+"】发送成功");
}
}