网站做app的软件有哪些大连地区购物小程序有哪些

当前位置: 首页 > news >正文

网站做app的软件有哪些,大连地区购物小程序有哪些,农副产品销售网站开发,网络游戏下载搭配食用#xff1a;Redis#xff08;基础篇#xff09;-CSDN博客 项目实现前的 Mysql中的表#xff1a; 表说明tb_user用户表tb_user_info用户详情表tb_shop商户信息表tb_shop_type商户类型表tb_blog用户日记表#xff08;达人探店日记)tb_follow用户关注表tb_voucher优… 搭配食用Redis基础篇-CSDN博客 项目实现前的 Mysql中的表 表说明tb_user用户表tb_user_info用户详情表tb_shop商户信息表tb_shop_type商户类型表tb_blog用户日记表达人探店日记)tb_follow用户关注表tb_voucher优惠券表tb_voucherorder优惠券的订单表 启动前端服务器 start nginx.exe 手机端首页 localhost:8080 项目架构 手机或者app端发起请求请求我们的Nginx服务器Nginx基于七层模型走的是HTTP协议可以实现基于Lua直接绕开Tomcat访问Redis也可以作为静态资源服务器轻松扛下上万并发 负载均衡到下游Tomcat服务器打散流量我们都知道一台4核8G的Tomcat在优化和处理简单业务的加持下大不了就处理1000左右的并发 经过Nginx的负载均衡分流后利用集群支撑起整个项目同时Nginx在部署了前端项目后更是可以做到动静分离进一步降低Tomcat服务的压力这些功能都得靠Nginx起作用所以Nginx是整个项目中重要的一环。 在Tomcat支撑起并发流量后我们如果让Tomcat直接去访问Mysql根据经验Mysql企业级服务器只要上点并发一般是16或32 核心cpu32 或64G内存像企业级mysql加上固态硬盘能够支撑的并发大概就是4000起~7000左右上万并发 瞬间就会让Mysql服务器的cpu硬盘全部打满容易崩溃所以我们在高并发场景下会选择使用mysql集群同时为了进一步降低Mysql的压力同时增加访问的性能我们也会加入Redis同时使用Redis集群使得Redis对外提供更好的服务。 邮箱登录  发送验证码 用户在提交手机号后会校验手机号是否合法如果不合法则要求用户重新输入手机号 如果手机号合法后台此时生成对应的验证码同时将验证码进行保存然后再通过短信的方式将验证码发送给用户短信验证码登录、注册 用户将验证码和手机号进行输入后台从session中拿到当前验证码然后和用户输入的验证码进行校验如果不一致则无法通过校验如果一致则后台根据手机号查询用户如果用户不存在则为用户创建账号信息保存到数据库无论是否存在都会将用户信息保存到session中方便后续获得当前登录信息校验登录状态 用户在请求的时候会从cookie中携带JsessionId到后台后台通过JsessionId从session中拿到用户信息如果没有session信息则进行拦截如果有session信息则将用户信息保存到threadLocal中并放行 实现发送邮箱验证码功能  输入手机号点击发送验证码按钮后会发送一个请求 调用UserController中的code方法携带参数是phone  但是黑马这里并不会真的使用短信服务发送验证码只是随机生成了一个验证码那我这里为了后期项目能真的部署上线还是打算用邮箱验证由于黑马这里貌似没有设置前端的手机号正则判断所以我们只需要去数据库中修改phone的字段类型将varchar(11)改为varchar(100) 首先导入邮箱验证需要的maven坐标 !– https://mvnrepository.com/artifact/javax.activation/activation – dependencygroupIdjavax.activation/groupIdartifactIdactivation/artifactIdversion1.1.1/version /dependency !– https://mvnrepository.com/artifact/javax.mail/mail – dependencygroupIdjavax.mail/groupIdartifactIdmail/artifactIdversion1.4.7/version /dependency !– https://mvnrepository.com/artifact/org.apache.commons/commons-email – dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-email/artifactIdversion1.4/version /dependency 然后编写一个工具类用于发送邮件验证码 package com.hmdp.utils;import javax.mail.; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Properties;public class MailUtils {public static void main(String[] args) throws MessagingException {sendTestMail(1796491347qq.com, new MailUtils().achieveCode());}public static void sendTestMail(String email, String code) throws MessagingException {//创建Properties类用于记录邮箱的一些属性Properties props new Properties();//设置发送邮件的邮件服务器的属性这里使用腾讯的smtp服务器//表示SMTP发送邮件必须进行身份验证props.put(mail.smtp.auth, true);//此处填写SMTP服务器props.put(mail.smtp.host, smtp.qq.com);//端口号QQ邮箱端口587props.put(mail.smtp.port, 587);//此处填写写信人的QQ账号props.put(mail.user, 1796491347qq.com);//此处填写16位STMP授权码props.put(mail.password, dpvzxlrnbycdegaf);//构建授权信息用于进行SMTP进行身份验证Authenticator authenticator new Authenticator() {protected PasswordAuthentication getPasswordAuthentication() {//用户名、密码String username props.getProperty(mail.user);String password props.getProperty(mail.password);return new PasswordAuthentication(username, password);}};//使用环境属性和授权信息创建邮件会话Session mailSession Session.getInstance(props, authenticator);//创建邮件消息MimeMessage message new MimeMessage(mailSession);//设置发件人InternetAddress form new InternetAddress(props.getProperty(mail.user));message.setFrom(form);//设置收件人的邮箱地址InternetAddress to new InternetAddress(email);message.setRecipient(MimeMessage.RecipientType.TO,to);//设置邮件标题message.setSubject(验证码 邮件测试);//设置邮件的内容体message.setContent(验证码是code,text/html;charsetUTF-8);//发送邮件Transport.send(message);}public static String achieveCode(){//由于数字1、0和字母O、I容易混淆所以这里生成的验证码不包含1和OString[] beforeShuffle new String[]{2, 3, 4, 5, 6, 7, 8, 9,A, B, C, D, E, F, G, H, I, J, K, L, M,N, P, Q, R, S, T, U, V, W, X, Y, Z,a, b, c, d, e, f, g, h, i, j, k, m,n, p, q, r, s, t, u, v, w, x, y, z};ListString list Arrays.asList(beforeShuffle);//将数组转换为集合Collections.shuffle(list);//打乱集合内元素顺序StringBuilder sb new StringBuilder();for(String s : list){sb.append(s);//获取打乱顺序后的集合元素并拼接成字符串}return sb.substring(3,8);} } 授权码 修改sendCode方法逻辑如下  验证手机号/邮箱格式  不正确则返回错误信息 正确则发送验证码 然后输入邮箱发送验证码看看能否接收到验证码 /** 发送手机验证码/PostMapping(code)public Result sendCode(RequestParam(phone) String phone, HttpSession session) throws MessagingException {// TODO 发送短信验证码并保存验证码if(RegexUtils.isEmailInvalid(phone)){return Result.fail(邮箱格式错误);}String code MailUtils.achieveCode();session.setAttribute(phone,code);log.info(发送登录验证码{},code);MailUtils.sendTestMail(phone,code);return Result.ok();} 实现登录、注册功能 点击登录按钮查看发送的请求  请求网址: http://localhost:8080/api/user/login 请求方法: POST  UserController中的login方法携带的参数也就是我们的邮箱和验证码  {phone: 1796491347qq.com, code: 4Nr3k} 邮箱和验证码封装到了LoginFormDto中 修改login方法逻辑如下 校验手机号/邮箱 不正确则返回错误信息正确则继续校验验证码 不一致则报错一致则先根据手机号/邮箱查询用户 用户不存在则创建存在则继续执行程序保存用户信息到session中 /** 登录功能* param loginForm 登录参数包含手机号、验证码或者手机号、密码*/PostMapping(/login)public Result login(RequestBody LoginFormDTO loginForm, HttpSession session){// TODO 实现登录功能//获取登录账号String phone loginForm.getPhone();//获取登录验证码String code loginForm.getCode();//获取session中的验证码Object cacheCode session.getAttribute(phone);//1. 校验邮箱if(RegexUtils.isEmailInvalid(phone)){//2.不符合格式则报错return Result.fail(邮箱格式错误);}//3.校验验证码log.info(code:{},cacheCode{},code,cacheCode);if(code null || !cacheCode.toString().equals(code)){//4.不一致则报错return Result.fail(验证码错误);}//5.根据账号查询用户是否存在LambdaQueryWrapperUser queryWrapper new LambdaQueryWrapper();queryWrapper.eq(User::getPhone,phone);User user userService.getOne(queryWrapper);//6.用户不存在则创建新用户if(user null){//创建的逻辑封装成一个方法user createUserWithPhone(phone);}//7.保存用户信息到session中session.setAttribute(user,user);return Result.ok();} private User createUserWithPhone(String phone) {//创建用户User user new User();//设置手机号user.setPhone(phone);//设置昵称(默认名)一个固定前缀随机字符串user.setNickName(user RandomUtil.randomString(8));//保存到数据库userService.save(user);return user; } 实现登录拦截功能拦截器 创建一个LoginInterceptor类实现HandlerInterceptor接口重写其中的两个方法前置拦截器和完成处理方法前置拦截器主要用于我们登陆之前的权限校验完成处理方法是用于处理登录后的信息避免内存泄露  utils包下的工具类-拦截器  /*** 拦截器/ public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {// 1.获取SessionHttpSession session request.getSession();// 2.获取Session中的用户Object user session.getAttribute(user);// 3.判断用户是否存在if (user null) {// 4.不存在拦截返回401状态码response.setStatus(401);return false;}// 5.存在保存用户信息到ThreadLocalUserHolder.saveUser((User) user);// 6.放行return true;}Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserHolder.removeUser();} }config包下的配置类 import com.hmdp.utils.LoginInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** MVC配置类用于自定义Spring MVC的配置。/ Configuration public class MvcConfig implements WebMvcConfigurer {/** 添加拦截器配置。** 本方法旨在注册一个登录拦截器并排除一些不需要拦截的路径。* 排除的路径通常是一些公共资源路径或者登录相关路径这些路径不需要用户登录即可访问。** param registry 拦截器注册表用于添加和配置拦截器。/Overridepublic void addInterceptors(InterceptorRegistry registry) {// 添加登录拦截器registry.addInterceptor(new LoginInterceptor())// 排除不需要拦截的路径.excludePathPatterns(/shop/, // 商城相关路径/shop-type/, // 商城类型路径/upload/, // 上传路径/blog/hot, // 热门博客路径/user/code, // 用户验证码路径/user/login // 用户登录路径);} } utils包下的工具类-保存用户信息到ThreadLocal import com.hmdp.entity.User;public class UserHolder {private static final ThreadLocalUser tl new ThreadLocal();public static void saveUser(User userId){tl.set(userId);}public static User getUser(){return tl.get();}public static void removeUser(){tl.remove();} } UserController中的方法 GetMapping(/me)public Result me(){// TODO 获取当前登录的用户并返回User user UserHolder.getUser();return Result.ok(user);} 短信登录 实现发送短信验证码功能短信功能同邮箱一样需要阿里云服务支持 UserController  PostMapping(code)public Result sendCode(RequestParam(phone) String phone, HttpSession session) throws MessagingException {// 发送短信验证码并保存验证码return userService.sendCode(phone, session);} 服务类IUserService  public interface IUserService extends IServiceUser {Result sendCode(String phone, HttpSession session); } 服务类的实现类 Service Slf4j public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Overridepublic Result sendCode(String phone, HttpSession session) {// 1.校验手机号if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合返回错误信息return Result.fail(手机号格式错误);}// 3.符合生成验证码String code RandomUtil.randomNumbers(6);// 4.保存验证码到sessionsession.setAttribute(code, code);// 5.发送验证码log.debug(发送短信验证码成功验证码{}, code);// 6.返回okreturn Result.ok();} } 正则表达式校验手机号格式工具类 public class RegexUtils {/ 是否是无效手机格式* param phone 要校验的手机号* return true:符合false不符合/public static boolean isPhoneInvalid(String phone){return mismatch(phone, RegexPatterns.PHONE_REGEX);}/** 是否是无效邮箱格式* param email 要校验的邮箱* return true:符合false不符合/public static boolean isEmailInvalid(String email){return mismatch(email, RegexPatterns.EMAIL_REGEX);}/** 是否是无效验证码格式* param code 要校验的验证码* return true:符合false不符合*/public static boolean isCodeInvalid(String code){return mismatch(code, RegexPatterns.VERIFY_CODE_REGEX);}// 校验是否不符合正则格式private static boolean mismatch(String str, String regex){if (StrUtil.isBlank(str)) {return true;}return !str.matches(regex);} } 实现登录功能 UserController PostMapping(/login)public Result login(RequestBody LoginFormDTO loginForm, HttpSession session){// 实现登录功能return userService.login(loginForm, session);} 服务类IUserService  public interface IUserService extends IServiceUser {Result login(LoginFormDTO loginForm, HttpSession session); } 服务类的实现类 Service Slf4j public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 1.校验手机号String phone loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合返回错误信息return Result.fail(手机号格式错误);}// 3.校验验证码Object cacheCode session.getAttribute(code);String code loginForm.getCode();if (cacheCode null || !cacheCode.toString().equals(code)) {// 4.不一致报错return Result.fail(验证码错误);}// 5.一致根据手机号查询用户 select * from tbuser where phone ?User user query().eq(phone, phone).one();// 6.判断用户是否存在if (user null) {// 7.不存在创建新用户并保存user createUserWithPhone(phone);}// 8.保存用户信息到sessionsession.setAttribute(user,user);return Result.ok();}private User createUserWithPhone(String phone) {// 1.创建用户User user new User();user.setPhone(phone);user.setNickName(user RandomUtil.randomString(10));// 2.保存用户save(user);return user;} }实现登录拦截功能(拦截器  utils包下的工具类-拦截器  /*** 拦截器/ public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {// 1.获取SessionHttpSession session request.getSession();// 2.获取Session中的用户Object user session.getAttribute(user);// 3.判断用户是否存在if (user null) {// 4.不存在拦截返回401状态码response.setStatus(401);return false;}// 5.存在保存用户信息到ThreadLocalUserHolder.saveUser((User) user);// 6.放行return true;}Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserHolder.removeUser();} }config包下的配置类 import com.hmdp.utils.LoginInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** MVC配置类用于自定义Spring MVC的配置。/ Configuration public class MvcConfig implements WebMvcConfigurer {/** 添加拦截器配置。** 本方法旨在注册一个登录拦截器并排除一些不需要拦截的路径。* 排除的路径通常是一些公共资源路径或者登录相关路径这些路径不需要用户登录即可访问。** param registry 拦截器注册表用于添加和配置拦截器。*/Overridepublic void addInterceptors(InterceptorRegistry registry) {// 添加登录拦截器registry.addInterceptor(new LoginInterceptor())// 排除不需要拦截的路径.excludePathPatterns(/shop/, // 商城相关路径/shop-type/, // 商城类型路径/upload/, // 上传路径/blog/hot, // 热门博客路径/user/code, // 用户验证码路径/user/login // 用户登录路径);} } utils包下的工具类-保存用户信息到ThreadLocal import com.hmdp.entity.User;public class UserHolder {private static final ThreadLocalUser tl new ThreadLocal();public static void saveUser(User userId){tl.set(userId);}public static User getUser(){return tl.get();}public static void removeUser(){tl.remove();} } UserController中的方法 GetMapping(/me)public Result me(){// TODO 获取当前登录的用户并返回User user UserHolder.getUser();return Result.ok(user);} 隐藏用户敏感信息 在点击”我的“ 时会发起一个GET请求查询用户信息但是返回来的结果包含了用户敏感信息。 现在需要在登录的 响应请求给前端的不包含隐私信息的UserDTO类  import lombok.Data;Data public class UserDTO {private Long id;private String nickName;private String icon; }UserController中响应的方法改成返回DTO GetMapping(/me)public Result me(){// 获取当前登录的用户并返回UserDTO user UserHolder.getUser();return Result.ok(user);} UserHolder改成DTO 该UserHolder类主要用于在多线程环境中保存和管理用户信息(UserDTO对象)。  public class UserHolder {private static final ThreadLocalUserDTO 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();} } 登录拦截的时候若存在则将DTO保存到线程而不是具有全部信息的user那样前端保存着太多信息会有很多负载。  public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {// 1.获取SessionHttpSession session request.getSession();// 2.获取Session中的用户Object user session.getAttribute(user);// 3.判断用户是否存在if (user null) {// 4.不存在拦截返回401状态码response.setStatus(401);return false;}// 5.存在保存用户信息到ThreadLocalUserHolder.saveUser((UserDTO) user);// 6.放行return true;}Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserHolder.removeUser();} } 修改8.保存用户信息到session 登录的时候保存到session的是userDTO若登录时创建用户信息保存到数据库的是user Service Slf4j public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 1.校验手机号String phone loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合返回错误信息return Result.fail(手机号格式错误);}// 3.校验验证码Object cacheCode session.getAttribute(code);String code loginForm.getCode();if (cacheCode null || !cacheCode.toString().equals(code)) {// 4.不一致报错return Result.fail(验证码错误);}// 5.一致根据手机号查询用户 select * from tbuser where phone ?User user query().eq(phone, phone).one();// 6.判断用户是否存在if (user null) {// 7.不存在创建新用户并保存user createUserWithPhone(phone);}// 8.保存用户信息到session// BeanUtil.copyProperties可以使得省略给DTO一个一个赋值session.setAttribute(user, BeanUtil.copyProperties(user, UserDTO.class));return Result.ok();}private User createUserWithPhone(String phone) {// 1.创建用户User user new User();user.setPhone(phone);user.setNickName(user RandomUtil.randomString(10));// 2.保存用户save(user);return user;} }集群的Session共享问题 当请求nginx时会负载均衡到tomcat集群中的一台但是在不同的tomcat中其session中的内容不共享。 但是每一台都存储同样的session信息会造成资源浪费负载大。 因此使用redis解决1、redis集群是数据共享的主从复制2、redis内容存储读写分离3、redis的key-value结构刚好可以存储session信息。 基于redis实现共享session登录  redis存储信息的两种方式 UserServiceImpl实现类  Resourceprivate StringRedisTemplate stringRedisTemplate;Overridepublic Result sendCode(String phone, HttpSession session) {// 1.校验手机号if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合返回错误信息return Result.fail(手机号格式错误);}// 3.符合生成验证码String code RandomUtil.randomNumbers(6);// 4.保存验证码到redis 有效期2分钟以避免redis一直存验证码不删除stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);// 5.发送验证码log.debug(发送短信验证码成功验证码{}, code);// 6.返回okreturn Result.ok();}Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {// 1.校验手机号String phone loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合返回错误信息return Result.fail(手机号格式错误);}// 3.从redis获取验证码并校验String cacheCode stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY phone);// 获取用户填写的验证码String code loginForm.getCode();if (cacheCode null || !cacheCode.equals(code)) {// 4.不一致报错return Result.fail(验证码错误);}// 5.一致根据手机号查询用户 select * from tb_user where phone ?User user query().eq(phone, phone).one();// 6.判断用户是否存在if (user null) {// 7.不存在创建新用户并保存user createUserWithPhone(phone);} // // 8.保存用户信息到session // // BeanUtil.copyProperties可以使得省略给DTO一个一个赋值 // session.setAttribute(user, BeanUtil.copyProperties(user, UserDTO.class));// 8.保存用户信息到redis// 1、随机生成token作为登录令牌String token UUID.randomUUID().toString(true);// 2、将User对象转为HashMap存储// 3、存储到redis中UserDTO userDTO BeanUtil.copyProperties(user, UserDTO.class);// redis要求key 和 value 都是String类型所以需要设置一个编辑器 DTO中的属性不全是String类型MapString, Object userMap BeanUtil.beanToMap(userDTO, new HashMap(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) - fieldValue.toString()));String tokenKey LOGIN_USER_KEY token;stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);// 设置token为keyuserDTO为value设置有效期stringRedisTemplate.expire(user: token, LOGIN_USER_TTL, TimeUnit.MINUTES);// 9.返回tokenreturn Result.ok(token);} MvcConfig Configuration public class MvcConfig implements WebMvcConfigurer {Resourceprivate StringRedisTemplate stringRedisTemplate;/* 添加拦截器配置。** 本方法旨在注册一个登录拦截器并排除一些不需要拦截的路径。* 排除的路径通常是一些公共资源路径或者登录相关路径这些路径不需要用户登录即可访问。** param registry 拦截器注册表用于添加和配置拦截器。*/Overridepublic void addInterceptors(InterceptorRegistry registry) {// 添加登录拦截器registry.addInterceptor(new LoginInterceptor(stringRedisTemplate))// 排除不需要拦截的路径.excludePathPatterns(/shop/, // 商城相关路径/shop-type/, // 商城类型路径/upload/**, // 上传路径/blog/hot, // 热门博客路径/user/code, // 用户验证码路径/user/login // 用户登录路径);} } 拦截器  public class LoginInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public LoginInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate stringRedisTemplate;}Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception { // // 1.获取Session // HttpSession session request.getSession();// 1.获取请求头中的tokenString token request.getHeader(authorization);if(StrUtil.isBlank(token)){// 不存在拦截返回401状态码response.setStatus(401);return false;}// // 2.获取Session中的用户 // Object user session.getAttribute(user);// 2.基于token从redis中获取用户MapObject, Object userMap stringRedisTemplate.opsForHash().entries(RedisConstants.LOGIN_USER_KEY token);// 3.判断用户是否存在if (userMap.isEmpty()) {// 4.不存在拦截返回401状态码response.setStatus(401);return false;}// 5.将查询到的Map用户数据转为UserDTOUserDTO userDTO BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6.存在保存用户到ThreadLocalUserHolder.saveUser(userDTO);// 7.刷新token有效期stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY token, RedisConstants.LOGIN_USER_TTL, java.util.concurrent.TimeUnit.MINUTES);return true;}Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserHolder.removeUser();} }