SpringMVC AJAX 文件上传

1,480 阅读4分钟

记录下采用AJAX的方式搭配SpringMVC完成文件上传。

一:关于multipart请求

ajax异步提交、form表单使用action进行post/get提交请求,Content-Type默认都为application/x-www-form-urlencoded。当提交表单时,表单中的“属性-值”对会被拼接成一个字符串:
username=admin&sex=nan&age=12

当form表单带图片、视频等二进制数据就要用到multipart表单了,需要指定表单属性为multipart。 multipart表单会把表单分割成块,表单中的每个字段对应一个块,每个块都有自己的数据类型。

二:SpringMVC文件上传代码

实现文件上传,其实就是解析一个Mutipart请求。DispatchServlet自己并不负责去解析mutipart 请求,而是委托一个实现了MultipartResolver接口的类来解析mutipart请求。在Spring3.1之后Spring提供了两个现成的MultipartResolver接口的实现类:

CommonMutipartResolver:通过利用Jakarta Commons FileUpload来解析mutipart 请求。
StandardServletMutipartResolver:依赖Servlet3.0来解析mutipart请求。

所以要实现文件上传功能,只需在我们的项目中配置好这两个bean中的任何一个即可。其实这两个都很好用,如果我们部署的容器支持Servlet3.0,我们完全可以使用StandardServletMutipartResolver。但是如果我们的应用部署的容器不支持Servlet3.0或者用到的Spring版本是3.1以前的,那么我们就需要用到CommonMutipartResolver了

通过CommonMutipartResolver 解析mutipart 请求

引入第三方依赖Apache的commons-fileupload第三方类库。
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2.1</version>
</dependency>

在springMVC的配置文件中注册通过CommonMutipartResolver

    <!--配置文件上传的解析类-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="100000" />
        <property name="maxInMemorySize" value="100000" />
    </bean>

编写文件上传的Controller

@Controller
public class FileUpload {

    @RequestMapping("/uploadFile")
    private @ResponseBody String uploadFile(MultipartFile image, HttpSession session,String name) {
        System.out.println(name);
        JSONObject jsonObject = new JSONObject();
        //判断上传文件是否为空
        if (!image.isEmpty()) {
            File path = new File(session.getServletContext().getRealPath("img"));//文件存储地
            String fileName = image.getOriginalFilename();//原始文件名
            if (fileName.endsWith("jpg") || fileName.endsWith("png")) {//限制只能上传jpg和png的图片文件
                File file = new File(path, fileName);
                if (!file.getParentFile().exists()){
                    file.getParentFile().mkdirs();
                }
                try {
                    image.transferTo(file);
                    jsonObject.put("info","上传文件成功");
                } catch (IOException e) {
                    e.printStackTrace();
                    jsonObject.put("info","上传文件失败,请上传.jpg或.png类型的图片");
                }
            }
        }else{
            jsonObject.put("info","上传文件为空!");
        }
        return jsonObject.toString();
    }

编写界面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form id="testForm" enctype="multipart/form-data">
    <input type="file" name="image"/><br/>
    <input type="text" id="name" name="name"/><br/>
    <input type="button" value="提交" id="submit">
</form>
</body>
<script type="text/javascript" src="js/jquery-1.8.1.min.js"></script>
<script>
    $(function () {
        $("#submit").click(function () {
            var formData = new FormData($( "#testForm" )[0]);
            $.ajax({
                type: "post",
                url: "uploadFile",
                data: formData,
                cache: false,
                processData: false,
                contentType: false,
                dataType: 'json',
                success: function (data) {
                    //如果返回的是json字符串、需要在前台解析为json对象
                    var object = $.parseJSON(data);
                    console.log(object);
                }
            });
        });
    })
</script>
</html>

运行结果如下: 后台收到name、前台收到json数据、服务器端成功上传文件

程序注意事项与FormData介绍

form表单.serialize()无法序列化二进制文件会报错,当表单中含有文件时可以借助FormData的传输方式,formdata增加了ajax对二进制文件上传的支持

MDN对formdata的使用介绍:developer.mozilla.org/zh-CN/docs/…

当使用formdata提交后,ajax的cache、processData、contentType均要设置为false。【此处踩坑】

cache设为false是为了兼容ie8,防止ie8之前版本缓存get请求的处理方式。
在 ajax 中 contentType 设置为 false 是为了避免 JQuery 对其操作,从而失去分界符,而使服务器不能正常解析文件。
processData:要求为Boolean类型的参数,默认为true。默认情况下,发送的数据将被转换为对象(从技术角度来讲并非字符串)以配合默认内容类型"application/x-www-form-urlencoded"。如果要发送DOM树信息或者其他不希望转换的信息,请设置为false。


当设置Content-Type为false时:有分界符、且是随机的

当将contentType: false注释掉时:服务器获取不到文件


当我们手动指定contentType: 'multipart/form-data',还是不行

所以请一定要在ajax处设置Content-Type:false并在form表单指定enctype="multipart/form-data"

相关链接

blog.csdn.net/irokay/arti…
blog.csdn.net/suifeng3051…
juejin.cn/post/684490…
www.jianshu.com/p/380661f02…
segmentfault.com/a/119000000…