SpringMVC实现文件上传

Spring 专栏收录该内容
2 篇文章 0 订阅

1. 快速实现

单文件上传

  1. 创建web项目

  2. 导入文件上传相关的两个jar包commons-fileupload-1.3.3.jarcommons-io-2.4.jar
    文件上传所需jar包

  3. 前端代码:

<%--
  1.这里的enctype一定要写成multipart/form-data,出错我可不负责嗷
  2.这个<%=request.getContextPath()%>JSP文件里面的表达式,这个表达式可以获取web项目的项目路径
 --%>
 <form id="fileUpload" enctype="multipart/form-data" method="post" action="<%=request.getContextPath()%>/file/fileupload">
	<%--
	  1.这里type属性设为file,这样input框子就是可以自动变成文件上传的框子了,是不是很神奇
	  2.name属性的值是用于后端接收参数用的,后端接收参数的时候变量名一定要与name的值一样哦
	--%>
    <input type="file" name="file">
    <button type="submit">上传文件</button>
  </form>
  1. 后端代码
@Controller
@RequestMapping("/test")
public class TestController {
     /**
     * 单文件上传后端接收控制器
     * 注意:MultipartFile形参的变量名必须与前端form表单里
     *          文件上传input框子的name属性值一样,否则会导致
     *          后端接收不到文件,还可能会报404错误
     * @author dalei
     * @param file 前端上传的文件
     */
    @PostMapping("/fileupload")
    @ResponseBody
    public void fileUploadControllerTest(MultipartFile file){
        if (file!=null&&!file.isEmpty()){
            System.out.println("文件上传成功!");
            System.out.println(file.getOriginalFilename());
        }
    }
}
  1. 运行测试
    单文件上传演示
  2. 运行结果
    单文件上传成功结果图

多文件上传

  1. 前端代码
	<%--多文件上传--%>
  <form id="fileUpload" enctype="multipart/form-data" method="post" action="<%=request.getContextPath()%>/test/filesUpload">
    <%--
      1.这里type属性设为file,这样input框子就是可以自动变成文件上传的框子了,是不是很神奇O(∩_∩)O哈哈~
      2.name属性的值是用于后端接收参数用的,后端接收参数的时候变量名一定要与name的值一样哦!
      3.多文件上传时,多写几个文件上传的input框子就行了,注意这几个input框子的name属性值要一样哦!
    --%>
    <input type="file" name="file"><br>
    <input type="file" name="file"><br>
    <input type="file" name="file"><br>
    <input type="file" name="file"><br>
    <button type="submit" class="layui-btn">上传文件</button>
  </form>
  1. 后端代码
@Controller
@RequestMapping("/test")
public class TestController {
    /**
     * 多文件上传后端接收控制器
     * 注意:①多文件上传时,后端要使用MulpartFile[]数组对象来接收
     *              ②同样,MultipartFile[]数组形参的变量名也必须与前端
     *              form表单里文件上传框子的name属性值一样,负责会导致
     *              后端接收不到文件,还可能会报404错误,一定注意哦!
     * @author dalei
     * @param file 前端上传的文件组
     */
    @PostMapping("/filesUpload")
    @ResponseBody
    public void fileArraysUploadControllerTest(MultipartFile[] file){
        if (file!=null&&file.length>0){
            System.out.println("文件上传成功!");
            for (MultipartFile mf:file) {
                System.out.println(mf.getOriginalFilename());
            }
        }
    }
}
  1. 运行测试
    多文件上传运行测试
  2. 运行结果
    多文件上传成功

2.文件上传原理

通过设置表单元素的enctype属性值为mulpart/form-data,让表单提交的数据已二进制编码的方式提交 。后端接收请求的Servlet中使用二进制流来换取内容,这样就能拿到前端上传的文件内容了

<form id="xxx" action="xxx" enctype="multipart/form-data" method="post"></form>

:enctype共有三种值,分别为application/x-www-form-urlencoded、multipart/form-data、text/plain

  • application/x-www-form-urlencoded:表单默认的编码方式,将表单数据编码成name/value形式
  • multipart/form-data:二进制编码类型,有啦传输条数数据类型,图片、歌曲等
  • text/plain:纯文本形式编码,数据以纯文本的形式进行编码,其中不含任何控件或格式字符

3.所需jar包

jar包版本可以根据自己需要选择(我用的是1.3.3的fileupload和2.4的io包哟~)

3.SpringMVC相关配置

在SpringMVC的配置文件中配置multipartResolver

<!--配置文件上传相关项-->
<!--这个bean的id一定要叫MultipartResolver哦,写错了spring就找不到啦!-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
    <!--设置文件上传的字符编码-->
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

