拦截器、过滤器

拦截器

配置拦截器

  • 配置springmvc.xml
    <!--配置拦截器-->
    <mvc:interceptors>
         <!--多个拦截器顺序执行-->
        <mvc:interceptor>
            <!--拦截规则-->
            <mvc:mapping path="/user/*"/>
            <!--拦截器类-->
            <bean id="MyInterceptor" class="com.hd.interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

注解方式

  • addPathPatterns 用于添加拦截规则
  • excludePathPatterns 用户排除拦截
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
    /**
     * 拦截器上注入Bean
     * @return
     */
    @Bean
    MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
              // 多个拦截器组成一个拦截器链
           registry.addInterceptor(myInterceptor()).addPathPatterns("/**").excludePathPatterns("/article/**").
excludePathPatterns("/articles/**").excludePathPatterns("/register.html").excludePathPatterns("/login.html").excludePathPatterns("/user/**").excludePathPatterns("/error/**").excludePathPatterns("/findOne");

        super.addInterceptors(registry);
    }
}

创建拦截器类

  • 继承org.springframework.web.servlet.HandlerInterceptor
  • 其他拦截器接口org.springframework.web.context.request.WebRequestInterceptor,区别HandlerInterceptor接口preHandle无返回值,不能终止请求
  • 方法执行顺序:
    • preHandle:执行handle方法之前调用,多个拦截器会顺序执行多个preHandle方法,其中某个拦截器preHandle方法返回false都终止请求
    • postHandle:执行handle方法之后,返回ModelAndView之前执行(可修改视图),多个拦截器会逆序执行多个postHandle方法
    • afterCompletion:执行完handle方法之后,视图渲染之后执行,多个拦截器会逆序执行多个afterCompletion方法
  • postHandle方法的ModelAndView参数可以修改视图,如改变ctntroller发往视图的参数
public class MyInterceptor implements HandlerInterceptor {
    /**
     *
     * @param httpServletRequest 请求
     * @param httpServletResponse 响应
     * @param object 当前拦截器对象
     * @return 是否将当前请求拦截下来,true将拦截处理并进入下一步骤,false请求将被终止
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        System.out.println("preHandle...");
        return true;
    }

    /**
     *
     * @param httpServletRequest 请求
     * @param httpServletResponse 响应
     * @param object 当前拦截器对象
     * @param modelAndView 模型视图对象,用于修改视图
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("afterCompletion...");
    }
}

使用拦截器实现中文编码设置

    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        httpServletRequest.setCharacterEncoding("utf-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        return true;
    }

多个拦截器执行顺序

  • 所有拦截器链的preHandle方法返回true才会执行postHandle、afterCompletion
  • 多个拦截器的preHandle()方法顺序执行,postHandle、afterCompletion逆序执行
  • 可通过重写拦截器方法改变顺序

基于拦截器的用户登陆

  1. 创建拦截器类
  • 获取session中用户数据,session中没有用户说明未登录,跳转登陆页面
  • 实现自动登陆:获取Cookie中用户token,通过token获取用户数据,并保存在session中
public class MyInterceptor implements HandlerInterceptor {
    @Autowired
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        Object userBysession = httpServletRequest.getSession().getAttribute("user");
        if (userBysession == null){
            // 未登录,根据token获取用户
            String loginToken = CookieUtil.findCookieByName(httpServletRequest, "vmds_login_token");
            if (StringUtils.isNotBlank(loginToken)){
                // 获取用户
                User user = userService.getUserByToken(loginToken);
                if (user != null){
                    // 保存用户到session
                    httpServletRequest.getSession().setAttribute("user", user);
                    return true;
                } else {
                    // 用户未找到,清除cookie
                    CookieUtil.clearCookie(httpServletRequest,httpServletResponse,"vmds_login_token");
                    httpServletResponse.sendRedirect("/login.html");
                    return false;
                }
            }
            else {
                // 没有cookie,跳转登录页面
                httpServletResponse.sendRedirect("/login.html");
                return false;
            }
        }
        else {
            // 已登陆
            return  true;
        }
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}
  1. 配置
    <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--拦截规则-->
            <mvc:mapping path="/user/*"/>
            <!--拦截器类-->
            <bean id="MyInterceptor" class="com.hd.interceptor.MyInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  1. Controller
  • 保存登陆成功的用户信息到session
  • 更新用户token,写入Cookie
    @RequestMapping(value = "/userlogin", method = RequestMethod.POST)
    @ResponseBody
    public String login(@RequestParam(value = "username") String name, @RequestParam(value = "password") String password, HttpSession session,HttpServletRequest request, HttpServletResponse response) {
        PageData pageData = new PageData(request);
        User user = userService.getUserByLogin(pageData);
        if (null == user) {
            // 用户未找到
            return "error";
        }

        // 添加cookie token
        Long mi = System.currentTimeMillis();
        CookieUtil.addCookie(response, "vmds_login_token", mi.toString(), 60 * 60 * 24 * 7);

        // 更新用户token
        user.setToken(mi.toString());
        userService.saveUser(user);

        session.setAttribute("user", user);
        return "200";
    }

过滤器

Filter(过滤器)是实现了Filter接口的java类,由 Servlet 容器进行调用和执行的,它可以决定是否将请求继续传递给 Servlet 程序,以及对请求和响应消息是否进行修改

配置过滤器

中文过滤器:解决前端传递的中文字符乱码问题

web.xml

  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <!--springmvc提供的字符编码过滤器类-->
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

注解方式

  • @WebFilter:过滤器注解
  • FilterConfig:Filter 配置对象,包含初始化参数、Filter name等
  • init(): Web 容器创建 Filter 的实例对象后,将立即调用该 Filter 对象的 init 方法。init 方法在 Filter 生命周期中仅被执行一次
  • doFilter():doFilter 方法来激活目标 Servlet 的 service 方法
  • destroy():该方法在 Web 容器卸载 Filter 对象之前被调用,也仅执行一次
@WebFilter(
        urlPatterns = "/articles/*",
        initParams = {@WebInitParam(name = "val1", value = "t1"), @WebInitParam(name = "val", value = "t2")})
public class TestFilter implements Filter{

    /**
     * 初始化,web 应用程序启动时实例化所有 Filter,实例化时执行init方法
     * @param filterConfig Filter 配置对象
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("TestFilter init");
        // 初始化参数
        String filterName = filterConfig.getFilterName();
        Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
        System.out.println("filterName = " + filterName);
        while (initParameterNames.hasMoreElements()) {
            String s = initParameterNames.nextElement();
            System.out.println(s + " = " + filterConfig.getInitParameter(s));
        }
    }

    /**
     * 当一个 Filter 对象能够拦截访问请求时,Servlet 容器将调用 Filter 对象的 doFilter 方法
     * @param request
     * @param response
     * @param chain  当前 Filter 链的对象
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 目标Servlet service 方法之前
        chain.doFilter(request, response); // doFilter 方法来激活目标 Servlet 的 service 方法
        // 目标Servlet service 方法之后
    }

    @Override
    public void destroy() {
        System.out.println("TestFilter destroy");
    }
}

拦截器、过滤器区别

  1. 过滤器Filter依赖于servlet,基于回掉函数,范围更大(可过滤一些资源)
  2. 拦截器Interceptor依赖于框架容器,基于反射机制,只能过滤url请求
posted @ 2020-11-12 22:30  熊云港  阅读(109)  评论(0编辑  收藏  举报