springboot 集成阿里SMS服务
引入依赖
1 | <dependency> |
配置文件
1 | aliyun: |
获取配置文件的内容 properties
1 | package com.orchids.sms.web.custom.sms; |
1 | package com.orchids.sms.web.custom.sms; |
编写生成验证码工具类
1 | package com.orchids.sms.web.custom.utils; |
发送短信
sevice
1
2
3
4
5package com.orchids.sms.web.service;
public interface SmsService {
void sendCode(String phone, String Code);
}serviceImpl 测试阿里云短信服务格式必须是这个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package com.orchids.sms.web.service.impl;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.orchids.sms.web.service.SmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
public class SmsServiceImpl implements SmsService {
private Client client;
public void sendCode(String phone, String code) {
SendSmsRequest smsRequest = new SendSmsRequest();
smsRequest.setPhoneNumbers(phone);
smsRequest.setSignName("阿里云短信测试");
smsRequest.setTemplateCode("SMS_154950909");
smsRequest.setTemplateParam("{\"code\":\"" + code + "\"}");
System.out.println("---------------"+code);
try {
client.sendSms(smsRequest);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}测试发送短信
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22package com.orchids.sms.web.service;
import com.orchids.sms.web.custom.utils.CodeUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
/**
* @ Author qwh
* @ Date 2024/6/4 8:48
*/
class SmsServiceTest {
private SmsService smsService;
void sendCode() {
smsService.sendCode("phone", CodeUtil.getCode(4));
}
}获取登录接口
阿里云发送验证码给用户 —》用户输入验证码
后端登录 首先生成验证码 调用阿里云验证码API发送验证码 并将验证码保存到redis设置过期时间 用户输入验证码后和redis中进行比较 成功生成登录token
引入依赖1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<!--官方文档:https://github.com/jwtk/jjwt#install-jdk-maven -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
<version>0.11.2</version>
</dependency>编写生成token的工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49package com.orchids.sms.web.custom.utils;
import com.orchids.sms.web.custom.execupation.SmsException;
import com.orchids.sms.web.entity.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;
/**
* @Author qwh
* @Date 2024/6/2 21:01
*/
public class JwtUtil {
private static long tokenExpiration = 60 * 60 * 1000L;
public static SecretKey secretKey = Keys.hmacShaKeyFor("M0PKKI6pYGVWWfDZw90a0lTpGYX1d4AQ".getBytes());
public static String createToken(Long userId,String username){
String token = Jwts.builder().
setSubject("USER_INFO").
setExpiration(new Date(System.currentTimeMillis()+tokenExpiration)).
claim("userId",userId).
claim("username",username).
signWith(secretKey, SignatureAlgorithm.HS256).
compact();
return token;
}
public static Claims parsToken(String token){
if (token==null) {
throw new SmsException(ResultCodeEnum.ADMIN_LOGIN_AUTH);
}
try {
JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
Jws<Claims> claims = jwtParser.parseClaimsJws(token);
return claims.getBody();
} catch (ExpiredJwtException e) {
throw new SmsException(ResultCodeEnum.TOKEN_EXPIRED);
} catch (JwtException e){
throw new SmsException(ResultCodeEnum.TOKEN_INVALID);
}
}
public static void main(String[] args) {
System.out.println(createToken(9L,"123123"));
}
}获取验证码
controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package com.orchids.sms.web.controller;
import com.orchids.sms.web.custom.login.LoginUserHolder;
import com.orchids.sms.web.custom.utils.JwtUtil;
import com.orchids.sms.web.entity.result.Result;
import com.orchids.sms.web.entity.vo.LoginVo;
import com.orchids.sms.web.entity.vo.UserInfoVo;
import com.orchids.sms.web.service.LoginService;
import com.orchids.sms.web.service.UserInfoService;
import io.jsonwebtoken.Claims;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @ Author qwh
* @ Date 2024/6/4 1:10
*/
public class LoginController {
private LoginService loginService;
public Result getCode( { String phone)
loginService.getCode(phone);
return Result.ok();
}
}service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57package com.orchids.sms.web.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orchids.sms.web.custom.execupation.SmsException;
import com.orchids.sms.web.custom.utils.CodeUtil;
import com.orchids.sms.web.custom.utils.JwtUtil;
import com.orchids.sms.web.entity.pojo.BaseStatus;
import com.orchids.sms.web.entity.pojo.RedisConstant;
import com.orchids.sms.web.entity.pojo.UserInfo;
import com.orchids.sms.web.entity.result.ResultCodeEnum;
import com.orchids.sms.web.entity.vo.LoginVo;
import com.orchids.sms.web.service.LoginService;
import com.orchids.sms.web.service.SmsService;
import com.orchids.sms.web.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
public class LoginServiceImpl implements LoginService {
private SmsService smsService;
private StringRedisTemplate stringRedisTemplate;
private UserInfoService userInfoService;
public void getCode(String phone) {
//1. 检查手机号码是否为空
if (!StringUtils.hasText(phone)) {
throw new SmsException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
}
String key = RedisConstant.APP_LOGIN_PREFIX+phone;
Boolean hasKey = stringRedisTemplate.hasKey(key);
if (hasKey){
Long ttl = stringRedisTemplate.getExpire(key, TimeUnit.SECONDS);
if (RedisConstant.APP_LOGIN_CODE_TTL_SEC-ttl < 30 ) {
throw new SmsException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
}else {
String code = CodeUtil.getCode(6);
smsService.sendCode(phone,code);
stringRedisTemplate.opsForValue().set(key,code,RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
}
}else {
String code = CodeUtil.getCode(6);
smsService.sendCode(phone,code);
stringRedisTemplate.opsForValue().set(key,code,RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
}
}
}登录
controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class LoginController {
private LoginService loginService;
private UserInfoService userInfoService;
public Result getCode( { String phone)
loginService.getCode(phone);
return Result.ok();
}
public Result<String> login( { LoginVo loginVo)
String token = loginService.login(loginVo);
return Result.ok(token);
}
}service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70package com.orchids.sms.web.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orchids.sms.web.custom.execupation.SmsException;
import com.orchids.sms.web.custom.utils.CodeUtil;
import com.orchids.sms.web.custom.utils.JwtUtil;
import com.orchids.sms.web.entity.pojo.BaseStatus;
import com.orchids.sms.web.entity.pojo.RedisConstant;
import com.orchids.sms.web.entity.pojo.UserInfo;
import com.orchids.sms.web.entity.result.ResultCodeEnum;
import com.orchids.sms.web.entity.vo.LoginVo;
import com.orchids.sms.web.service.LoginService;
import com.orchids.sms.web.service.SmsService;
import com.orchids.sms.web.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
public class LoginServiceImpl implements LoginService {
private SmsService smsService;
private StringRedisTemplate stringRedisTemplate;
private UserInfoService userInfoService;
public String login(LoginVo loginVo) {
//判断手机号码和验证码是否为空
if (!StringUtils.hasText(loginVo.getPhone())) {
throw new SmsException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
}
if (!StringUtils.hasText(loginVo.getCode())){
throw new SmsException(ResultCodeEnum.APP_LOGIN_CODE_EMPTY);
}
//校验验证码
String key = RedisConstant.APP_LOGIN_PREFIX + loginVo.getPhone();
String code = stringRedisTemplate.opsForValue().get(key);
if (code==null){
throw new SmsException(ResultCodeEnum.APP_LOGIN_CODE_EXPIRED);
}
if (!code.equals(loginVo.getCode())) {
throw new SmsException(ResultCodeEnum.APP_LOGIN_CODE_ERROR);
}
//判断是否用户是否存在 不存在注册
LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserInfo::getPhone,loginVo.getPhone());
UserInfo userInfo = userInfoService.getOne(queryWrapper);
if (userInfo==null) {
userInfo = new UserInfo();
userInfo.setPhone(loginVo.getPhone());
userInfo.setStatus(BaseStatus.ENABLE);
userInfo.setNickname("用户-"+loginVo.getPhone().substring(6));
userInfoService.save(userInfo);
}
//判断用户是否被禁用
if (userInfo.getStatus().equals(BaseStatus.DISABLE)) {
throw new SmsException(ResultCodeEnum.APP_ACCOUNT_DISABLED_ERROR);
}
//返回token
return JwtUtil.createToken(userInfo.getId(), loginVo.getPhone());
}
}登录后获取登录信息
controller
1
2
3
4
5
6
7
8
9
public Result<UserInfoVo> info( { String token)
Claims claims = JwtUtil.parsToken(token);
Long userId = claims.get("userId", Long.class);
System.out.println(userId);
UserInfoVo userInfoVo = userInfoService.getUserInfoById(userId);
return Result.ok(userInfoVo);
}service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package com.orchids.sms.web.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orchids.sms.web.entity.pojo.UserInfo;
import com.orchids.sms.web.entity.vo.UserInfoVo;
import com.orchids.sms.web.mapper.UserInfoMapper;
import com.orchids.sms.web.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
implements UserInfoService {
private UserInfoMapper userInfoMapper;
public UserInfoVo getUserInfoById(Long userId) {
System.out.println(userId);
UserInfo userInfo = userInfoMapper.selectById(userId);
System.out.println(userInfo.toString());
return new UserInfoVo(userInfo.getNickname(), userInfo.getAvatarUrl());
}
}测试 通过 这个案例是基于我自己的程序 但是其他程序逻辑大差不多查
其中的枚举类 不同的业务会给出的 如果没有大不了自己编写
全局错误配置 按照自己的业务进行编写 以下是这个案例的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42package com.orchids.sms.web.custom.exception;
import com.orchids.sms.web.entity.result.ResultCodeEnum;
import lombok.Data;
/**
* @Author qwh
* @Date 2024/6/1 20:18
*/
public class SmsException extends RuntimeException {
//异常状态码
private Integer code;
/**
* 通过状态码和错误消息创建异常对象
* @param message
* @param code
*/
public SmsException(String message, Integer code) {
super(message);
this.code = code;
}
/**
* 根据响应结果枚举对象创建异常对象
* @param resultCodeEnum
*/
public SmsException(ResultCodeEnum resultCodeEnum) {
super(resultCodeEnum.getMessage());
this.code = resultCodeEnum.getCode();
}
public String toString() {
return "LovehouseException{" +
"code=" + code +
", message=" + this.getMessage() +
'}';
}
}完整的pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.orchids</groupId>
<artifactId>Sms</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Sms</name>
<description>Sms</description>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.0.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.23</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.2.4</version>
</dependency>
<!--官方文档:https://github.com/jwtk/jjwt#install-jdk-maven -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
<version>0.11.2</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.orchids.sms.SmsApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>application.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32# 应用服务 WEB 访问端口
server:
port: 8080
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2b8
username: yourname
password: yourpasswd
hikari:
connection-test-query: SELECT 1 # 自动检测连接
connection-timeout: 60000 #数据库连接超时时间,默认30秒
idle-timeout: 500000 #空闲连接存活最大时间,默认600000(10分钟)
max-lifetime: 540000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
maximum-pool-size: 12 #连接池最大连接数,默认是10
minimum-idle: 10 #最小空闲连接数量
pool-name: SPHHikariPool # 连接池名称
data:
redis:
host: localhost
port: 6379
database: 0
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
aliyun:
sms:
access-key-id: youaccesskey
access-key-secret: youraccesskeysecret
endpoint: dysmsapi.aliyuncs.com
评论