:SpringMVC文件上传工作流程(纯文字介绍,可能有点生硬,等我搞清楚了就给你们画图,嘿嘿嘿~~)

Spring组件已经封装好文件上传的组件了,它的流程原理是:SpringMVC的DispatcherServlet控制器中定义了一个multipartResolver(这就是为什么spring配置文件上传的时候,bean的id要叫multipartResolver了)属性,如果用户配置了该bean,启动spring容器的时候,spring会自动注入该参数。如果用户没有配置,则默认为null。
当DispatcherServlet收到请求的时候,它的checkMulpart()方法会调用MultipartResolver的isMulpart()方法,判断请求中是否包含了文件,且MultipartResolver属性是否存在实例。如果满足条件,则调用MultipartResolver的resolveMultipart()方法,对请求参数进行解析,然后将文件解析成MultipartFile并封装在MultiPartHttpServletRequest对象中,返回给DispatcherServlet。

4.单文件上传解析

  1. 前端设置:

    • form表单的enctype属性值设为 multipart/form-data
    • form表单的action设为文件提交地址
    • form表单的method属性设为post

    注意点:

    • enctype属性必须设为 multipart/form-data ,不然表单数据不会以二进制形式编码,后端就接收不到参数
    • method属性最好设为post,这样就不用考虑文件大小了。因为get方式提交参数有大小限制,大概为2k。如果想要限制上传文件的大小,可以使用第三方文件上传组件或者在springMVC的配置文件里手动配置
  2. 后端设置:

    后端控制器接收文件的时候,使用MultipartFile对象作为形参就能接收到前端上传的文件了。

    注意点:

    Multipart对象的变量名必须与form表单文件上传input框的name属性值保持一致,负责后端会接收不到参数,如果写错了,还可以使用@RequestMapping(“xxx”)注解来使参数对应上,不然后端无法读取到上传的文件。

5.多文件上传解析

  1. 前端设置:

    • form表单的enctype属性值设为 multipart/form-data
    • form表单的action设为文件提交地址
    • form表单的method属性设为post
    • form表单文件上传的input框写多个,多个input框的name属性值要一致,这样后端才能同时读取到多个文件

    注意点:

    • enctype属性必须设为 multipart/form-data ,不然表单数据不会以二进制形式编码,后端就接收不到参数
    • method属性最好设为post,这样就不用考虑文件大小了。因为get方式提交参数有大小限制,大概为2k。如果想要限制上传文件的大小,可以使用第三方文件上传组件或者在springMVC的配置文件里手动配置
  2. 后端设置:

    后端控制器接收文件的时候,使用MultipartFile[]数组对象作为形参就能接收到前端上传的文件了。

    注意点:

    Multipart[]数组对象的变量名必须与form表单文件上传input框的name属性值保持一致,负责后端会接收不到参数,如果写错了,还可以使用@RequestMapping(“xxx”)注解来使参数对应上,不然后端无法读取到上传的文件。

6.后端接收参数相关内容

(1)前端仅仅上传单个文件,别的什么都不上传

如果前端只是做了一个文件上传的操作,并没有提交其他表单的信息,那么可以只写一个MultipartFile对象接收参数

(2)前端上传一个表单

  • 如果前端上传了一个表单,表单里不只有普通的用户名等信息,还包含上传的文件,这个时候后端可以使用一个bean实体类接收。这里要注意,bean里面各个属性名称要与form表单的name属性值一样,否则后端无法接收参数。
  • 文件封装一样的原理,属性设为Multipart或者Multipart[]数组对象就行了。

附:

1) 前端上传完整表单,包含单文件,后端使用封装实体接收表单内容代码示例

① 封装实体bean代码

/**
 	* 完整表单内容封装实体类
	 * @author dalei
	 */
	public class FormDataReceive {
	    /**
	     * 这里几个属性的名称要与前端表单的每一个name属性保持一致,
	     * 负责会导致前端表单数据无法封装进来,造成参数丢失,或者可能会
	     * 报404错误
	     * @author dalei
	     */
	    private String username;
	    private String password;
	    private MultipartFile file;
	
	    public FormDataReceive() {
	    }
	
	    public FormDataReceive(String username, String password, MultipartFile file) {
	        this.username = username;
	        this.password = password;
	        this.file = file;
	    }
	
	    public String getUsername() {
	        return username;
	    }
	
	    public void setUsername(String username) {
	        this.username = username;
	    }
	
	    public String getPassword() {
	        return password;
	    }
	
	    public void setPassword(String password) {
	        this.password = password;
	    }
	
	    public MultipartFile getFile() {
	        return file;
	    }
	
	    public void setFile(MultipartFile file) {
	        this.file = file;
	    }
	
	    @Override
	    public String toString() {
	        return "FormDataReceive{" +
	                "username='" + username + '\'' +
	                ", password='" + password + '\'' +
	                ", file=" + file +
	                '}';
	    }
	}

