继承HttpServletRequestWrapper以实现在Filter中修改HttpServletRequest的参数

一 简介

如题所示,有时候我们需要在一个请求到达Controller之前能够截获其请求,并且根据其具体情况对 HttpServletRequest 中的参数进行过滤或者修改。这时,有的同学可能会想:我们是否可以在一个Filter中将 HttpServletRequest 里的所有参数都取出来分别进行过滤然后再放回到该HttpServletRequest 中呢?

很显然,在 HttpServletRequest 貌似只有 setAttribute(String name, Object o) 这个方法可以设置参数,但是我们经过尝试之后可以发现:使用 setAttribute(String name, Object o) 方法来重新设置参数显然是不行的,因为在Controller中获取参数本质上还是调用的ServletRequest的public String getParameter(String name) 或者 public String[] getParameterValues(String name) 方法,因此想要达到“在Filter中修改HttpServletRequest的参数”的目的,显然是需要使用装饰模式来复写这些方法才行的

在正式代码之前,我还是先简单介绍下ServletRequest、HttpServletRequest、ServletRequestWrapper以及HttpServletRequestWrapper这几个接口或者类之间的层次关系,并说明“继承HttpServletRequestWrapper类以实现在Filter中修改HttpServletRequest的参数”这种方式的原理是什么

如果我们从网上下载tomcat的源代码并查看的话,就可以很清楚地看到这几个类之间的层次关系了,在eclipse中看,它们之间的层次关系是这样的:

20160924212148

如果这个图表还不够清楚地话,我还画了一个简单的UML结构图:

20160924212657710

注:因为我现在没有下载专门的UML建模工具,因此就使用“画图”工具简单地画了一下类图,同时这里的ModifyParametersWrapper 是我后面举例用到的的一个自定义的类

如果学过“装饰模式”的童鞋可能已经发现了,上面这个关系毫无疑问是一个很标准的装饰模式

  • ServletRequest    抽象组件
  • HttpServletRequest    抽象组件的一个子类,它的实例被称作“被装饰者”
  • ServletRequestWrapper    一个基本的装饰类,这里是非抽象的
  • HttpServletRequestWrapper    一个具体的装饰者,当然这里也继承了HttpServletRequest这个接口,是为了获取一些在ServletRequest中没有的方法
  • ModifyParametersWrapper    同样是 一个具体的装饰者(PS:我自定义的一个类)

注:一个标准的装饰模式的UML类图是这样的:

 

 

26160050

那么问题来了,如何在Filter中修改后台Controller中获取到的HttpServletRequest中的参数?

答:很简单,只需要在Filter中自定义一个类继承于HttpServletRequestWrapper,并复写getParameterNames、getParameter、getParameterValues等方法即可

二 代码实现

(1)自定义的过滤器ModifyParametersFilter.java:

上面的代码很简单,就是添加了一个内部类:ModifyParametersWrapper,然后复写了ServletRequest中的几个方法,具体来说就是将原来的每个参数的值的前面加上了“Modified: ”这个字符串

(2)在web.xml中注册该过滤器:

(3)添加一个测试使用的Controller,即:TestModifyController.java:

这里没有处理复杂的逻辑,仅仅只是简单地输出

(4)测试:

启动项目之后访问:http://localhost:9180/FilterDemo/param/modify.html?name=abc

可以发现,在控制台中输出如下:

这就表明了我们前面自定义的过滤器已经将HttpServletRequest中原来的参数成功修改了。同时,还说明SpringMVC的@RequestParam注解本质上调用的是ServletRequest中的 getParameterValues(String name) 方法而不是 getParameter(String name) 方法

注:tomcat-8.5.5源码下载地址:http://pan.baidu.com/s/1skWOso9

参考文章:

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要给HttpServletRequest设置Header,可以通过自定义类继承HttpServletRequestWrapper并重写addHeader方法来实现。首先,我们可以创建一个名为HeaderMapRequestWrapper的类,并继承HttpServletRequestWrapper。在该类,我们可以重写addHeader方法,在该方法通过super.addHeader方法将新的Header添加到请求。以下是示例代码: ```java public class HeaderMapRequestWrapper extends HttpServletRequestWrapper { private final Map<String, String> customHeaders; public HeaderMapRequestWrapper(HttpServletRequest request) { super(request); this.customHeaders = new HashMap<>(); } public void addHeader(String name, String value) { customHeaders.put(name, value); } @Override public String getHeader(String name) { String headerValue = customHeaders.get(name); if (headerValue != null) { return headerValue; } return super.getHeader(name); } @Override public Enumeration<String> getHeaderNames() { List<String> headerNames = new ArrayList<>(customHeaders.keySet()); Enumeration<String> originalHeaderNames = super.getHeaderNames(); while (originalHeaderNames.hasMoreElements()) { String headerName = originalHeaderNames.nextElement(); if (!headerNames.contains(headerName)) { headerNames.add(headerName); } } return Collections.enumeration(headerNames); } } ``` 然后,在具体使用的地方,比如在过滤器(Filter)的doFilter方法,可以创建一个HeaderMapRequestWrapper对象,并调用其addHeader方法来设置新的Header。以下是示例代码: ```java @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) { HttpServletRequest request = (HttpServletRequest) servletRequest; String token = request.getHeader("token"); // 获取其他需要的值 // ... HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(request); requestWrapper.addHeader("headerName", "headerValue"); try { filterChain.doFilter(requestWrapper, servletResponse); } catch (Exception e) { e.printStackTrace(); log.error("处理请求头异常"); } } ``` 通过自定义HttpServletRequestWrapper和添加新的Header,我们可以实现HttpServletRequest设置Header的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [HttpServletRequest修改header值](https://blog.csdn.net/thulium_kyg/article/details/122487077)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [httpServletRequest添加 修改 header,Interceptor 添加 修改header](https://blog.csdn.net/qq_44163445/article/details/124273922)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值