1,基于session实现
1.1 流程图
1.1 pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.8.0</version>
</dependency>
<!--Redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
1.2 配置文件
server:
port: 18083
spring:
application:
name: springboot_redis
datasource:
redis:
host: 127.0.0.1
port: 6379
database: 0
lettuce:
pool:
max-active: 8 #最大连接数
max-idle: 8 #最大空闲连接
min-idle: 0 #最小空闲连接
#连接等待时间
max-wait: 100
1.3 启动类
package com.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.study")
public class RedisSmsApplication {
public static void main(String[] args) {
SpringApplication.run(RedisSmsApplication.class,args);
}
}
1.4 完成拦截器
package com.study.intercept;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("preHandle");
//1.获取session
HttpSession session = request.getSession();
//2.获取session中的用户
Object user = session.getAttribute("user");
//3.判断用户是否存在. 不存在:拦截;存在:放入ThreadLocal,放行(写了ThreadLocal的封装工具类UserHolder)
if(user==null){
response.setStatus(401);
response.getWriter().write("user not login!");
return false;
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion");
}
}
1.5 完成拦截器config
package com.study.config;
import com.study.intercept.LoginInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@Slf4j
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
log.info("addInterceptors---");
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/smsSessionController/demo1",
"/smsSessionController/login",
"/smsSessionController/getSessionCode",
"/smsSessionController/sendCode"
);
}
}
1.6 完成工具类
- idsutil
/*
* 文 件 名:IdsUtil.java
* 系统名称:风险管控平台
* Copyright@2003-2019 State Grid Corporation of China, All Rights Reserved
* 版本信息:V1.0
* 版 权:NARI
*/
package com.study.utils;
import java.security.SecureRandom;
import java.util.UUID;
/**
* 概述:id生成工具类
* 功能:
* 作者:15657
* 创建时间:2019-05-29 14:20
*/
public class IdsUtil {
public static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"};
/**
* 生成8位uuid
*
* @return
*/
public static String getUUID8() {
StringBuffer shortBuffer = new StringBuffer();
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < 8; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]);
}
return shortBuffer.toString();
}
/**
* 生成16位uuid
*
* @return
*/
public static String getUUID16() {
String uuid = UUID.randomUUID().toString();
char[] cs = new char[32];
char c = 0;
for (int i = uuid.length() / 2, j = 1; i --> 0;) {
if ((c = uuid.charAt(i)) != '-') {
cs[j++] = c;
}
}
String uid = String.valueOf(cs);
return uid.trim();
}
/**
* 生成32位uuid
*
* @return
*/
public static String getUUID32() {
return UUID.randomUUID().toString().replace("-", "");
}
//生成指定长度字符串
public static String getRandomString(int length){
String base="0123456789";
SecureRandom random = new SecureRandom();
StringBuffer sb = new StringBuffer();
for(int i=0;i<length;i++){
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
- RegexUtils
package com.study.utils;
import java.util.regex.Pattern;
public class RegexUtils {
private RegexUtils() {
}
/**
* 验证电话号码
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isTel(CharSequence input) {
return estimate("^0\\d{2,3}[- ]?\\d{7,8}", input);
}
/**
* 验证身份证号码18位
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIDCard18(CharSequence input) {
return estimate("^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])$", input);
}
/**
* 验证手机号(简单)
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isMobileSimple(CharSequence input) {
return estimate("^[1]\\d{10}$", input);
}
/**
* 验证手机号(精确)
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isMobileExact(CharSequence input) {
return estimate("^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|(147))\\d{8}$", input);
}
/**
* 验证邮箱
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isEmail(CharSequence input) {
return estimate("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", input);
}
/**
* 验证URL
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isURL(CharSequence input) {
return estimate("[a-zA-z]+://[^\\s]*", input);
}
/**
* 验证汉字
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isChinesec(CharSequence input) {
return estimate("^[\\u4e00-\\u9fa5]+$", input);
}
/**
* 验证yyyy-MM-dd格式的日期校验
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isDate(CharSequence input) {
return estimate("^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$", input);
}
/**
* 验证IP地址
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIP(CharSequence input) {
return estimate("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)", input);
}
/**
* 判断是否匹配正则
*
* @param regex 正则表达式
* @param input 要匹配的字符串
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean estimate(String regex, CharSequence input) {
return input != null && input.length() > 0 && Pattern.matches(regex, input);
}
}
1.7 完成实体类
- LoginFormDTO
package com.study.entity;
import lombok.Data;
@Data
public class LoginFormDTO {
private String phone;
private String code;
}
- ResponseResult
package com.study.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class ResponseResult<T> implements Serializable {
private Boolean success;//是否成功
private Integer code;//状态码
private String message;//返回消息
private T data;
public ResponseResult() {
}
public static <T> ResponseResult<T> ok(){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setMessage("执行成功");
return responseResult;
}
public static <T> ResponseResult<T> ok(T data){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setMessage("执行成功");
responseResult.setData(data);
return responseResult;
}
public static <T> ResponseResult<T> error(Integer code){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(false);
responseResult.setCode(code);
responseResult.setMessage("执行失败");
return responseResult;
}
public static <T> ResponseResult<T> error(){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(false);
responseResult.setCode(ResultCode.ERROR);
responseResult.setMessage("执行失败");
return responseResult;
}
public ResponseResult<T> success(Boolean success){
this.setSuccess(success);
return this;
}
public ResponseResult<T> code (Integer code){
this.setCode(code);
return this;
}
public ResponseResult<T> message (String message){
this.setMessage(message);
return this;
}
public static<T> ResponseResult<T> exist (String message){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setMessage(message);
responseResult.setSuccess(true);
return responseResult;
}
public static<T> ResponseResult<T> exist (){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setSuccess(true);
return responseResult;
}
}
- ResultCode
package com.study.entity;
public class ResultCode {
public static final Integer SUCCESS = 200;
public static final Integer ERROR = 500;
public static final int NOT_LOGIN = 600;
public static final int NOT_AUTH = 700;
}
- User
package com.study.entity;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class User {
private String id;
private String name;
private Integer age;
}
1.8 完成对外接口
package com.study.session.controller;
import com.study.entity.LoginFormDTO;
import com.study.entity.ResponseResult;
import com.study.entity.User;
import com.study.utils.IdsUtil;
import com.study.utils.RegexUtils;
import io.lettuce.core.dynamic.annotation.Param;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
@Slf4j
@RestController
@RequestMapping("/smsSessionController")
public class SmsSessionController {
private static User user;
static {
user = new User();
user.setAge(25);
user.setId(IdsUtil.getUUID8());
user.setName("李乃龙");
}
/**
* 测试接口
* @return
*/
@GetMapping("demo1")
private String demo1(){
return "demo1";
}
/**
* 发送验证码
* @param phone
* @param session
* @return
*/
@GetMapping("sendCode")
private ResponseResult sendCode(@RequestParam("phone") String phone, HttpSession session){
//1.校验手机号:利用util下RegexUtils进行正则验证
boolean mobileExact = RegexUtils.isMobileExact(phone);
if(!mobileExact){
return ResponseResult.error().message("手机号格式不正确!");
}
//2.生成验证码:导入hutool依赖,内有RandomUtil
String code = IdsUtil.getUUID8();
//3.保存验证码到session
session.setAttribute(phone,code);
//4.发送验证码
log.info("验证码为: " + code);
log.debug("发送短信验证码成功!");
return ResponseResult.ok("发送短信验证码成功!验证码为: " + code);
}
/**
* 获取验证码
* @param session
* @return
*/
@GetMapping("getSessionCode")
private ResponseResult getSessionCode(@RequestParam("phone") String phone,HttpSession session){
//2.生成验证码:导入hutool依赖,内有RandomUtil
Object code = session.getAttribute(phone);
Object user = session.getAttribute("user");
return ResponseResult.ok("发送短信验证码成功!验证码为: " + code+",用户信息为:"+user);
}
/**
* 登录
* @param loginForm
* @param session
* @return
*/
@PostMapping("login")
private ResponseResult login(@RequestBody LoginFormDTO loginForm, HttpSession session){
//1.校验手机号
String phone = loginForm.getPhone();
if(!RegexUtils.isMobileExact(phone)){
return ResponseResult.error().message("手机号格式不正确!");
}
//2.校验验证码
Object cacheCode = session.getAttribute(phone);
String code = loginForm.getCode();
if(code==null||!cacheCode.toString().equals(code)){
//3.不一致,报错
return ResponseResult.error().message("验证码错误!");
}
//6.存入session
session.setAttribute("user",user.toString());
return ResponseResult.ok().message("登录成功!");
}
}
1.9 测试
-
http://localhost:18083/smsSessionController/sendCode?phone=18110229299
-
http://localhost:18083/smsSessionController/getSessionCode?phone=18110229299
-
http://localhost:18083/smsSessionController/login
1.10 集群的session共享问题
多台Tomcat不共享session存储空间,当请求切换到不同的tomcat服务时导致数据丢失的问题
所以我们把数据存入Redis,集群的Redis可以替代session
2,基于redis实现
2.1 pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.8.0</version>
</dependency>
<!--Redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.21</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.2 配置文件
server:
port: 18083
spring:
application:
name: springboot_redis
datasource:
redis:
host: 127.0.0.1
port: 6379
database: 0
lettuce:
pool:
max-active: 8 #最大连接数
max-idle: 8 #最大空闲连接
min-idle: 0 #最小空闲连接
#连接等待时间
max-wait: 100
2.3 启动类
package com.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.study")
public class RedisSmsApplication {
public static void main(String[] args) {
SpringApplication.run(RedisSmsApplication.class,args);
}
}
2.4 拦截器
package com.study.interceptor;
import com.study.constants.RedisConstants;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class LoginInterceptor implements HandlerInterceptor {
private final StringRedisTemplate stringRedisTemplate;
public LoginInterceptor(StringRedisTemplate stringRedisTemplate){
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取请求头中的token
String token = request.getHeader("authorization");
if (StringUtils.isEmpty(token)){
//不存在,拦截 设置响应状态吗为401(未授权)
response.setStatus(401);
return false;
}
//2.基于token获取redis中用户
String key= RedisConstants.LOGIN_USER_KEY + token;
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
//3.判断用户是否存在
if (userMap.isEmpty()){
//4.不存在则拦截,设置响应状态吗为401(未授权)
response.setStatus(401);
return false;
}
//7.更新token的有效时间,只要用户还在访问我们就需要更新token的存活时间
stringRedisTemplate.expire(key, RedisConstants.LOGIN_USER_TTL, TimeUnit.SECONDS);
//8.放行
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2.5 拦截器配置config
package com.study.config;
import com.study.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor(stringRedisTemplate))
.excludePathPatterns(
"/smsRedisController/demo1",
"/smsRedisController/login",
"/smsRedisController/getSessionCode",
"/smsRedisController/sendCode"
);
}
}
2.6 完成工具类
- IdsUtil
/*
* 文 件 名:IdsUtil.java
* 系统名称:风险管控平台
* Copyright@2003-2019 State Grid Corporation of China, All Rights Reserved
* 版本信息:V1.0
* 版 权:NARI
*/
package com.study.utils;
import java.security.SecureRandom;
import java.util.UUID;
/**
* 概述:id生成工具类
* 功能:
* 作者:15657
* 创建时间:2019-05-29 14:20
*/
public class IdsUtil {
public static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"};
/**
* 生成8位uuid
*
* @return
*/
public static String getUUID8() {
StringBuffer shortBuffer = new StringBuffer();
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < 8; i++) {
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]);
}
return shortBuffer.toString();
}
/**
* 生成16位uuid
*
* @return
*/
public static String getUUID16() {
String uuid = UUID.randomUUID().toString();
char[] cs = new char[32];
char c = 0;
for (int i = uuid.length() / 2, j = 1; i --> 0;) {
if ((c = uuid.charAt(i)) != '-') {
cs[j++] = c;
}
}
String uid = String.valueOf(cs);
return uid.trim();
}
/**
* 生成32位uuid
*
* @return
*/
public static String getUUID32() {
return UUID.randomUUID().toString().replace("-", "");
}
//生成指定长度字符串
public static String getRandomString(int length){
String base="0123456789";
SecureRandom random = new SecureRandom();
StringBuffer sb = new StringBuffer();
for(int i=0;i<length;i++){
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
- RegexUtils
package com.study.utils;
import java.util.regex.Pattern;
public class RegexUtils {
private RegexUtils() {
}
/**
* 验证电话号码
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isTel(CharSequence input) {
return estimate("^0\\d{2,3}[- ]?\\d{7,8}", input);
}
/**
* 验证身份证号码18位
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIDCard18(CharSequence input) {
return estimate("^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9Xx])$", input);
}
/**
* 验证手机号(简单)
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isMobileSimple(CharSequence input) {
return estimate("^[1]\\d{10}$", input);
}
/**
* 验证手机号(精确)
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isMobileExact(CharSequence input) {
return estimate("^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|(147))\\d{8}$", input);
}
/**
* 验证邮箱
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isEmail(CharSequence input) {
return estimate("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", input);
}
/**
* 验证URL
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isURL(CharSequence input) {
return estimate("[a-zA-z]+://[^\\s]*", input);
}
/**
* 验证汉字
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isChinesec(CharSequence input) {
return estimate("^[\\u4e00-\\u9fa5]+$", input);
}
/**
* 验证yyyy-MM-dd格式的日期校验
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isDate(CharSequence input) {
return estimate("^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$", input);
}
/**
* 验证IP地址
*
* @param input 待验证文本
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean isIP(CharSequence input) {
return estimate("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)", input);
}
/**
* 判断是否匹配正则
*
* @param regex 正则表达式
* @param input 要匹配的字符串
* @return {@code true}: 匹配<br>{@code false}: 不匹配
*/
public static boolean estimate(String regex, CharSequence input) {
return input != null && input.length() > 0 && Pattern.matches(regex, input);
}
}
2.7 完成常量类
package com.study.constants;
public class RedisConstants {
public static final String LOGIN_CODE_KEY = "login:code:";
public static final Long LOGIN_CODE_TTL = 10L;
public static final String LOGIN_USER_KEY = "login:token:";
public static final Long LOGIN_USER_TTL = 36000L;
public static final Long CACHE_NULL_TTL = 2L;
public static final Long CACHE_SHOP_TTL = 30L;
public static final String CACHE_SHOP_KEY = "cache:shop:";
public static final String LOCK_SHOP_KEY = "lock:shop:";
public static final Long LOCK_SHOP_TTL = 10L;
public static final String SECKILL_STOCK_KEY = "seckill:stock:";
public static final String BLOG_LIKED_KEY = "blog:liked:";
public static final String FEED_KEY = "feed:";
public static final String SHOP_GEO_KEY = "shop:geo:";
public static final String USER_SIGN_KEY = "sign:";
}
2.8 完成实体类
- LoginFormDTO
package com.study.entity;
import lombok.Data;
@Data
public class LoginFormDTO {
private String phone;
private String code;
}
- ResponseResult
package com.study.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class ResponseResult<T> implements Serializable {
private Boolean success;//是否成功
private Integer code;//状态码
private String message;//返回消息
private T data;
public ResponseResult() {
}
public static <T> ResponseResult<T> ok(){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setMessage("执行成功");
return responseResult;
}
public static <T> ResponseResult<T> ok(T data){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setMessage("执行成功");
responseResult.setData(data);
return responseResult;
}
public static <T> ResponseResult<T> error(Integer code){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(false);
responseResult.setCode(code);
responseResult.setMessage("执行失败");
return responseResult;
}
public static <T> ResponseResult<T> error(){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(false);
responseResult.setCode(ResultCode.ERROR);
responseResult.setMessage("执行失败");
return responseResult;
}
public ResponseResult<T> success(Boolean success){
this.setSuccess(success);
return this;
}
public ResponseResult<T> code (Integer code){
this.setCode(code);
return this;
}
public ResponseResult<T> message (String message){
this.setMessage(message);
return this;
}
public static<T> ResponseResult<T> exist (String message){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setMessage(message);
responseResult.setSuccess(true);
return responseResult;
}
public static<T> ResponseResult<T> exist (){
ResponseResult<T> responseResult = new ResponseResult<T>();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setSuccess(true);
return responseResult;
}
}
- ResultCode
package com.study.entity;
public class ResultCode {
public static final Integer SUCCESS = 200;
public static final Integer ERROR = 500;
public static final int NOT_LOGIN = 600;
public static final int NOT_AUTH = 700;
}
- User
package com.study.entity;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class User {
private String id;
private String name;
private Integer age;
}
2.9 完成对外接口
package com.study.controller;
import cn.hutool.core.lang.UUID;
import com.study.constants.RedisConstants;
import com.study.entity.LoginFormDTO;
import com.study.entity.ResponseResult;
import com.study.entity.User;
import com.study.utils.IdsUtil;
import com.study.utils.RegexUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
@Slf4j
@RestController
@RequestMapping("/smsRedisController")
public class SmsRedisController {
@Resource
private StringRedisTemplate stringRedisTemplate;
private static User user;
static {
user = new User();
user.setAge(25);
user.setId(IdsUtil.getUUID8());
user.setName("李乃龙");
}
/**
* 测试接口
* @return
*/
@GetMapping("demo1")
private String demo1(){
return "demo1";
}
/**
* 发送验证码
* @param phone
* @param session
* @return
*/
@GetMapping("sendCode")
private ResponseResult sendCode(@RequestParam("phone") String phone, HttpSession session){
//1.校验手机号:利用util下RegexUtils进行正则验证
boolean mobileExact = RegexUtils.isMobileExact(phone);
if(!mobileExact){
return ResponseResult.error().message("手机号格式不正确!");
}
//2.生成验证码:导入hutool依赖,内有RandomUtil
String code = IdsUtil.getUUID8();
//3.保存验证码到session
stringRedisTemplate.opsForValue().set(RedisConstants.LOGIN_CODE_KEY +phone,code, RedisConstants.LOGIN_CODE_TTL, TimeUnit.MINUTES);//有效期2mins
//4.发送验证码
log.info("验证码为: " + code);
log.debug("发送短信验证码成功!");
return ResponseResult.ok("发送短信验证码成功!验证码为: " + code);
}
/**
* 获取验证码
* @param session
* @return
*/
@GetMapping("getSessionCode")
private ResponseResult getSessionCode(@RequestParam("phone") String phone,
@RequestParam("tokenKey") String tokenKey,
HttpSession session){
// //2.生成验证码:导入hutool依赖,内有RandomUtil
String code = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + phone);
String user = stringRedisTemplate.opsForValue().get(tokenKey);
return ResponseResult.ok("发送短信验证码成功!验证码为: " + code+",用户信息为:"+user);
}
/**
* 登录
* @param loginForm
* @param session
* @return
*/
@PostMapping("login")
private ResponseResult login(@RequestBody LoginFormDTO loginForm, HttpSession session){
//1.校验手机号
String phone = loginForm.getPhone();
if(!RegexUtils.isMobileExact(phone)){
return ResponseResult.error().message("手机号格式不正确!");
}
//2.校验验证码
String cacheCode = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + phone);
String code = loginForm.getCode();
if(code==null||!cacheCode.toString().equals(code)){
//3.不一致,报错
return ResponseResult.error().message("验证码错误!");
}
//生成token
String token = UUID.randomUUID().toString(true);//hutools
//存储到Redis的key
String tokenKey = RedisConstants.LOGIN_USER_KEY + token;
//User转为HashMap存储
HashMap<Object, Object> userMap = new HashMap<>();
userMap.put("id", user.getId());
userMap.put("name", user.getName());
userMap.put("age", user.getAge());
//存储到Redis
stringRedisTemplate.opsForValue().set(tokenKey,userMap.toString());
//设置有效期
stringRedisTemplate.expire(tokenKey,RedisConstants.LOGIN_USER_TTL,TimeUnit.MINUTES);
return ResponseResult.ok().message("登录成功! tokenKey:"+tokenKey);
}
}
2.10 测试
- http://localhost:18083/smsRedisController/sendCode?phone=18110229299
- http://localhost:18083/smsRedisController/getSessionCode?phone=18110229299&tokenKey=login:token:12e812bd6f654dbfb71ff47b352ad222
- http://localhost:18083/smsRedisController/login