② 前端代码

<%--
	    1.这里的enctype一定要写成multipart/form-data,出错我可不负责嗷
	    2.这个<%=request.getContextPath()%>JSP文件里面的表达式,这个表达式可以获取web项目的项目路径
	   --%>
	  <form id="fileUpload" enctype="multipart/form-data" method="post" action="<%=request.getContextPath()%>/test/formDataUpload">
	    <%--
	      1.这里type属性设为file,这样input框子就是可以自动变成文件上传的框子了,是不是很神奇
	      2.name属性的值是用于后端接收参数用的,后端接收参数的时候变量名一定要与name的值一样哦
	    --%>
	    用户名:<input type="text" name="username"><br><br>
	    密码:<input type="password" name="password"><br><br>
	    上传的文件:<input type="file" name="file"><br><br>
	    <button type="submit" class="layui-btn">提交数据</button>
	  </form>

③ 后端代码

@Controller
	@RequestMapping("/test")
	public class TestController {
	    /**
	     * 完整表单数据上传后端接收控制器
	     * 注意:FormDataReceive形参的各个属性名必须与前端form表单里
	     *          各个input框子的name属性值一样,否则会导致
	     *          后端接收不到数据,还可能会报404错误
	     * @author dalei
	     * @param formData 前端上传的文件
	     */
	    @PostMapping("/formDataUpload")
	    @ResponseBody
	    public void fileUploadEntityControllerTest(FormDataReceive formData){
	       if (formData!=null){
	           System.out.println("表单数据成功接收到了!");
	           System.out.println(formData.getUsername());
	           System.out.println(formData.getPassword());
	           MultipartFile file=formData.getFile();
	           if (file!=null&&!file.isEmpty()){
	               System.out.println(file.getOriginalFilename());
	           }
	       }
	    }
	}

④ 运行测试
在这里插入图片描述
⑤ 运行结果
在这里插入图片描述

2) 前端上传完整表单,包含多文件,后端使用封装实体接收表单内容代码示例

① 封装实体bean代码

<%--
		    1.这里的enctype一定要写成multipart/form-data,出错我可不负责嗷
		    2.这个<%=request.getContextPath()%>是JSP文件里面的表达式,这个表达式可以获取web项目的项目路径
		   --%>
		  <form id="fileUpload" enctype="multipart/form-data" method="post" action="<%=request.getContextPath()%>/test/formDataFilesUpload">
		    <%--
		      1.这里type属性设为file,这样input框子就是可以自动变成文件上传的框子了,是不是很神奇
		      2.name属性的值是用于后端接收参数用的,后端接收参数的时候变量名一定要与name的值一样哦
		    --%>
		    用户名:<input type="text" name="username"><br><br>
		    密码:<input type="password" name="password"><br><br>
		    上传的文件:<input type="file" name="file"><br>
		    上传的文件:<input type="file" name="file"><br>
		    上传的文件:<input type="file" name="file"><br>
		    上传的文件:<input type="file" name="file"><br>
		    <button type="submit" class="layui-btn">提交数据</button>
		  </form>

② 后端代码

@Controller
			@RequestMapping("/test")
			public class TestController {
			    /**
		     * 完整表单数据上传后端接收控制器
		     * 注意:FormDataFilesReceiver形参的各个属性名必须与前端form表单里
		     *          各个input框子的name属性值一样,否则会导致
		     *          后端接收不到数据,还可能会报404错误
		     * @author dalei
		     * @param formData 前端上传的文件
		     */
		    @PostMapping("/formDataFilesUpload")
		    @ResponseBody
		    public void fileUploadEntityFilesControllerTest(FormDataFilesReceiver formData){
		        if (formData!=null){
		            System.out.println("表单数据成功接收到了!");
		            System.out.println(formData.getUsername());
		            System.out.println(formData.getPassword());
		            MultipartFile[] file=formData.getFile();
		            if (file!=null&&file.length>0){
		                for (MultipartFile mf:file) {
		                    System.out.println(mf.getOriginalFilename());
		                }
		            }
		        }
		    }
		}

④ 运行测试
在这里插入图片描述
⑤ 运行结果
在这里插入图片描述

7.使用第三方文件上传组件

以上介绍的方法都是使用原生方式实现的,现在有很多优秀的前端框架都集成了文件上传组件了,而且使用更方便。详细阅读API即可轻松使用(读不懂可以找我讨论哦,O(∩_∩)O哈哈~),这里就不做演示了,后端原理一样的,不用担心。

最后,写的不对的地方或者有某些问题,欢迎给我留言哦。
在这里插入图片描述

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页

打赏作者

我的小幸运呢

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值