springboot下的Filter过滤器;Spring的GenericFilterBean过滤器;springmvc的HandlerInterceptorAdapter拦截器;
Filter
Filter要使请求继续被处理,就一定要显示调用filterChain.doFilter()
自定义Filter,@WebFilter形式
@WebFilter形式控制不了多个过滤器之间的执行顺序,默认是按照class名字首字母的ASCII的字母排序.
并且需要在启动类上加上@ServletComponentScan扫描过滤器
package com.fchan.espractice.filter;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(filterName = "tokenFilter", urlPatterns = "/testMybatisTrsanctional/*")
public class TokenFilter implements Filter, ApplicationContextAware {
private ApplicationContext applicationContext;
@Autowired
private ObjectMapper objectMapper;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
String token = request.getHeader("token");
if(!StringUtils.isEmpty(token)){
filterChain.doFilter(servletRequest, servletResponse);
}
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
Map<String,Object> map = new HashMap<>();
map.put("name","李四");
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(objectMapper.writeValueAsBytes(map));
outputStream.close();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
启动类加上扫描注解
package com.fchan.espractice;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.PlatformTransactionManager;
@SpringBootApplication
@MapperScan("com.fchan.espractice.dao")
//ServletComponentScan扫描自定义Filter,可以指定包路径
@ServletComponentScan
public class EsPracticeApplication {
@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager){
System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
return new Object();
}
public static void main(String[] args) {
SpringApplication.run(EsPracticeApplication.class, args);
}
}
过滤器方式2,自定义执行顺序
自定义的2个过滤器
package com.fchan.espractice.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import java.io.IOException;
@Slf4j
public class TestFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("TestFilter.doFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
}
package com.fchan.espractice.filter;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class TokenFilter implements Filter, ApplicationContextAware {
private ApplicationContext applicationContext;
@Autowired
private ObjectMapper objectMapper;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
String token = request.getHeader("token");
if(!StringUtils.isEmpty(token)){
filterChain.doFilter(servletRequest, servletResponse);
}
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
Map<String,Object> map = new HashMap<>();
map.put("name","李四");
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(objectMapper.writeValueAsBytes(map));
outputStream.close();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
配置2个过滤器
多个过滤器之间order数值小的执行顺序优先
package com.fchan.espractice.filter.config;
import com.fchan.espractice.filter.TestFilter;
import com.fchan.espractice.filter.TokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyFilterConfig {
@Bean
public TestFilter testFilter(){
return new TestFilter();
}
@Bean
public TokenFilter tokenFilter(){
return new TokenFilter();
}
@Bean
public FilterRegistrationBean<TestFilter> TestFilterFilterRegistrationBean(@Autowired TestFilter testFilter){
FilterRegistrationBean<TestFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(testFilter);
filterRegistrationBean.addUrlPatterns("/*");
//order数值小的顺序优先
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean<TokenFilter> TokenFilterFilterRegistrationBean(@Autowired TokenFilter tokenFilter){
FilterRegistrationBean<TokenFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(tokenFilter);
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setOrder(3);
return filterRegistrationBean;
}
}
Spring的GenericFilterBean过滤器
org.springframework.web.filter.GenericFilterBean是spring对Servelet的Filter的实现,我们继承GenericFilterBean后可以将Servelet的Filter纳入spring的容器中作为bean;
@Order(-999)数值越小执行优先级越高
自定义的过滤器
package com.fchan.espractice.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Component
@Order(-999)
public class MySpringFilter extends GenericFilterBean {
@Autowired
private ObjectMapper objectMapper;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
String token = request.getHeader("token");
if(!StringUtils.isEmpty(token)){
filterChain.doFilter(servletRequest, servletResponse);
}
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
Map<String,Object> map = new HashMap<>();
map.put("name","李四");
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(objectMapper.writeValueAsBytes(map));
outputStream.close();
}
}
Springmvc的HandlerInterceptorAdapter拦截器
在HandlerInterceptorAdapter中主要提供了以下的方法:
preHandle:在方法被调用前执行。在该方法中可以做类似校验的功能。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行,也就是说我们想调用的方法不会被执行,但是你可以修改response为你想要的响应。
postHandle:在方法执行后调用。
afterCompletion:在整个请求处理完毕后进行回调,也就是说视图渲染完毕或者调用方已经拿到响应。
自定义拦截器
package com.fchan.espractice.intercept;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@Component
public class GlobalIntercept extends HandlerInterceptorAdapter {
@Autowired
private ObjectMapper objectMapper;
public GlobalIntercept() {
super();
}
/**
* false拦截
* true放行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
if(!StringUtils.isEmpty(token)){
return true;
}
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
Map<String,Object> map = new HashMap();
map.put("name","张三");
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(objectMapper.writeValueAsBytes(map));
outputStream.close();
return false;
}
}
配置拦截器,及顺序说明
多个拦截器的话按照
registry.addInterceptor
的添加顺序来执行
package com.fchan.espractice.intercept.config;
import com.fchan.espractice.intercept.GlobalIntercept;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptConfig implements WebMvcConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(applicationContext.getBean(GlobalIntercept.class));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}