在上一篇博客中,实现了登录、登录凭证模块的开发,今天,通过昨天session中的登录凭证,是的其他请求可以持有用户信息。主要利用拦截器以及ThreadLocal。
重写拦截器的三个方法preHandle、postHandle、afterCompletion。分别实现获取用户信息,并保存到ThreadLocal中、向ModelAndView 中传入用户信息、以及清空ThreadLocal中用户的功能。通过HostHolder工具类封装起ThreadLocal的相应操作。
1 package com.nowcoder.community.controller.interceptor; 2 3 import com.nowcoder.community.entity.LoginTicket; 4 import com.nowcoder.community.entity.User; 5 import com.nowcoder.community.service.UserService; 6 import com.nowcoder.community.util.CookieUtil; 7 import com.nowcoder.community.util.HostHolder; 8 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.stereotype.Component; 10 import org.springframework.web.servlet.HandlerInterceptor; 11 import org.springframework.web.servlet.ModelAndView; 12 13 import javax.servlet.http.HttpServletRequest; 14 import javax.servlet.http.HttpServletResponse; 15 import java.util.Date; 16 17 @Component 18 public class LoginTicketInterceptor implements HandlerInterceptor { 19 20 @Autowired 21 private UserService userService; 22 23 @Autowired 24 private HostHolder hostHolder; 25 26 @Override 27 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 28 // 从cookie中获取凭证 29 String ticket = CookieUtil.getValue(request, "ticket"); 30 31 if (ticket != null) { 32 // 查询凭证 33 LoginTicket loginTicket = userService.findLoginTicket(ticket); 34 // 检查凭证是否有效 35 if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) { 36 // 根据凭证查询用户 37 User user = userService.findUserById(loginTicket.getUserId()); 38 // 在本次请求中持有用户 39 hostHolder.setUser(user); 40 } 41 } 42 43 return true; 44 } 45 46 @Override 47 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 48 User user = hostHolder.getUser(); 49 if (user != null && modelAndView != null) { 50 modelAndView.addObject("loginUser", user); 51 } 52 } 53 54 @Override 55 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 56 hostHolder.clear(); 57 } 58 }
package com.nowcoder.community.util;
import com.nowcoder.community.entity.User;
import org.springframework.stereotype.Component;
/**
* 持有用户信息,用于代替session对象.
*/
@Component
public class HostHolder {
private ThreadLocal<User> users = new ThreadLocal<>();
public void setUser(User user) {
users.set(user);
}
public User getUser() {
return users.get();
}
public void clear() {
users.remove();
}
}
此外,写了一个注解。通过拦截器对方法判断是否有@LoginRequired注解,若有改注解则需要先登录。
注解声明很简单,只需通过元注解标明注解作用的目标和注解的保留位置。
package com.nowcoder.community.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LoginRequired { }
再写一个拦截器检验是否有@LoginRequired注解
1 package com.nowcoder.community.controller.interceptor; 2 3 import com.nowcoder.community.annotation.LoginRequired; 4 import com.nowcoder.community.util.HostHolder; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.stereotype.Component; 7 import org.springframework.web.method.HandlerMethod; 8 import org.springframework.web.servlet.HandlerInterceptor; 9 10 import javax.servlet.http.HttpServletRequest; 11 import javax.servlet.http.HttpServletResponse; 12 import java.lang.reflect.Method; 13 14 @Component 15 public class LoginRequiredInterceptor implements HandlerInterceptor { 16 17 @Autowired 18 private HostHolder hostHolder; 19 20 @Override 21 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 22 if (handler instanceof HandlerMethod) { 23 HandlerMethod handlerMethod = (HandlerMethod) handler; 24 Method method = handlerMethod.getMethod(); 25 LoginRequired loginRequired = method.getAnnotation(LoginRequired.class); 26 if (loginRequired != null && hostHolder.getUser() == null) { 27 response.sendRedirect(request.getContextPath() + "/login"); 28 return false; 29 } 30 } 31 return true; 32 } 33 }
拦截器配置类代码如下
package com.nowcoder.community.config; import com.nowcoder.community.controller.interceptor.AlphaInterceptor; import com.nowcoder.community.controller.interceptor.LoginRequiredInterceptor; import com.nowcoder.community.controller.interceptor.LoginTicketInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private LoginTicketInterceptor loginTicketInterceptor; @Autowired private LoginRequiredInterceptor loginRequiredInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginTicketInterceptor) .excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg"); registry.addInterceptor(loginRequiredInterceptor) .excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg"); } }