我们为什么要包装HttpServletRequest?api提供了一个HttpServletRequestWrapper,但我们从包装请求中获得了什么?

Ank*_*oel 6 java java-ee

使用HttpServletRequestWrapper包装HttpServletRequest的目的是什么?这样做我们可以获得什么好处?

van*_*nje 16

HttpServletRequest是HTTP特定的servlet请求的接口.通常,您可以在servlet过滤器或servlet中获取此接口的实例.

有时您想在某个时候调整原始请求.使用a,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);
}
Run Code Online (Sandbox Code Playgroud)

我们采用原始请求,并在方法中adjustParamDates()操纵请求并将其传递给过滤器链.

现在,我们将如何实施adjustParamDates()?

private HttpServletRequest adjustParamDates(HttpServletRequest req) {
  // ???
}
Run Code Online (Sandbox Code Playgroud)

我们需要一个新的接口实例,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);
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

有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);
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案需要在一本书的某个章节中。很好的解释和示例解释。轻微建议,希望看到魔法物品的完整“导入”声明。 (3认同)