使用HttpServletRequestWrapper包装HttpServletRequest的目的是什么?这样做我们可以获得什么好处?
答案 0 :(得分:12)
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
,我们只需要用自定义行为覆盖四个param方法。
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);
}
});
}