2.6 显示登录信息

164 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

显示登录信息

image-20220712091339538

显示登录信息的意思是在头部把登录用户的头像显示出来,另外点开头像旁边的**“倒三角”,要显示登录用户的名字,还有,根据用户登录与否我们还要调整头部显示的内容,比如“登录”“注册”**。

拦截器可以拦截浏览器的请求,它可以在请求的开始或结束插入一些代码,从而可以解决多个请求共有的业务

关于拦截器详细内容这里不过多赘述,更详细内容可以看我之前的博客:SpringBoot中文件下载、拦截器、war包部署、jar包部署

拦截器的简单使用(只是测试,不涉及项目内容)

@Component
public class AlphaInterceptor implements HandlerInterceptor {

    private static 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());
    }

    // 在模板引擎之后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.debug("afterCompletion: " + handler.toString());
    }
}

image-20220712102845535

拦截器的配置类

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AlphaInterceptor alphaInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(alphaInterceptor)       // 将需要配置的拦截器传给它
                //  /** 表示static目录下所有的文件夹,排除哪些路径不需要拦截
                .excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg")
                // 明确拦截注册、登录请求
                .addPathPatterns("/register", "/login");

    }
}

image-20220712102947799

之后启动项目访问登录注册页面查看控制台是否输出拦截器内的日志即可查看测试是否成功。

用拦截器处理在页面上显示用户的登录状态

image-20220712104026516

登录成功的话上面凭证查询然后在模板上显示每次请求都要干的,因为每次请求模板上都要显示用户信息,因此这套逻辑应该用拦截器处理,而不是写多次。

cookie是从request传过来的,从request我们可以得到cookie,从request取cookie有点麻烦,我们把它封装一下,方便以后复用。

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;
    }
}

image-20220712171916990

首先因为UserService里面没有查询凭证的方法,所以我们在UserService后面追加查询凭证的方法

public LoginTicket findLoginTicket(String ticket){
    return  loginTicketMapper.selectByTicket(ticket);
}

image-20220712172028909

在拦截其中我们本次请求中持有用户,因为浏览器对服务器是多对一,所以这里我们要考虑在多线程间隔离存这个对象, 需要用到threadLocal,这里我们封装成小工具,方便以后复用

/**
 * 持有用户信息,用于代替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();
    }

}

image-20220712172135212

拦截器

@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);
            // 检查凭证是否有效,1. 凭证存在   2. 凭证状态为0   3. 凭证超时时间晚于当前时间
            if(loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())){
                // 根据凭证查询用户
                User user = userService.findUserById(loginTicket.getUserId());
                // 在本次请求中持有用户
                // 因为浏览器对服务器是多对一,所以这里我们要考虑在多线程间隔离存这个对象,
                // 需要用到threadLocal,这里我们封装成小工具,方便以后复用
                hostHolder.setUser(user);
            }
        }
        return true;
    }

    // 我们之前preHandle存的user应该在模板引擎之中用,所以我们在拦截器的postHandle方法中将user存到model里
    @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();
    }
}

image-20220712172321270

image-20220712172434371

拦截器写完了,接下来我们对拦截器进行一个配置

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AlphaInterceptor alphaInterceptor;

    @Autowired
    private LoginTicketInterceptor loginTicketInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(alphaInterceptor)       // 将需要配置的拦截器传给它
                //  /** 表示static目录下所有的文件夹,排除哪些路径不需要拦截
                .excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg")
                // 明确拦截注册、登录请求
                .addPathPatterns("/register", "/login");

        registry.addInterceptor(loginTicketInterceptor)       // 将需要配置的拦截器传给它
                //  /** 表示static目录下所有的文件夹,排除哪些路径不需要拦截
                .excludePathPatterns("/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg");
                // 注:没有写addPathPatterns表示没有明确拦截哪个路径,那就是拦截所有
    }


}

image-20220712172554074

然后我们需要在模板上进行一个处理,因为所有的页面都是复用 index.html的header,所以我们需要去改写index.html的header部分

image-20220712171749946

测试:

image-20220712172630689

image-20220712172652848