SpringMVC(14) - spring的多部件(文件上传)支持

参考:https://docs.spring.io/spring/docs/4.3.20.RELEASE/spring-framework-reference/htmlsingle/#mvc-multipart

1. 简介
Spring的内置多部件支持处理Web应用程序中的文件上传。可以使用org.springframework.web.multipart包中定义的可插入的MultipartResolver对象启用此多部件支持。 Spring提供了一个用于Commons FileUpload的MultipartResolver实现,另一个用于Servlet 3.0多部件请求解析。

默认情况下,Spring不进行多部件处理,因为一些开发人员希望自己处理多部件。可以通过向Web应用程序的上下文添加多部件解析器来启用Spring多部件处理。检查每个请求以查看它是否包含多部件。如果未找到任何多部件,则请求将按预期继续执行。如果在请求中找到了多部件,则将会使用已在上下文中声明的MultipartResolver。之后,请求中的multipart属性将被视为任意其他属性。

2. 将MultipartResolver与Commons FileUpload一起使用
以下示例显示如何使用CommonsMultipartResolver:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 最大文件大小,单位字节 -->
    <property name="maxUploadSize" value="100000"/>
</bean>

当然,还需要在类路径中放置适当的jar,以使多部件解析器工作。对于CommonsMultipartResolver,需要使用commons-fileupload.jar。

当Spring DispatcherServlet检测到多部件请求时,它会激活已在上下文中声明的解析器并移交请求。解析器然后将当前的HttpServletRequest包装到支持多部分文件上传的MultipartHttpServletRequest中。使用MultipartHttpServletRequest,可以获取有关此请求包含的多部件的信息,并实际访问控制器中的多部件文件。

3. 将MultipartResolver与Servlet 3.0一起使用
为了使用基于Servlet 3.0的多部件解析,需要在web.xml中使用“multipart-config”部分标记DispatcherServlet,或在Servlet中通过代码方式使用javax.servlet.MultipartConfigElement注册,或者在自定义Servlet的类上有一个javax.servlet.annotation.MultipartConfig注解。由于Servlet 3.0不允许从MultipartResolver完成这些设置,因此需要在该Servlet注册级别应用配置设置(如最大大小或存储位置)。

一旦以上述方式之一启用了Servlet 3.0多部件解析,就可以将StandardServletMultipartResolver添加到Spring配置中:

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</bean>

4. 处理表单中的文件上传
MultipartResolver完成其任务后,将像处理其他任何请求一样处理该请求。 首先,创建一个带有文件输入的表单,允许用户上传表单。 encoding属性(enctype="multipart/form-data")让浏览器知道如何将表单编码为multipart请求:

<html>
    <head>
        <title>Upload a file please</title>
    </head>
    <body>
        <h1>Please upload a file</h1>
        <form method="post" action="/form" enctype="multipart/form-data">
            <input type="text" name="name"/>
            <input type="file" name="file"/>
            <input type="submit"/>
        </form>
    </body>
</html>

下一步是创建一个处理文件上传的控制器。 这个控制器非常类似于普通的带注解的@Controller,除了我们在方法参数中使用MultipartHttpServletRequest或MultipartFile:

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) {

        if (!file.isEmpty()) {
            byte[] bytes = file.getBytes();
            // 将bytes存储在某处,如数据库,本地文件
            return "redirect:uploadSuccess";
        }

        return "redirect:uploadFailure";
    }

}

注意@RequestParam方法参数如何映射到表单中声明的输入元素。 在此示例中,byte[]没有任何操作,但实际上可以将其保存在数据库中,将其存储在文件系统中,等等。

使用Servlet 3.0多部件解析时,还可以使用javax.servlet.http.Part作为方法参数:

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") Part file) {

        InputStream inputStream = file.getInputStream();
        // store bytes from uploaded file somewhere

        return "redirect:uploadSuccess";
    }

}

5. 处理程序客户端的文件上传请求
还可以在RESTful服务方案中从非浏览器客户端提交多部件请求。所有上述示例和配置也适用于此处。但是,与通常提交文件和简单表单字段的浏览器不同,编程客户端还可以发送特定内容类型的更复杂数据 --- 例如,带有文件的多部件请求和带有JSON格式数据的第二部分:

POST /someUrl
Content-Type: multipart/mixed

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit
{
    "name": "value"
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="file-data"; filename="file.properties"
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
... File Data ...

可以使用 @RequestParam("meta-data") String metadata 控制器方法参数访问名为“meta-data”的部分。但是,可能更愿意接受从请求部分体中的JSON格式数据初始化强类型对象,这与@RequestBody借助一个HttpMessageConverter将非多部件请求体转换为目标对象的方式非常相似。

为此,可以使用@RequestPart注解而不是@RequestParam注解。它允许通过HttpMessageConverter传递特定多部件的内容,同时考虑到multipart的'Content-Type'头:

@PostMapping("/someUrl")
public String onSubmit(@RequestPart("meta-data") MetaData metadata, @RequestPart("file-data") MultipartFile file) {
    // ...
}

请注意如何使用@RequestParam或@RequestPart可以互换地访问MultipartFile方法参数。 但是,本案例中的@RequestPart("meta-data") MetaData 方法参数基于其“Content-Type”头读取为JSON内容,并在MappingJackson2HttpMessageConverter的帮助下进行转换。

猜你喜欢

转载自blog.csdn.net/mytt_10566/article/details/84202634