博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring boot中使用servlet filter
阅读量:6329 次
发布时间:2019-06-22

本文共 6906 字,大约阅读时间需要 23 分钟。

Spring boot中使用servlet filter

liuyuhang原创,未经允许请勿转载!

 

在web项目中经常需要一些场景,如参数过滤防止sql注入,防止页面攻击,空参数矫正等,

也可以做成token验证,session验证,点击率统计等。

为了这种业务,经常会需要写过滤器(Filter)。

servlet提供的默认过滤器比较好用,配置也还算方便;

转入springboot开发后,注解也并不复杂,原理依旧。

 

使用filter的步骤并不复杂,主要分为几个步骤:

  1、新建class 实现Filter抽象类(javax.servlet.Filter)

  2、override三个方法(init,doFilter,destroy)

  3、编写ParameterRequestWrapper类继承HttpServletRequestWrapper类(稍后说明原因)

  4、ParameterRequestWrapper类构造器

  5、构造器中复写父类构造器并将request.getParameterMap加入子类成员变量

  6、编写addParam方法留用

  7、修改参数并调用ParameterRequestWrapper实例保存params

  8、调用doFilter方法中的FilterChain变量,将修改后的request重新封装

  9、在springboot入口方法中添加注解@ServletComponentScan注册filter

其中1、2步骤为必须的,其余的步骤为修改request参数使用的封装方式。

 

1、新建class实现Filter抽象类(javax.servlet.Filter);

2、override三个方法(init,doFilter,destroy);代码如下:

1 package lyh.java.filterAndInteceptor; 2  3 import java.io.IOException; 4  5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 import javax.servlet.annotation.WebFilter;12 13 import org.springframework.core.annotation.Order;14 15 @Order(1)//多个filter的时候,该序号越小,越早执行16 @WebFilter(filterName = "FirstFilter", urlPatterns = "/*")//url过滤配置,并非包配置17 public class MyMvcFilter implements Filter{18 19     @Override20     public void init(FilterConfig filterConfig) throws ServletException {21         //这里写init逻辑,该init将在服务器启动时调用22     }23 24     @Override25     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {26         //request处理逻辑27         //request在封装逻辑28         //chain重新写回request和response29     }30 31     @Override32     public void destroy() {33         //这里写destroy逻辑,该destroy逻辑将在服务器关闭时调用34     }35 }

 

9、在springboot入口方法中添加注解@ServletComponentScan注册filter,代码如下:

1 package lyh.java; 2  3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.SpringBootConfiguration; 5 import org.springframework.boot.web.servlet.ServletComponentScan; 6  7 import lyh.java.config.DataSourceConfig; 8  9 @SpringBootConfiguration//springboot基础配置注解10 @ServletComponentScan//springboot servlet filter11 public class Run {12 13     public static void main(String[] args) throws Exception {14         SpringApplication.run(Run.class, args);15     }16 }

 

到这里,就完成了Filter的简单创建了,可以自行测试使用

 

创建Filter,一般目的是为了过滤一些参数,如果是为了中断该访问,应该是创建Interceptor

对于java中的mvc,过滤或者修改参数,针对的主要是request中的parameterMap的修改。

当然还有很多好用的操作,这里不做讨论了。

 

修改request实例,思路上有两个步骤是必须要考虑的:

①如何获取request中的parameterMap并且修改?

②如何将修改后的parameterMap重新传递回去,使得controller能够不受影响?

 

对于如何解决以上两个问题,思路上也要经过两个步骤:

①常用的是request.getParameter或request.getParamerterMap方法,但是ServletRequest是一个接口;

该接口定义了getParameterMap抽象方法,只要找到该接口的实现类,继承该类,利用java继承原理,

相互继承的类,调用父类方法的时候,若子类复写了该方法,则默认调用子类方法。

以此来实现request的重新封装。

②在子类中定义add方法,来添加新的param,同时该param与request中原有的param进行校对,去重,

保证子类的覆盖父类的,这样获取param的时候,不会有所察觉。

 

在一番查找之后,发现了一个类,来专门处理request对象的,截图如下

注意类注解:Methods default to calling through to the wrapped request object.意为request默认调用该封装对象

注意截图中的构造器,该构造器传入servletRequest对象,因此该带参构造器肯定要被子类重写

 

于是,编写一个类,继承该类,同时修改构造器,复写getParameter方法,提供一个map作为request内容的缓存;

使得复写的getParameter能够从此缓存中获取param即可,代码如下,注释完善,不再赘述:

