Filter和Interceptor

过滤器(注解)

1.定义过滤器TestFilter001 ,实现Filter,重写init(初始化),doFilter(过滤),destroy(销毁)方法。
这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。
 1.@WebFilter注解,filterName属性表示filter的名称,urlPatter表示要拦截的URL资源,可以是一个或者多个。

2.@Order(1)表示如果有多个拦截器的话就是设置这个拦截器的运行等级,数字越小,越先执行

3.init()方法只会执行一次,初始化过滤器。

4.doFilter()核心方法,配置过滤器的逻辑代码。

5.destroy()只会在项目停止或者是项目重新部署的时候才会执行。

配置完上面的之后我们还需要在启动类加上一个扫描包的注解,开启包扫描。@ServletComponentScan(“com.example.demofilter.filter”),当然你也可以不用写包的具体地址,不传参数,但是建议是传参数,并且这个采参数也可以传多个的。

import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@Order(1)
@WebFilter(filterName = "myFilter1", urlPatterns = {"/*"})
public class TestFilter001 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化过滤器");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("进入目标资源之前先干点啥");
//        filterChain.doFilter(servletRequest, servletResponse);
		long start = System.currentTimeMillis();
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Execute cost="+(System.currentTimeMillis()-start));
        System.out.println("处理一下服务端返回的response");
    }

    @Override
    public void destroy() {
        System.out.println("过滤器被销毁了");
    }
}

2.配置
这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包。
在这里插入图片描述

过滤器(非注解)

1.  现在我们通过过滤器来实现记录请求执行时间的功能,其实现如下:

 public class LogCostFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        long start = System.currentTimeMillis();
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("Execute cost="+(System.currentTimeMillis()-start));
    }
 
    @Override
    public void destroy() {
 
    }
}

2.  方法执行前先记录时间戳,然后通过过滤器链完成请求的执行,在返回结果之间计算执行的时间。这里需要主要,这个类必须继承Filter类,这个是Servlet的规范,这个跟以前的Web项目没区别。但是,有了过滤器类以后,以前的web项目可以在web.xml中进行配置,但是spring boot项目并没有web.xml这个文件, 在Spring boot中,我们需要FilterRegistrationBean来完成配置。其实现过程如下:
通过自己定义一个java配置文件,将自定义的Filter 注册到到FilterRegistrationBean里面。

@Configuration
public class FilterConfig {
 
    @Bean
    public FilterRegistrationBean registFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new LogCostFilter());
        registration.addUrlPatterns("/*");
        registration.setName("LogCostFilter");
        registration.setOrder(1);
        return registration;
    }
 
}

这样配置就完成了,需要配置的选项主要包括实例化Filter类,然后指定url的匹配模式,设置过滤器名称和执行顺序,这个过程和在web.xml中配置其实没什么区别,只是形式不同而已。现在我们可以启动服务器访问任意URL。

拦截器

1.实现拦截器类
  这里我们需要实现HandlerInterceptor这个接口,这个接口包括三个方法,preHandle是请求执行前执行的,postHandler是请求结束执行的,但只有preHandle方法返回true的时候才会执行,afterCompletion是视图渲染完成后才执行,同样需要preHandle返回true,该方法通常用于清理资源等工作

public class TestInterceptor implements HandlerInterceptor {
    private static  ThreadLocal<Long> e = new ThreadLocal<>();
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        e.set(System.currentTimeMillis());
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor cost=" + (System.currentTimeMillis() - e.get()));
    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}

2.配置拦截器
这里我们继承了WebMVCConfigurerAdapter,看过前面的文章的朋友应该已经见过这个类了,在进行静态资源目录配置的时候我们用到过这个类。这里我们重写了addInterceptors这个方法,进行拦截器的配置,主要配置项就两个,一个是指定拦截器,第二个是指定拦截的URL

@Configuration
public class TestInterceptorConfig  extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}

总结:
在分析两者的区别之前,我们先理解一下AOP的概念,AOP不是一种具体的技术,而是一种编程思想。在面向对象编程的过程中,我们很容易通过继承、多态来解决纵向扩展。 但是对于横向的功能,比如,在所有的service方法中开启事务,或者统一记录日志等功能,面向对象的是无法解决的。所以AOP——面向切面编程其实是面向对象编程思想的一个补充。而我们今天讲的过滤器和拦截器都属于面向切面编程的具体实现。而两者的主要区别包括以下几个方面:

1、Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。

2、Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理的方式来执行。

3、Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。
  无论是过滤器还是拦截器都属于AOP(面向切面编程)思想的具体实现。除了这两种实现我们还见过另一种更灵活的AOP实现技术,即Aspect,我们可以通过Aspect来完成更多更强大的功能。

++

 

/**
 * xss攻击过滤器 
 */
@Slf4j
@Component
@WebFilter(urlPatterns = "/*", filterName = "XSSCheck", initParams = { @WebInitParam(name = "securityconfig", value = "/*") })
@ConditionalOnProperty(value = "hysoft.filter.xss.enable", havingValue = "true", matchIfMissing = false)
public class XssFilter implements SafeFilter {
    private FilterConfig config;
    private static String errorPath;
    private static String[] excludePaths;
    private static String[] safeless;

