【问题标题】:Accessing Spring Filter/HandlerInterceptor Multipart Parts and Parameters(form fields)访问 Spring Filter/HandlerInterceptor 多部分和参数(表单字段)
【发布时间】:2019-10-20 11:28:09
【问题描述】:

我正在编写一个过滤器(也尝试了一个 HandlerInterceptor),并且需要访问 MultiPart 消息的各个部分 - 包括参数(表单字段)和文件。下面的示例代码只给我标头和一般请求信息,为任何正文/内容请求返回 null,例如getParameter 或 getPart。

public class SampleFilter implements Filter {

    @Override
    public void doFilter (ServletRequest req, ServletResponse resp, FilterChain filterchain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        log.info(request.getContentType());  //Works OK
        log.info(request.getHeader("X-Some-Header"));  //Works OK
        log.info(String.valueOf(request.getContentLength()));  //Works OK
        log.info(request.getParameter("some-form-field"));  //Does NOT work

        for (Part p : request.getParts())  //Does NOT work
        {
            log.info("Part:" + p.getName()); 
        }
}

我已经为此创建了一个 HandlerInterceptor 版本,因为我相信这会在 DespatcherServlet 处理了多部分结构之后在管道中稍后发生。这使我能够从请求中获取表单字段/“参数”,但文件部分仍然没有运气。

public class SampleHandler extends HandlerInterceptorAdapter {

        @Override
        public boolean preHandle (HttpServletRequest request, HttpServletResponse resp, Object handler) throws Exception {

            log.info(request.getContentType());
            log.info(request.getHeader("X-sample-header"));
            log.info(String.valueOf(request.getContentLength()));

            for (String msg : request.getParameterValues("sample-field"))
            {
                log.info(msg);
            }

            log.info(String.valueOf(request.getParts().size()));  // Shows 0

            for (Part p : request.getParts())
            {
                log.info("Part:" + p.getName());
            }

            return true;


到目前为止,我发现的大多数示例都是关于普通控制器中的多部分(见下文,我已经有了这个) - 我专门寻找 Filter 或 HandlerInterceptor 或类似的预控制器钩子。

我有一个现有的 RestController 成功实现了 MultiPart 功能,但不确定如何将这个或类似的方法应用于过滤器:

@RestController
@RequestMapping (value = {"/**"})
@Slf4j
public class SampleController {

    @RequestMapping(value = {"/**"}, method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ResponseBody
    public ResponseEntity<String> SampleMultipartController(@RequestHeader Map<String, String> httpheaders,
                                                        @RequestParam("param1") String param1,
                                                        @RequestParam("param2") List<String> param2,
                                                        @RequestParam ("file") List<MultipartFile> files) throws IOException {

//etc...

我定义了一个 Commons multipartResolver:

@Bean(name = "multipartResolver")
    public CommonsMultipartResolver multipartResolver() {
        final int MAX_UPLOAD_SIZE = (100 * 1024 * 1024);
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setMaxUploadSize(MAX_UPLOAD_SIZE + MAX_UPLOAD_SIZE/5);
        multipartResolver.setMaxUploadSizePerFile(MAX_UPLOAD_SIZE);
        multipartResolver.setMaxInMemorySize(MAX_UPLOAD_SIZE/100);
        return multipartResolver;
    }

【问题讨论】:

    标签: java spring spring-boot spring-mvc servlet-filters


    【解决方案1】:

    通过使用HandlerInterceptor 解决了问题(因为这是 DespatcherServlet 后,它似乎已应用 Multipart Resolver 而不是使用过滤器),和通过删除 Commons Multipart 的东西并改用@MultipartConfig 注解。

    @MultipartConfig
    public class SampleHandler extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle (HttpServletRequest request, HttpServletResponse resp, Object handler) throws Exception {
    
    

    可以访问零件/表格数据:

    request.getParameter("some-form-field"))
    

    如果有多个:

    for (String val : request.getParameterValues("some-form-field"))...etc
    

    对于文件:

    MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
    req.getFile("some-file"))...etc...
    

    如果有多个:

    MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
    for (MultipartFile file : req.getFiles("some-file"))...etc...
    

    也许有更优雅的方法,但这很有效。

    【讨论】:

      【解决方案2】:

      我会在doFilter 中做这样的事情:

      @Override
      public void doFilter (ServletRequest req, ServletResponse resp, FilterChain filterchain) throws IOException, ServletException {
      
          HttpServletRequest request = (HttpServletRequest) req;
          HttpServletResponse response = (HttpServletResponse) resp;
      
          URI uri = new URI(request.getRequestURI());
      
          Map<String, String> map = Arrays.stream(uri.getRawQuery().split("&"))
                  .collect(Collectors.toMap(param -> param.split("=")[0], param -> param.split("=")[0]));
      
      }
      

      然后你的地图中就有你的参数了。

      【讨论】:

      • 我正在寻找在多部分以及文件中传递的表单字段,没有uri参数。问题是访问多部分的部分 - 其中一些不是文件。
      • getRequestURI 甚至不包含 URL 的查询部分,而要检索查询,必须调用 getQueryString。但实际上查询参数已经被解析并通过getParameterNames、getParameter、getParameterValues等提供。
      猜你喜欢
      • 2016-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-18
      • 1970-01-01
      • 1970-01-01
      • 2017-09-21
      • 1970-01-01
      • 2012-09-12
      相关资源
      最近更新 更多