在上一篇博客中,實現了登錄、登錄憑證模塊的開發,今天,通過昨天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"); } }