解决MultipartResolver带来的multipart/form-data请求参数和FileItem无法同时获取的问题

记录工作中遇到的一点小麻烦

先描述问题吧,项目中web上传通过Spring的MultipartResolver处理,后来因需求变更需要上传几G的大文件,就采用插件分片上传,后台接收文件时需要获取ServletFileUpload中的FileItems中的某些属性,所以就将MultipartResolver的配置取消掉了,结果上线后发现之前正常工作的普通http接口都出现异常,无法获取请求中的参数。通过postman调试发现是content-type为multipart/form-data的请求参数无法获取

显然这里有两个问题,我们分开来说。首先为何Controller无法获取multipart/form-data编码形式的参数,而x-www-form-urlencoded编码却可以呢?通过查阅资料可知,x-www-form-urlencoded顾名思义,会对请求消息进行URLENCODE,空格转换为 "+" 加号,特殊符号转换为 ASCII HEX 值,而multipart/form-data不对字符进行编码,使用二进制数据传输,一般用于上传文件,非文本的数据传输。那为何之前项目的接口方采用multipart/form-data的编码方式能正常获取参数呢?自然是MultipartResolver的功劳了,通过Spring源码可知,在实现类中CommonsMultipartResolver中:

protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
    // 获取请求的编码类型
    String encoding = determineEncoding(request);
    FileUpload fileUpload = prepareFileUpload(encoding);
    try {
        List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
        return parseFileItems(fileItems, encoding);
    } catch (...) {}
}

在 parseRequest() 方法中,首先调用了 prepareFileUpload() 方法来根据编码类型确定一个 FileUpload 实例,然后利用这个 FileUpload 实例解析请求数据后得到文件信息,最后将文件信息解析成 CommonsMultipartFile (实现了 MultipartFile 接口) 并包装在 MultipartParsingResult 对象中。所以Spring实际在这里获取到了request中的参数,然后封装好供Controller获取了。同时在这里我们再回想下第二个问题,为何启用MultipartResolver后无法获取FileItems了?答案也在这段代码中,正如上文所说,Spring将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest) 对象中,最后传递给 Controller,自然而然FileItems就不存在了

最后总结一下吧:

一、接口的编码方式一定要预先定义好,中间服务层代码好改,让调用方们重新构造请求时会死人的

二、虽然使用MultipartResolver后FileItems就无法获取了,但是Spring已经将一切信息都封装在MultipartHttpServletRequest中,可以很容易的获取得到,实例代码如下:

    @RequestMapping(value = "/multipartDemo", method = RequestMethod.POST)
    @ResponseBody
    public String multipartDemo(HttpServletRequest request, HttpServletResponse response) {
	    //获取multipartRequest 
		MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        //获取表单文本
		String formText = multipartRequest.getParameter("formText");
		//获取上传文件
		MultipartFile multiFile = multipartRequest.getFile("multiFile");
        //转存本地
        File localFile = new File("C:\\local.tet");
		multiFile.transferTo(localFile);

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,使用multipart/form-data接收多参数可以通过使用Java API中的HttpServletRequest对象来实现。下面是一种常见的处理方式: 1. 在Servlet中获取HttpServletRequest对象: ```java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取HttpServletRequest对象 HttpServletRequest httpRequest = (HttpServletRequest) request; } ``` 2. 使用Apache Commons FileUpload库解析multipart/form-data请求: ```java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取HttpServletRequest对象 HttpServletRequest httpRequest = (HttpServletRequest) request; // 创建一个DiskFileItemFactory对象,用于处理文件上传的临时文件 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置临时文件存储目录 String tempDir = "路径"; factory.setRepository(new File(tempDir)); // 创建一个ServletFileUpload对象 ServletFileUpload upload = new ServletFileUpload(factory); try { // 解析请求获取所有的表单项 List<FileItem> items = upload.parseRequest(httpRequest); // 遍历所有的表单项 for (FileItem item : items) { if (item.isFormField()) { // 处理普通表单项 String fieldName = item.getFieldName(); String fieldValue = item.getString("UTF-8"); // 进行相应的处理 } else { // 处理文件上传表单项 String fieldName = item.getFieldName(); String fileName = item.getName(); InputStream fileContent = item.getInputStream(); // 进行相应的处理 } } } catch (FileUploadException e) { e.printStackTrace(); } } ``` 在上述代码中,我们使用了Apache Commons FileUpload库来解析multipart/form-data请求。首先,创建一个DiskFileItemFactory对象来处理文件上传的临时文件,并设置临时文件存储目录。然后,创建一个ServletFileUpload对象,并调用parseRequest方法解析请求获取所有的表单项。通过遍历表单项,可以分别处理普通表单项和文件上传表单项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值