    public final static String XSS_ERROR_PATH = "/templates/common/error.ftl";
    public final static String XSS_EXCLUDE_PATHS = "";
    public final static String XSS_SAFELESS = "<script, </script, <iframe, </iframe, <frame, </frame, set-cookie, %3cscript, %3c/script, %3ciframe, %3c/iframe, %3cframe, %3c/frame, src=\"javascript:, <body, </body, %3cbody, %3c/body, <, >, </, />, %3c, %3e, %3c/, /%3e";

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.config = config;
        try {
            errorPath = XSS_ERROR_PATH;
            String excludePath = XSS_EXCLUDE_PATHS;
            if (!"".equals(excludePath) && null != excludePath){
                excludePaths = excludePath.split(",");
            }
            String safeles = XSS_SAFELESS;
            if (!"".equals(safeles) && null != safeles) {
                safeless = safeles.split(",");
                log.debug(safeless.toString());
            }
        } catch (Exception e) {
            log.error("XSS初始化失败",e);
        }
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
        Enumeration params = req.getParameterNames();
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        boolean isSafe = true;
        String requestUrl = request.getRequestURI();
        if (isSafe(requestUrl)) {
            requestUrl = requestUrl.substring(requestUrl.indexOf("/"));
            if (!excludeUrl(requestUrl)) {
                String cache = "";
                while (params.hasMoreElements()) {
                    cache = req.getParameter((String) params.nextElement());
                    if (!"".equals(cache) && null != cache) {
                        if (!isSafe(cache)) {
                            isSafe = false;
                            break;
                        }
                    }
                }
            }
        } else {
            isSafe = false;
        }
        if (!isSafe) {
            log.error("您输入的参数有非法字符,请输入正确的参数!");
            request.setAttribute("err", "您输入的参数有非法字符,请输入正确的参数!");
            request.setAttribute("pageUrl",request.getRequestURI());
            request.getRequestDispatcher(errorPath).forward(request, response);
            return;
        }
        filterChain.doFilter(req, resp);
    }

    private static boolean isSafe(String str) {
        if (!"".equals(str) && null != str) {
            for (String s : safeless) {
                if (str.toLowerCase(Locale.ENGLISH).contains(s)){
                    return false;
                }
            }
        }
        return true;
    }

    private boolean excludeUrl(String url) {
        if (excludePaths != null && excludePaths.length > 0) {
            for (String path : excludePaths) {
                if (url.toLowerCase(Locale.ENGLISH).equals(path)){
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void destroy() {
    }

}

++

 
/**
  *  1.拦截用户登陆信息 
 **/
@Component
public class AuthRestInterceptor extends HandlerInterceptorAdapter { 
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        String clazzName = handlerMethod.getBeanType().getName();
        HttpSession session = request.getSession();
        UserAccountVo vo = (UserAccountVo) session.getAttribute("xxx.userinfo");
        if(vo != null){ 
            BaseContextHandler.setUser(new User(vo.getUserId(),vo.getUsername(),vo.getLoginId(),vo.getSex(),vo.getOrgId(),vo.getOrgName(),vo.getOrgType(),vo.getOrgLevel(),vo.getAreaId(),vo.getAreaName(),vo.getAreaCode(),vo.getRoles(), Integer.valueOf(vo.getAreaLevel()) ));
        }
        return super.preHandle(request, response, handler);
    } 
    
	@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        BaseContextHandler.remove();
        super.afterCompletion(request, response, handler, ex);
    }
}

```java
 /**
 *2.配置
 **/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {


    @Autowired
    private List<HandlerMethodArgumentResolver> resolvers;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.addAll(0, resolvers);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getAuthRestInterceptor()).addPathPatterns("/**")
                .excludePathPatterns(getExcludeCommonPathPatterns().toArray(new String[]{}));
        super.addInterceptors(registry);
    }

    @Bean
    AuthRestInterceptor getAuthRestInterceptor() {
        return new AuthRestInterceptor();
    }

    private ArrayList<String> getExcludeCommonPathPatterns() {
        ArrayList<String> list = new ArrayList<>();
        String[] urls = {
                "/error",
                "/swagger-resources/**",
                "/swagger-ui.html**",
                "/webjars/**",
                "/loginRestService/getConfig",
                "/loginRestService/changePassword",
                "/loginRestService/checkUser",
                "/loginRestOverwriteService/changePassword",
                "/CaptchaImg**"
        };
        Collections.addAll(list, urls);
        return list;
    }
}

/**
  *存储用户信息
 **/
public class BaseContextHandler {

    public static final ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<>();

    /** 临时存在ThreadLocal中的用户 key */
    public static final String CONTEXT_KEY_USER = "currentUser";

    private static void set(String key, Object value) {
        Map<String, Object> map = threadLocal.get();
        if (map == null) {
            map = new HashMap<>();
            threadLocal.set(map);
        }
        map.put(key, value);
    }

    private static Object get(String key) {
        Map<String, Object> map = threadLocal.get();
        if (map == null) {
            map = new HashMap<>();
            threadLocal.set(map);
        }
        return map.get(key);
    }

    /**
     * 获取用户
     * @return
     */
    public static User getUser() {
        Object value = get(CONTEXT_KEY_USER);
        if (value != null && !"".equals(value)) {
           return (User) value;
        }
        User user = new User();
        user.setUserId("");
        user.setOrgId("");
//        预防空指针
        return user;
    }

    public static void setUser(User user) {
        set(CONTEXT_KEY_USER, user);
    }

    public static void remove() {
        threadLocal.remove();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值