学习目标:
提示:学习如何利用Redis来实现发送验证码功能
学习产出:
1. 准备pom环境
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.47</version>
</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.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.17</version>
</dependency>
2. 配置ThreadLocal和过滤器
java
public class UserHolder {
private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
public static void saveUser(UserDTO user){
tl.set(user);
}
public static UserDTO getUser(){
return tl.get();
}
public static void removeUser(){
tl.remove();
}
}
java
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Autowired
private StringRedisTemplate redis;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(
new LoginInterceptor(redis))
//哪些请求放行不走过滤器
.excludePathPatterns("/user/code","/user/login","/blog/hot","/shop/**","/shop-type/**","/voucher/**");
}
}
---------------------------------------------
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
private StringRedisTemplate redis;
public LoginInterceptor(StringRedisTemplate redis) {
this.redis = redis;
}
//controller执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取请求头中的token
String authorization = request.getHeader("authorization");
if (StrUtil.isBlank(authorization)) {
response.setStatus(401);
return false;
}
//2.基于token获取Redis中的用户
Map<Object, Object> userMap = redis.opsForHash().entries("login:token:" + authorization);
//3.判断用户是否存在
if (userMap.isEmpty()) {
//4.不存在,拦截,401
response.setStatus(401);
return false;
}
//5.将查询到的Hash数据转换为Dto对象
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
//6.存在,保存信息到ThreadLocal
UserHolder.saveUser(userDTO);
//7.访问接口每次都会刷新token过期时间
redis.expire("login:token:" + authorization,30,TimeUnit.MINUTES);
//7.放行
return true;
}
//渲染后返回给前台数据前
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//移除用户,避免内存泄露
UserHolder.removeUser();
}
}
3. Controller层:负责接收请求和向下分配
java
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private IUserService userService;
/**
* 发送手机验证码
*/
@PostMapping("code")
public Result sendCode(@RequestParam("phone") String phone) {
//调用Service层来实现具体逻辑
return userService.sendCode(phone);
}
}
4. Service层:负责业务的处理逻辑
java
package com.hmdp.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hmdp.dto.LoginFormDTO;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.User;
import com.hmdp.mapper.UserMapper;
import com.hmdp.service.IUserService;
import com.hmdp.utils.RegexUtils;
import com.hmdp.utils.SystemConstants;
import com.hmdp.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.xml.validation.Validator;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.hmdp.utils.RedisConstants.*;
import static com.hmdp.utils.SystemConstants.USER_NICK_NAME_PREFIX;
/**
* <p>
* 服务实现类
* </p>
*
* @author 虎哥
* @since 2021-12-22
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
private static final ObjectMapper mapper = new ObjectMapper();
@Resource
private StringRedisTemplate redis;
@Override
public Result sendCode(String phone) {
//1.校验手机号
if (RegexUtils.isPhoneInvalid(phone)) {
//2.如果不符合,返回错误信息
return Result.fail("无效手机号");
}
//3.符合,生成验证码
String code = RandomUtil.randomNumbers(6);
//4.保存验证码到Redis中
redis.opsForValue().set(USER_NICK_NAME_PREFIX + phone, code, 60, TimeUnit.SECONDS);
//5.模拟发送验证码
log.info("发送验证码为===> {}", code);
//6.返回
return Result.ok();
}
//通过手机号创建新用户
private User createUserWithPhone(String phone) {
//创建用户
User user = new User();
user.setPhone(phone);
user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));
save(user);
return user;
}
}