package com.now.community.community.controller.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class AlphaInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AlphaInterceptor.class);
// 在Controller之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.debug("preHandle: " + handler.toString());
return true;
}
// 在Controller之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.debug("postHandle: " + handler.toString());
}
// 在TemplateEngine之后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.debug("afterCompletion: " + handler.toString());
}
}
配置:
package com.now.community.community.config;
import com.now.community.community.controller.interceptor.*;
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 AlphaInterceptor alphaInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(alphaInterceptor)
.excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.woff", "/**/*.svg")
.addPathPatterns("/register", "/login");
}
}
访问register或者login时,拦截到了请求。
为什么不把用户信息保存在session 里,而是ThreadLocal里?
在分布式的环境下,使用session存在共享数据的问题。通常的解决方案,是将共享数据存入数据库,所有的应用服务器都去数据库获取共享数据。对于每一次请求,开始时从数据库里取到数据,然后将其临时存放在本地的内存里,考虑到线程之间的隔离,所以用threadlocal,这样在本次请求的过程中,就可以随时获取到这份共享数据了。所以,session的替代方案是数据库,ThreadLocal只是打了个辅助。
为什么不直接把user信息直接放在request里面?
request对象就是本次请求,我们可以在请求结束前的任意时刻,从request对象里获取与本次请求有关的数据。
实际上,确实可以通过request来持有用户数据的。但是从设计上、代码分层上来说,这样不好。
在Spring MVC框架中,request是一个比较底层的数据对象,一般我们不直接使用它。
而且并不是任意的位置都方便获取request对象,因为它不被容器管理,不是随便就能注入给一个Bean的。因为不鼓励这样做,requerst是表现层的对象,要是随便注入,你很可能会将其注入给service,从而产生耦合。所以,我们自己写一个组件,单独解决这个问题。原则上可以,但事实上不会,这是从代码合理性角度考量的。
我们封装一下:
package com.now.community.community.util;
import com.now.community.community.entity.User;
import org.springframework.stereotype.Component;
/**
* 持有用户信息,用于代替session对象.
*/
@Component
public class HostHolder {
private ThreadLocal users = new ThreadLocal<>();
public void setUser(User user) {
users.set(user);
}
public User getUser() {
return users.get();
}
public void clear() {
users.remove();
}
}
取cookie封装:
package com.now.community.community.util;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
public class CookieUtil {
public static String getValue(HttpServletRequest request, String name) {
if (request == null || name == null) {
throw new IllegalArgumentException("参数为空!");
}
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
return cookie.getValue();
}
}
}
return null;
}
}
拦截器:
查用户放入hostholder
controller执行
查hostholder里的user
放入modelAndView
模板用数据显示界面
清除
package com.now.community.community.controller.interceptor;
import com.now.community.community.entity.LoginTicket;
import com.now.community.community.entity.User;
import com.now.community.community.service.UserService;
import com.now.community.community.util.CookieUtil;
import com.now.community.community.util.HostHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
@Component
public class LoginTicketInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Autowired
private HostHolder hostHolder;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//从cookie获取凭证
String ticket= CookieUtil.getValue(request,"ticket");
if (ticket != null){
// 查询凭证
LoginTicket loginTicket = userService.findLoginTicket(ticket);
// 检查凭证是否有效
if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) {
// 根据凭证查询用户
User user = userService.findUserById(loginTicket.getUserId());
// 在本次请求中持有用户
hostHolder.setUser(user);
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
User user = hostHolder.getUser();
if (user != null && modelAndView != null) {
modelAndView.addObject("loginUser", user);
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
hostHolder.clear();
}
}