springboot整合项目-拦截器HandlerInterceptor

拦截器

在Spring MVC中拦截请求是通过处理器拦截器HandlerInterceptor来实现的,它拦截的目标是请求的地址。在Spring MVC中定义一个拦截器,需要实现HandlerInterceptor接口。

1 HandlerInterceptor

1.1 preHandle()方法

该方法将在请求处理之前被调用。SpringMVC中的Interceptor是链式的调用,在一个应用或一个请求中可以同时存在多个Interceptor。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle()方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值类型,当返回false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值true时,就会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时,就会调用当前请求的Controller方法。

1.2 postHandle()方法

该方法将在当前请求进行处理之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle是相反的,也就是说先声明的Interceptor的postHandle方法反而会后执行。如果当前Interceptor的preHandle()方法返回值为false,则此方法不会被调用。

1.3 afterCompletion()方法

该方法将在整个当前请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作。如果当前Interceptor的preHandle()方法返回值为false,则此方法不会被调用。

2 WebMvcConfigurer

在SpringBoot项目中,如果想要自定义一些Interceptor、ViewResolver、MessageConverter,该如何实现呢?在SpringBoot 1.5版本都是靠重写WebMvcConfigurerAdapter类中的方法来添加自定义拦截器、视图解析器、消息转换器等。而在SpringBoot 2.0版本之后,该类被标记为@Deprecated。因此我们只能靠实现WebMvcConfigurer接口来实现。

WebMvcConfigurer接口中的核心方法之一addInterceptors(InterceptorRegistry registry)方法表示添加拦截器。主要用于进行用户登录状态的拦截,日志的拦截等。

  • addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例

  • addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns("/**")对所有请求都拦截

  • excludePathPatterns:用于设置不需要拦截的过滤规则

public interface WebMvcConfigurer {
    // ...
    default void addInterceptors(InterceptorRegistry registry) {
   	}
}

3 项目添加拦截器功能

1.分析:项目中很多操作都是需要先登录才可以执行的,如果在每个请求处理之前都编写代码检查Session中有没有登录信息,是不现实的。所以应使用拦截器解决该问题。

2.创建拦截器类com.cy.store.interceptor.LoginInterceptor,并实现org.springframework.web.servlet.HandlerInterceptor接口。

package com.cy.store.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/** 定义处理器拦截器 */
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (request.getSession().getAttribute("uid") == null) {
            response.sendRedirect("/web/login.html");
            return false;
        }
        return true;
    }
}

3.创建LoginInterceptorConfigurer拦截器的配置类并实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口,配置类需要添加@Configruation注解修饰。

package com.cy.store.config;
import com.cy.store.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;

/** 注册处理器拦截器 */
@Configuration
public class LoginInterceptorConfigurer implements WebMvcConfigurer {
    /** 拦截器配置 */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 创建拦截器对象
        HandlerInterceptor interceptor = new LoginInterceptor();

        // 白名单
        List<String> patterns = new ArrayList<String>();
        patterns.add("/bootstrap3/**");
        patterns.add("/css/**");
        patterns.add("/images/**");
        patterns.add("/js/**");
        patterns.add("/web/register.html");
        patterns.add("/web/login.html");
        patterns.add("/web/index.html");
        patterns.add("/web/product.html");
        patterns.add("/users/reg");
        patterns.add("/users/login");
        patterns.add("/districts/**");
        patterns.add("/products/**");

        // 通过注册工具添加拦截器
        registry.addInterceptor(interceptor).addPathPatterns("/**").excludePathPatterns(patterns);
    }
}

会话

1.重新构建login()方法,登录成功后将uid和username存入到HttpSession对象中。

@RequestMapping("login")
public JsonResult<User> login(String username, String password, HttpSession session) {
    // 调用业务对象的方法执行登录,并获取返回值
    User data = userService.login(username, password);

    //登录成功后,将uid和username存入到HttpSession中
    session.setAttribute("uid", data.getUid());
    session.setAttribute("username", data.getUsername());
    // System.out.println("Session中的uid=" + getUidFromSession(session));
    // System.out.println("Session中的username=" + getUsernameFromSession(session));

    // 将以上返回值和状态码OK封装到响应结果中并返回
    return new JsonResult<User>(OK, data);
}

2.在父类BaseController中添加从HttpSession对象中获取uid和username的方法,以便于后续快捷的获取这两个属性的值。

/**
 * 从HttpSession对象中获取uid
 * @param session HttpSession对象
 * @return 当前登录的用户的id
 */
protected final Integer getUidFromSession(HttpSession session) {
	return Integer.valueOf(session.getAttribute("uid").toString());
}

/**
 * 从HttpSession对象中获取用户名
 * @param session HttpSession对象
 * @return 当前登录的用户名
 */
protected final String getUsernameFromSession(HttpSession session) {
	return session.getAttribute("username").toString();
}
posted @ 2022-11-03 15:49  wiselee/  阅读(275)  评论(0编辑  收藏  举报