使用HttpServletRequestWrapper封装HttpServletRequest的目的是什么?我们从这样做中获得什么好处?为什么我们要包装HttpServletRequest? api提供了一个HttpServletRequestWrapper,但是我们从包装请求中获得了什么?
回答
HttpServletRequest
是一个HTTP特定的servlet请求的接口。通常,您会在servlet filters或servlets中获得此接口的实例。
有时您想在某个时刻调整原始请求。使用HttpServletRequestWrapper
,您可以包装原始请求并覆盖一些方法,以使其行为稍有不同。
实施例:
你有一堆servlet和JSP,其期望在一定的格式一些请求参数。例如。日期格式为yyyy-MM-dd
。
现在需要以不同的格式支持日期,如dd.MM.yyyy
具有相同的功能。假设没有中央字符串日期函数(它是继承的遗留应用程序),您必须在servlet和JSP中查找所有位置。
作为替代方案,您可以实现一个servlet过滤器。您映射过滤器,以便对您的servlet和JSP的所有请求都将通过此过滤器。
该过滤器的目的是检查日期参数的格式,并根据需要将它们重新格式化为旧格式。 servlet和JSP会始终以预期的旧格式获取日期字段。无需改变它们。
这是你的过滤器的骨架:
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest adjustedRequest = adjustParamDates((HttpServletRequest) request);
chain.doFilter(adjustedRequest, response);
}
我们采取的原始请求和方法adjustParamDates()
我们处理该请求,并将它传递下来的过滤器链。
现在,我们将如何实施adjustParamDates()
?
private HttpServletRequest adjustParamDates(HttpServletRequest req) {
// ???
}
我们需要接口HttpServletRequest
的新实例,它的行为完全一样的原始实例req
。但是getParameter()
,getParameterMap()
,getParameterNames()
,getParameterValues()
这四种方法不应该在原始参数上工作,而是在调整后的参数集上工作。接口HttpServletRequest
的所有其他方法应该像原始方法一样运行。
所以我们可以这样做。我们创建一个HttpServletRequest
的实例并实现所有方法。通过调用原始请求实例的相应方法,大多数方法实现非常简单:
private HttpServletRequest adjustParamDates(final HttpServletRequest req) {
final Map<String, String[]> adjustedParams = reformatDates(req.getParameterMap());
return new HttpServletRequest() {
public boolean authenticate(HttpServletResponse response) {
return req.authenticate(response);
}
public String changeSessionId() {
return req.changeSessionId();
}
public String getContextPath() {
return req.getContextPath();
}
// Implement >50 other wrapper methods
// ...
// Now the methods with different behaviour:
public String getParameter(String name) {
return adjustedParams.get(name) == null ? null : adjustedParams.get(name)[0];
}
public Map<String, String[]> getParameterMap() {
return adjustedParams;
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(adjustedParams.keySet());
}
public String[] getParameterValues(String name) {
return adjustedParams.get(name);
}
});
}
有超过50种实现方法。他们中的大多数只是原始请求的包装实现。我们只需要四个自定义实现。但是我们必须写下所有这些方法。
因此,请参阅HttpServletRequestWrapper
类。这是一个默认的包装器实现,它接受原始请求实例并将接口HttpServletRequest
的所有方法实现为调用原始请求的相应方法的简单包装器方法,就像我们上面所做的那样。
通过子类HttpServletRequestWrapper
我们只需要用自定义行为覆盖四个参数方法。
private HttpServletRequest adjustParamDates(final HttpServletRequest req) {
final Map<String, String[]> adjustedParams = reformatDates(req.getParameterMap());
return new HttpServletRequestWrapper(req) {
public String getParameter(String name) {
return adjustedParams.get(name) == null ? null : adjustedParams.get(name)[0];
}
public Map<String, String[]> getParameterMap() {
return adjustedParams;
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(adjustedParams.keySet());
}
public String[] getParameterValues(String name) {
return adjustedParams.get(name);
}
});
}
- 1. 为什么我们需要包装类
- 2. 软件包安装--binstubs为我们提供什么服务?
- 3. 为什么我们需要装饰器中的包装函数?
- 4. 装配需要什么?为什么我们使用它们?
- 5. 为什么我们需要蟒蛇包装(例如鸡蛋)?
- 6. 我们需要安装什么?
- 7. 外键 - 他们为我做了什么?
- 8. 我见过一个,但是...... 10g包装究竟是什么?
- 9. 当我们有包装类时,为什么支持基元?
- 10. 为什么语言是不是装的?我做错了什么?
- 11. 我忘了包括什么?
- 12. 当我们提取请求时,为什么我们使用Like而不是==?
- 13. 什么是仿函数,为什么我们需要它们?
- 14. 什么是EJB回调,为什么我们需要它们?
- 15. 我们为什么要放?
- 16. java将GZIPOutputStream&ByteArrayOutputStream包装在一起 - 我做错了什么?
- 17. 为什么封装不在对象中/为什么我们称之为封装
- 18. 为什么我的Django安装提供了一个空的HTTP响应?
- 19. 虽然我们有Swing,但为什么我们需要JavaFX?
- 20. 为什么我们需要在数据源中提供密码?
- 21. 为什么我们要包含(Object o)而不是Containers(E e)?
- 22. 了解什么是现有库的API包装
- 23. 我们已经有了nodejs,为什么我们需要nginx或apache?
- 24. 什么是包装器(在Ruby API中)
- 25. 为什么我们需要装饰器中的`* args`?
- 26. 我在做什么错了瓶装+ AngularJS + HTTP POST请求
- 27. 什么是OWASP?为什么我们需要这个?
- 28. 什么是jquery noConflict,为什么我们需要这个?
- 29. 什么是__i686.get_pc_thunk.bx?我们为什么需要这个电话?
- 30. Shadow DOM让我们实现了什么?
AFAIK它是篡改请求参数(例如更改它们的名称)的唯一方法,无需向Web流添加额外的跳跃。 – BigMike