过滤器Filter原来还能这样用
相关概念也就不去讨论了,网上相关文章就有很多,本文主要是想通过过滤器实现一些拦截功能并顺带验证一下两个问题:
1.过滤器能不能通过@Order或者实现Ordered接口达到多个自定义过滤器排序的目的?
2.过滤器当中到底能不能使用@Autowired注入并使用spring的资源?
需求: 我们的接口,有时是不需要token校验的,比如定时服务feign调用一些外部服务,定时服务根本没有当前登录人,也就不存在token,所以我们需要对这些服务的访问直接放行或者强制给header里面添加一个token;
定义过滤器,如果是定时服务访问,在header里面手动添加token,如果不是定时服务访问,实现token校验,如果token校验通过,需要将token里面的人员名称和编号放到参数里面;如果token校验不通过,需要让用户转到登录页面重新登录;
1.由于我要想更改request请求的参数和header,只能重写HttpServletRequestWrapper, 然后用自己继承HttpServletRequestWrapper来定义修改参数的方法,doFilter的request是要求ServletRequest,而HttpServletRequestWrapper是继承ServletRequestWrapper,并实现HttpServletRequest,而HttpServletRequest是继承ServletRequest,所以,我们可以自己定义一个类,继承HttpServletRequestWrapper就可以作为doFilter参数传进去;
自定义类FilterTestHttpServletRequestWrappe继承HttpServletRequestWrapper,并定义一个修改参数的方法;注意,其中参数的getParameterValues方法必须重写,请求头的getHeaders方法必须重写,不然controller层是获取不到添加的数据的;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.util.*;public class FilterTestHttpServletRequestWrappe extends HttpServletRequestWrapper { //参数集合 private Map parameterMap; //请求头集合 private Map headerMap=new HashMap(); public FilterTestHttpServletRequestWrappe(HttpServletRequest request) { super(request); //构造函数将参数定义未原始请求的参数 this.parameterMap=request.getParameterMap(); } //自定义新增参数的方法 public void addParameter(String paramName,String[] paramValues){ this.parameterMap.put(paramName,paramValues); } @Override //如果用不到其实可以不用重写 public String getParameter(String name) { if(parameterMap.containsKey(name)){ return parameterMap.get(name)[0]; } return super.getParameter(name); } @Override //这个方法是必须要重写的 public String[] getParameterValues(String name) { return parameterMap.get(name); } @Override //这个方法是必须要重写的 public Enumeration getHeaders(String name) { List headers = Collections.list(super.getHeaders(name)); if(headerMap.containsKey(name)){ headers.add(headerMap.get(name)); } return Collections.enumeration(headers); } //自定义方法天加header的方法 public void addHeader(String name,String value){ headerMap.put(name,value); }}
2.定义第一个过滤器FilterTest1,识别是不是定时服务访问,我们定时服务的域名是http://schedule-service/:
@Component@WebFilter(filterName = "filter1",urlPatterns = "/")//@Order这个注解可以实现过滤器排序@Order(0)public class FilterTest1 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 { HttpServletRequest request = (HttpServletRequest) servletRequest; //获取url StringBuffer requestURL = request.getRequestURL(); String requestURI = request.getRequestURI(); //获取域名 String serviceDomain = requestURL.substring(0, requestURL.indexOf(requestURI)); //判断是不是定时服务 if("http://schecule-service".equals(serviceDomain)){ //手动生成一个默认token String token=JWTUtil.generateDefaultToken(); FilterTestHttpServletRequestWrappe filterTestHttpServletRequestWrappe = new FilterTestHttpServletRequestWrappe(request); //将token添加到header里面 filterTestHttpServletRequestWrappe.addHeader("Authorization",token); filterChain.doFilter(filterTestHttpServletRequestWrappe,servletResponse); }else { //如果不是就需要判断校验token是否存在 //从header中获取token String token = request.getHeader("Authorization"); //校验 Boolean okToken=JwtUtil.checkToken(token); if(okToken){{ //如果校验通过就放行 filterChain.doFilter(servletRequest,servletResponse); }else{ //如果没有token或者token校验不通过,需要重定向到登录页面 HttpServletResponse response = (HttpServletResponse) servletResponse; response.sendRedirect("http://localhost:3306/login.html"); } } @Override public void destroy() { }}
3. 定义第二个过滤器FilterTest2,实现token解析,并重新封装解析后的参数:
import com.jzcs.tongYongInterface.mapper.FilterMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Component@WebFilter(filterName = "filter2",urlPatterns = "/")@Order(1)//在第一个过滤器后面执行public class FilterTest2 implements Filter { @Autowired private FilterMapper filterMapper; @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化方法!"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //1.校验token HttpServletRequest request = (HttpServletRequest) servletRequest; String token = request.getHeader("Authorization"); UserInfo userInfo=JwtUtil.parseToken(token); //如果校验通过,需要将token中的数据解析出来,放到参数里面 FilterTestHttpServletRequestWrappe filterTestHttpServletRequestWrappe = new FilterTestHttpServletRequestWrappe(request); filterTestHttpServletRequestWrappe.addParameter("userName",userInfo.getUserName()); filterTestHttpServletRequestWrappe.addParameter("userId",userInfo.getUserId()); filterChain.doFilter(filterTestHttpServletRequestWrappe,servletResponse); } @Override public void destroy() { }}
综上:是我们的过滤器的一个应用场景;回到我们的两个问题:
1.过滤器能不能通过@Order或者实现Ordered接口达到多个自定义过滤器排序的目的?
2.过滤器当中到底能不能使用@Autowired注入并使用spring的资源?
显然:我们是可以通过@Order或者实现Ordered接口达到多个自定义过滤器排序的目的;
过滤器里面也可以使用@Autowired注入并使用spring的资源,并且访问数据库的;