1 package lyh.java.tools; 2  3 import java.util.HashMap; 4 import java.util.Map; 5  6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletRequestWrapper; 8  9 /**10  * 重写ParameterRequestWrapper继承HttpServletRequestWrapper并重写部分方法11  * 构造器调用父类构造器12  * 重写param作为缓存13  * 重写getParameter获取子类缓存14  * 增加两个add方法修改该缓存15  * @author Liuyuhang16  *17  */18 public class ParameterRequestWrapper extends HttpServletRequestWrapper {19     20     /**21      * 初始化params,作为getParameter方法获取的参数列表,内首先包含req中的paramMap,再修改22      */23     private Map
params = new HashMap
();24 25 /**26 * 重载构造器,并调用父类构造器,将参数写入子类params27 * @param request28 */29 public ParameterRequestWrapper(HttpServletRequest request) {30 super(request);// 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似31 this.params.putAll(request.getParameterMap());//将参数表,赋予给当前的Map以便于持有request中的参数32 }33 34 /**35 * 重写getParameter,代表参数从当前类中的map获取36 */37 @Override38 public String getParameter(String name) {39 String[]values = params.get(name);40 if(values == null || values.length == 0) {41 return null;42 }43 return values[0];44 }45 46 /**47 * 获取子类param缓存的方法48 */49 public Map
getParamsMap(){50 return this.params;51 }52 /**53 * 写入一个map的方法54 * @param map55 */56 public void addParamsMap(Map
map) {57 for(Map.Entry
entry : map.entrySet()) {58 addParam(entry.getKey() , entry.getValue());59 }60 }61 /**62 * 写入一个参数的方法63 * @param name64 * @param obj65 */66 public void addParam(String name , Object obj) {67 if(obj != null) {68 if(obj instanceof String[]) {69 params.put(name , (String[])obj);70 }else if(obj instanceof String) {71 params.put(name , new String[] {(String)obj});72 }else {73 params.put(name , new String[] {String.valueOf(obj)});74 }75 }76 }77 78 }

 

 返回Filter类中的doFilter方法,对该方法进行加工。思路是:

①封装ServletRequest实例为子类抽象HttpServletRequest对象实例,调用刚刚写的方法的构造器

将ParameterRequestWrapper实例化得实例对象rpw;

②获取该prw的param,一一过滤,如字符串trim,修改null或者空字符串,修改时间日期格式,

获取token来进行身份验证之类。

③调用doFilter中的FilterChain参数,将重新写过的request和response写回。

 

具体代码如下:

1     @Override 2     public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { 3         //将request封装为子类 4         HttpServletRequest httpReq = (HttpServletRequest) req; 5         //调用复写的构造器重新封装request 6         ParameterRequestWrapper prw = new ParameterRequestWrapper(httpReq); 7         //这里写requtst过滤内容的逻辑,如字符串trim,修改null或者空字符串,修改时间日期格式,获取token来进行身份验证之类。 8         prw.addParam("user", "Filter-user"); 9         //调用chain执行filter并写回参数10         chain.doFilter(prw, resp);11     }

 

写个类测试下。代码如下:

1 package lyh.java.controller; 2  3 import javax.servlet.http.HttpServletRequest; 4  5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RestController; 7  8 @RestController//restFull Controller注解,返回json格式 9 public class hello {10     11     @RequestMapping("/hello")12     public String helloTest(HttpServletRequest req) throws Exception {13         String user = req.getParameter("user");14         System.out.println("user:"+user);15         return "hello world!  "+user;16     }17     18     19 }

运行结果如下:

完工!

以上!✧(∗≧ꇴ≦)人(≧ꈊ≦∗)✧

转载于:https://www.cnblogs.com/liuyuhangCastle/p/9568325.html

你可能感兴趣的文章
Linux文件夹分析
查看>>
解决部分月份绩效无法显示的问题:timestamp\union al\autocommit等的用法
查看>>
CRT + lrzsz 进行远程linux系统服务器文件上传下载
查看>>
nginx 域名跳转 Nginx跳转自动到带www域名规则配置、nginx多域名向主域名跳转
查看>>
man openstack >>1.txt
查看>>
linux几大服务器版本大比拼
查看>>
在BT5系统中安装postgresQL
查看>>
Can't connect to MySQL server on 'localhost'
查看>>
【Magedu】Week01
查看>>
写给MongoDB开发者的50条建议Tip25
查看>>
PostgreSQL学习手册(四) 常用数据类型
查看>>
为什么要让带宽制约云计算发展
查看>>
[iOS Animation]-CALayer 绘图效率
查看>>
2012-8-5
查看>>
VS中ProjectDir的值以及$(ProjectDir)../的含义
查看>>
我的友情链接
查看>>
PHP实现排序算法
查看>>
Business Contact Mnanager for Outlook2010
查看>>
9种用户体验设计的状态是必须知道的(五)
查看>>
解决WIN7下组播问题
查看>>