拦截器使用
1.定义拦截器,实现HandlerInterceptor接口
2.配置拦截器,为它指定拦截、排除的路径
拦截器应用
1.在请求开始时查询登录用户
2.在本次请求中持有用户数据
3.在模板视图上显示用户数据
4.在请求结束时清理用户数据
定义拦截器LoginTicketInterceptor
@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工具类,遍历cookie[],获取相应的value String ticket = CookieUtil.getValue(request, "ticket"); if (ticket != null) { //查询凭证 LoginTicket loginTicket = userService.selectTicket(ticket); if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) { //根据凭证查询用户 User user = userService.findUserById(loginTicket.getUserId()); //在本次请求中持有用户,多线程状态下ThreadLocal每个用户单独持有一个线程 hostHolder.setUsers(user); //构建用户认证的结果,并存入SecurityContext,便于Security进行授权 Authentication authentication = new UsernamePasswordAuthenticationToken( user, user.getPassword(), userService.getAuthorities(user.getId())); SecurityContextHolder.setContext(new SecurityContextImpl(authentication)); } } return true; } //在模板之前调用 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable 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, @Nullable Exception ex) throws Exception { hostHolder.clear(); SecurityContextHolder.clearContext(); } }
HostHolder
@Component public class HostHolder { private ThreadLocal<User> users = new ThreadLocal<>(); public void setUsers(User user) { users.set(user); } public User getUser() { return users.get(); } public void clear(){ users.remove(); } }
在config中配置Interceptor
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private LoginTicketInterceptor loginTicketInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginTicketInterceptor) .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg"); } }
前台页面需要加入判断th:if="${loginUser!=null}",当用户没登陆的时候显示“登录”,登陆后隐藏按钮,并显示用户相关信息
<ul class="navbar-nav mr-auto"> <li class="nav-item ml-3 btn-group-vertical"> <a class="nav-link" th:href="@{/index}">首页</a> </li> <li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser!=null}"> <a class="nav-link position-relative" th:href="@{/letter/list}">消息<span class="badge badge-danger" th:text="${allUnreadCount!=0?allUnreadCount:''}">12</span></a> </li> <li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser==null}"> <a class="nav-link" th:href="@{/register}">注册</a> </li> <li class="nav-item ml-3 btn-group-vertical" th:if="${loginUser==null}"> <a class="nav-link" th:href="@{/login}">登录</a> </li> <li class="nav-item ml-3 btn-group-vertical dropdown" th:if="${loginUser!=null}"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <img th:src="${loginUser.headerUrl}" class="rounded-circle" style="width:30px;"/> </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item text-center" th:href="@{|/user/profile/${loginUser.id}|}">个人主页</a> <a class="dropdown-item text-center" th:href="@{/user/setting}">账号设置</a> <a class="dropdown-item text-center" th:href="@{/logout}">退出登录</a> <div class="dropdown-divider"></div> <span class="dropdown-item text-center text-secondary" th:utext="${loginUser.username}">nowcoder</span> </div> </li> </ul>
显示状态
未登录
登陆后