过滤器和拦截器
前言
Github:https://github.com/HealerJean
1、过滤器和拦截器
1.1、过滤器、拦截器、aop`区别
过滤器:拦截器拦截的是URL
,
拦截器:拦截器拦截的是URL
,
①拦截器是基于
Java
的反射机制的,而过滤器是基于函数回调。②拦截器不依赖与
servlet
容器,过滤器依赖与servlet
容器。③拦截器只能对
action
请求起作用,而过滤器则可以对几乎所有的请求起作用。④拦截器可以访问
action
上下文、值栈里的对象,而过滤器不能访问。⑤在
action
的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。⑥拦截器可以获取
IOC
容器中的各个bean
,而过滤器就不行,这点很重要,在拦截器里注入一个service
,可以调用业务逻辑。
Spring AOP
:只能拦截 Spring
管理 Bean
的访问(业务层 Service
)
三者功能类似,但各有优势,从过滤器–》拦截器–》切面,拦截规则越来越细致,执行顺序依次是过滤器、拦截器、切面。一般情况下数据被过滤的时机越早对服务的性能影响越小,因此我们在编写相对比较公用的代码时,优先考虑过滤器,然后是拦截器,最后是aop
。比如权限校验
1、一般情况下,所有的请求都需要做登陆校验,此时就应该使用过滤器在最顶层做校验;
2、日志记录,一般日志只会针对部分逻辑做日志记录,而且牵扯到业务逻辑完成前后的日志记录,因此使用过滤器不能细致地划分模块,此时应该考虑拦截器
3、然而拦截器也是依据URL
做规则匹配,因此相对来说不够细致,因此我们会考虑到使用AOP实现,AOP可以针对代码的方法级别做拦截,很适合日志功能。
1.2、忽略URL配置
1.2.1、过滤器
Spring
中自定义过滤器(Filter
)一般只有一个方法,返回值是void
,当请求到达web
容器时,会探测当前请求地址是否配置有过滤器,有则调用该过滤器的方法(可能会有多个过滤器),然后才调用真实的业务逻辑,至此过滤器任务完成。过滤器并没有定义业务逻辑执行前、后等,仅仅是请求到达就执行。特别注意:过滤器方法的入参有
request
,response
,FilterChain
,其中FilterChain
是过滤器链,使用比较简单,而request
,response
则关联到请求流程,因此可以对请求参数做过滤和修改,同时FilterChain过滤链执行完,并且完成业务流程后,会返回到过滤器,此时也可以对请求的返回数据做处理。
public class Filter_1 implements Filter {
private FilterConfig filterConfig;
private List<String> whiteList = Arrays.asList("/api/business/contract/notifyAsync","/api/account/notify");
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException {
if (whiteList.contains(((HttpServletRequest) servletRequest).getRequestURI())) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
//添加url进行判断忽略下面的方法
SpaceHttpServletRequestWrapper requestWrapper = new SpaceHttpServletRequestWrapper(
(HttpServletRequest) servletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
}
}
1.2.2、拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor_1)
.addPathPatterns("/**")
.excludePathPatterns("/develop/swagger/**");//忽略的
}
1.3、启动顺序
⬤ 谁先配置,谁先启动,DispatcherServlet之后那就顺序反过来执行了,具体看测试结果
⬤ order(2), 数字越小,越先执行
1.3、过滤器和拦截器
1.3.1、过滤器1
package com.hlj.proj.config.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParamsFilter
* @Date 2019/9/29 14:33.
* @Description
*/
public class Filter_1 implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException {
System.out.println("############ Filter_1 在DispatcherServlet之前执行############");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("############ Filter_1 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后############");
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
1.3.2、过滤器2
package com.hlj.proj.config.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParamsFilter
* @Date 2019/9/29 14:33.
* @Description 空格过滤
*/
public class Filter_2 implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException {
System.out.println("############ Filter_2 在DispatcherServlet之前执行############");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("############ Filter_2 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后############");
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
1.3.3、拦截器1
package com.hlj.proj.config.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author HealerJean
* @ClassName Interceptor_1
* @date 2019/11/21 22:08.
* @Description
*/
@Component
@Slf4j
public class Interceptor_1 implements HandlerInterceptor {
/**
* 在DispatcherServlet之前执行
* */
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("************ Interceptor_1 在DispatcherServlet之前执行**********");
return true;
}
/**
* 在controller执行之后的DispatcherServlet之后执行
* */
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
System.out.println("************ Interceptor_1 在controller执行之后的DispatcherServlet之后执行**********");
}
/**
* 在页面渲染完成返回给客户端之前执行
* */
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("************ Interceptor_1 在页面渲染完成返回给客户端之前执行**********");
}
}
1.3.4、拦截器2
package com.hlj.proj.config.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author HealerJean
* @ClassName Interceptor_1
* @date 2019/11/21 22:08.
* @Description
*/
@Component
@Slf4j
public class Interceptor_2 implements HandlerInterceptor {
/**
* 在DispatcherServlet之前执行
* */
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("************ Interceptor_2 在DispatcherServlet之前执行**********");
return true;
}
/**
* 在controller执行之后的DispatcherServlet之后执行
* */
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
System.out.println("************ Interceptor_2 在controller执行之后的DispatcherServlet之后执行**********");
}
/**
* 在页面渲染完成返回给客户端之前执行
* */
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("************ Interceptor_2 在页面渲染完成返回给客户端之前执行**********");
}
}
1.3.7、配置:注意配置顺序
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private Interceptor_1 interceptor_1;
@Resource
private Interceptor_2 interceptor_2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor_1)
.addPathPatterns("/**")
.excludePathPatterns("/develop/swagger/**");
registry.addInterceptor(interceptor_2)
.addPathPatterns("/**")
.excludePathPatterns("/develop/swagger/**");
}
@Bean
public FilterRegistrationBean filter1() {
FilterRegistrationBean fitler = new FilterRegistrationBean();
fitler.setFilter(new Filter_1());
fitler.addUrlPatterns("/hlj/*");
fitler.setName("filter_1");
fitler.setDispatcherTypes(DispatcherType.REQUEST);
return fitler;
}
@Bean
public FilterRegistrationBean filter2() {
FilterRegistrationBean fitler = new FilterRegistrationBean();
fitler.setFilter(new Filter_2());
fitler.addUrlPatterns("/hlj/*");
fitler.setName("filter_2");
fitler.setDispatcherTypes(DispatcherType.REQUEST);
return fitler;
}
}
1.3.6、测试启动
############ Filter_1 在DispatcherServlet之前执行############
############ Filter_2 在DispatcherServlet之前执行############
************ Interceptor_1 在DispatcherServlet之前执行**********
************ Interceptor_2 在DispatcherServlet之前执行**********
样例--------GET请求------请求参数{} com.hlj.proj.controller.DemoController.get[58]
************ Interceptor_2 在controller执行之后的DispatcherServlet之后执行**********
************ Interceptor_1 在controller执行之后的DispatcherServlet之后执行**********
************ Interceptor_2 在页面渲染完成返回给客户端之前执行**********
************ Interceptor_1 在页面渲染完成返回给客户端之前执行**********
############ Filter_2 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后############
############ Filter_1 在视图页面返回给客户端之前执行,但是执行顺序在Interceptor之后############
谁配置在前,谁先执行,然后反过来
2、实用过滤器
主要是重写HttpServletRequestWrapper
// 404是不会进入的
// 重写getParameterValues方法,通过循环取出每一个请求结果,再对请求结果进行过滤
@Override
public String[] getParameterValues(String parameter) {
}
// 404是不会进入的
// 重写getParameter方法 对请求结果进行过滤
@Override
public String getParameter(String name) {
}
2.1、空格过滤器
2.1.1、普通请求的空格过滤器
2.1.1.1、SpaceParamsFilter
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParamsFilter
* @Date 2019/9/29 14:33.
* @Description 普通请求空格过滤
*/
public class SpaceParamsFilter implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException {
filterChain.doFilter(new SpaceParameHttpServletRequestWrapper(
(HttpServletRequest) servletRequest), servletResponse);
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
2.11.2、SpaceParameHttpServletRequestWrapper
package com.hlj.proj.config.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParameHttpServletRequestWrapper
* @Date 2019/9/29 14:44.
* 空格过滤处理
* 下面的将构造器中将所有的请求的参数获取了(包括404),但是其实并没有进行空格过滤处理),
* 一般普通请求空格过滤用下面的就可以了
*/
public class SpaceParameHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* 下面的将构造器中将所有的请求的参数获取了(包括404),但是其实并没有进行空格过滤处理),
* 一般普通请求空格过滤用下面的就可以了
*/
public SpaceParameHttpServletRequestWrapper(HttpServletRequest servletRequest) throws IOException {
super(servletRequest);
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return new String[0];
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = values[i].trim();
}
return encodedValues;
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value == null) {
return null;
}
return value.trim();
}
// private Map<String, String[]> params = new HashMap<>();
//
// public SpaceParameHttpServletRequestWrapper(HttpServletRequest servletRequest) throws IOException {
// super(servletRequest);
//
// Map<String, String[]> requestMap = servletRequest.getParameterMap();
// this.params.putAll(requestMap);
// this.modifyParameterValues();
// }
//
// /**
// * 404是不会进入的
// * 重写getParameterValues方法,通过循环取出每一个请求结果,再对请求结果进行过滤
// */
// @Override
// public String[] getParameterValues(String name) {
// return params.get(name);
// }
//
// /**
// * 重写getParameter方法 对请求结果进行过滤
// **/
// @Override
// public String getParameter(String name) {
// String[]values = params.get(name);
// if (values == null || values.length == 0) {
// return null;
// }
// return values[0];
// }
// public void modifyParameterValues() {
// Set<String> set = params.keySet();
// Iterator<String> it = set.iterator();
// while (it.hasNext()) {
// String key = it.next();
// String[] values = params.get(key);
// values[0] = values[0].trim();
// params.put(key, values);
// }
// }
}
2.1.1.3、过滤器配置
public class InterceptorConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean spaceJsonFilter() {
FilterRegistrationBean fitler = new FilterRegistrationBean();
fitler.setFilter(new SpaceJsonFilter());
fitler.addUrlPatterns("/hlj/*");
fitler.setName("SpaceJsonFilter");
fitler.setDispatcherTypes(DispatcherType.REQUEST);
return fitler;
}
}
2.1.2、Json
请求空格过滤
2.1.2.1、SpaceJsonFilter
package com.hlj.proj.config.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParamsFilter
* @Date 2019/9/29 14:33.
* @Description Josn请求空格过滤
*/
public class SpaceJsonFilter implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException {
filterChain.doFilter(new SpaceJsonHttpServletRequestWrapper(
(HttpServletRequest) servletRequest), servletResponse);
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
2.1.2.2、SpaceJsonHttpServletRequestWrapper
package com.hlj.proj.config.filter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hlj.proj.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParameHttpServletRequestWrapper
* @Date 2019/9/29 14:44.
* @Description
*/
public class SpaceJsonHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
/**
* 预先出初始化数据
*/
public SpaceJsonHttpServletRequestWrapper(HttpServletRequest servletRequest) throws IOException {
super(servletRequest);
BufferedReader reader = servletRequest.getReader();
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String json = sb.toString();
if (StringUtils.isNotBlank(json)) {
json = JsonUtils.toJsonString(trimSpace(json));
}
body = json.getBytes("utf-8");
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* 重写getInputStream方法 Json类型的请求参数必须通过流才能获取到值
*/
@Override
public ServletInputStream getInputStream() {
ByteArrayInputStream bis = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bis.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
public static Map<String, Object> trimSpace(String jsonString) {
Map<String, Object> map = new HashMap<>();
JSONObject jsonObject = JSONObject.parseObject(jsonString);
for (Object k : jsonObject.keySet()) {
Object o = jsonObject.get(k);
if (o instanceof JSONArray) {
List<Object> list = new ArrayList<>();
Iterator<Object> it = ((JSONArray) o).iterator();
while (it.hasNext()) {
Object obj = it.next();
if (obj instanceof JSONObject) {
list.add(trimSpace(obj.toString()));
} else {
list.add(obj.toString().trim());
}
}
map.put(k.toString(), list);
} else if (o instanceof JSONObject) {
// 如果内层是json对象的话,继续解析
map.put(k.toString(), trimSpace(o.toString()));
} else {
// 如果内层是普通对象的话,直接放入map中
map.put(k.toString(), o.toString().trim());
}
}
return map;
}
}
2.1.2.3、过滤器配置
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean spaceFilter() {
FilterRegistrationBean fitler = new FilterRegistrationBean();
fitler.setFilter(new SpaceFilter());
fitler.addUrlPatterns("/*");
fitler.setName("SpaceFilter");
fitler.setDispatcherTypes(DispatcherType.REQUEST);
return fitler;
}
}
2.1.3、结合上面二者
2.1.3.1、SpaceFilter
package com.hlj.proj.config.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParamsFilter
* @Date 2019/9/29 14:33.
* @Description 空格过滤
*/
public class SpaceFilter implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException {
filterChain.doFilter(new SpaceHttpServletRequestWrapper(
(HttpServletRequest) servletRequest), servletResponse);
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
2.1.3.2、SpaceHttpServletRequestWrapper
package com.hlj.proj.config.filter;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hlj.proj.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
/**
* @author HealerJean
* @version 1.0v
* @ClassName SpaceParameHttpServletRequestWrapper
* @Date 2019/9/29 14:44.
* @Description
*/
public class SpaceHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
/**
* 预先出初始化数据
*/
public SpaceHttpServletRequestWrapper(HttpServletRequest servletRequest) throws IOException {
super(servletRequest);
BufferedReader reader = servletRequest.getReader();
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String json = sb.toString();
if (StringUtils.isNotBlank(json)) {
json = JsonUtils.toJsonString(trimSpace(json));
}
body = json.getBytes("utf-8");
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return new String[0];
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = values[i].trim();
}
return encodedValues;
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value == null) {
return null;
}
return value.trim();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* 重写getInputStream方法 Json类型的请求参数必须通过流才能获取到值
*/
@Override
public ServletInputStream getInputStream() {
ByteArrayInputStream bis = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bis.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
public static Map<String, Object> trimSpace(String jsonString) {
Map<String, Object> map = new HashMap<>();
JSONObject jsonObject = JSONObject.parseObject(jsonString);
for (Object k : jsonObject.keySet()) {
Object o = jsonObject.get(k);
if (o instanceof JSONArray) {
List<Object> list = new ArrayList<>();
Iterator<Object> it = ((JSONArray) o).iterator();
while (it.hasNext()) {
Object obj = it.next();
if (obj instanceof JSONObject) {
list.add(trimSpace(obj.toString()));
} else {
list.add(obj.toString().trim());
}
}
map.put(k.toString(), list);
} else if (o instanceof JSONObject) {
// 如果内层是json对象的话,继续解析
map.put(k.toString(), trimSpace(o.toString()));
} else {
// 如果内层是普通对象的话,直接放入map中
map.put(k.toString(), o.toString().trim());
}
}
return map;
}
}
2.1.3.3、配置过滤器
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean spaceJsonFilter() {
FilterRegistrationBean fitler = new FilterRegistrationBean();
fitler.setFilter(new SpaceFilter());
fitler.addUrlPatterns("/hlj/*");
fitler.setName("SpaceJsonFilter");
fitler.setDispatcherTypes(DispatcherType.REQUEST);
return fitler;
}
}
2.2、Xss
攻击过滤器
2.2.1、XssFilter
package com.hlj.proj.config.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author HealerJean
* @ClassName XssFilter
* @Date 2019/11/21 17:38.
* @Description 防Xss攻击Filter ,只能阻止普通的http请求,不能阻止Json请求,如果需要组织Json请求则需要按照空格过滤器一样进行配置
*/
public class XssFilter implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws
IOException, ServletException {
filterChain.doFilter(new XssHttpServletRequestWrapper(
(HttpServletRequest) servletRequest), servletResponse);
}
@Override
public void destroy() {
this.filterConfig = null;
}
}
2.2.2、SpaceParameHttpServletRequestWrapper
package com.hlj.proj.config.filter;
import org.apache.commons.lang3.StringEscapeUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
/**
* 只有确定的controller才回访问这里
*/
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return new String[0];
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null) {
return null;
}
return cleanXSS(value);
}
private String cleanXSS(String value) {
return StringEscapeUtils.escapeXml10(value);
}
}
2.2.3、配置过滤器
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean xssSqlFilter() {
FilterRegistrationBean fitler = new FilterRegistrationBean();
fitler.setFilter(new XssFilter());
fitler.addUrlPatterns("/hlj/*");
fitler.setName("XssFilter");
fitler.setDispatcherTypes(DispatcherType.REQUEST);
return fitler;
}
}
3、实用拦截器
3.1、打印访问日志
@Component
@Slf4j
public class UrlInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
log.info("admin:请求地址:[{}];访问ip:[{}]", httpServletRequest.getRequestURL(), IpUtil.getIp());
return true;
}
}
3.2、自定义注解方法请求次数限制
3.2.1、设置默认方法允许进入的次数
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EntryTimes {
/**
* 方法允许进入的次数
* @return
*/
int value() default 1;
/**
* 可以的前缀 url前缀
* @return
*/
String prefix() default "";
}
3.2.2、aop拦截
import com.duodian.admore.zhaobutong.annotation.EntryTimes;
import com.duodian.admore.zhaobutong.bean.Code;
import com.duodian.admore.zhaobutong.bean.Response;
import com.duodian.admore.zhaobutong.util.AesUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* 控制每个用户访问Controller方法的次数
* Created by fengchuanbo on 2017/5/25.
*/
@Aspect
@Component
public class MethodEntryTimesLimitInterceptor {
private static final String METHOD_CAN_ENTRY_TIMES_KEY = "method:entry:times:";
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 需要有 EntryTimes 标注,并且第一个参数需要是 AuthUser才可以
* @param pjp
* @return
* @throws Throwable
*/
@Around("@annotation(com.duodian.admore.zhaobutong.annotation.EntryTimes)")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getParameter("token");
String aes = AesUtils.LoginDecrypt(token);
Long userId = Long.valueOf(aes.split("#")[0]);
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
EntryTimes annotation = method.getAnnotation(EntryTimes.class);
int times = annotation.value();
String key = METHOD_CAN_ENTRY_TIMES_KEY + ":" + annotation.prefix() + ":" + userId;
// 没有整个方法使用一个redis链接,是为了方式方法执行时间过长一直占用redis链接。
Long increment = getEntryTimes(key);
Object retVal;
try {
// 放在try里面,才能执行finally
if (increment > times){
// 设置十秒钟超时,防止finally在系统崩溃或重启时没有执行造成用户不能操作。
expireKey(key,10);
return Response.of(Code.ACTION_FREQUENT);
}
//调用核心逻辑
retVal = pjp.proceed();
}finally {
deleteKey(key);
}
return retVal;
}
private Long getEntryTimes(String key){
return stringRedisTemplate.opsForValue().increment(key,1);
}
private void deleteKey(String key){
stringRedisTemplate.delete(key);
}
//添加缓存紧急数据的增加
private void expireKey(String key, int seconds){
stringRedisTemplate.boundValueOps(key).expire(seconds, TimeUnit.SECONDS);
}
}
//或者可以参考 opt项目
public Long increase(final String key,final Long seconds){
return redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
redisConnection.select(DB_INDEX);
byte[] keyBytes = stringRedisSerializer.serialize(key);
Long val = redisConnection.incr(keyBytes);
redisConnection.expire(keyBytes,seconds);
return val;
}
});
}
public String getRunStatus(){
return redisTemplate.execute(new RedisCallback<String>() {
public String doInRedis(RedisConnection redisConnection) throws DataAccessException {
redisConnection.select(DB_INDEX);
byte[] result = redisConnection.get(stringRedisSerializer.serialize(KEY));
return stringRedisSerializer.deserialize(result);
}
});
}