四、SpringMVC 上传与下载
文件上传:本质就是通过IO实现文件的复制,将本地文件复制到服务器端。
文件下载:本质就是通过IO实现文件的复制,将服务器端文件复制到本地。
Spring MVC 框架的文件上传基于 commons-fileupload 组件,并在该组件上做了进一步的封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。
4.1 导入文件上传jar包
方式一:引入jar包
方式二:maven依赖配置
<dependencies>
<!-- spring核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springbean包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springcontext包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- spring表达式包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springAOP包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springAspects包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- spring对web的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springwebMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- 配置javaweb环境 -->
<!-- servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 上传组件包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
4.2 配置
- SpringMVC 为文件上传提供了直接的支持,这种支持是通过即插即用的MultipartResolver实现的。
- SpringMVC 用Commons FileUpload技术实现了一个实现类:CommonsMultipartResovler。
- SpringMVC 中默认没有装配MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用需要配置CommonsMultipartResovler。
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- springmvc的注解式开发 -->
<!-- 开启组件扫描 -->
<context:component-scan base-package="com.newcapec.controller"/>
<!-- MVC注解驱动 -->
<mvc:annotation-driven/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 文件上传的属性设置 -->
<!-- 设置上传文件的大小: 文件的总字节数 -->
<!--
1KB = 1024B
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
...
-->
<property name="maxUploadSize" value="104857600"/>
<!-- 设置上传的字符编码 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 设置缓存大小 -->
<property name="maxInMemorySize" value="10240"/>
</bean>
</beans>
4.3 单文件上传
4.3.1 页面
index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center;">
<h1>首页</h1>
<p><a href="views/upload.jsp">文件上传</a></p>
<p><a href="views/uploads.jsp">批量上传</a></p>
<p><a href="views/show.jsp">文件展示</a></p>
<p><a href="views/download.jsp">文件下载</a></p>
</div>
</body>
</html>
success.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center;">
<h1>上传成功!!!</h1>
</div>
</body>
</html>
upload.jsp:
- form表单提交类型改为enctype="multipart/form-data"。
- 提交方式为post请求,method="post"。
- 在表单中添加type="file"的input表单元素,用来选择需要上传的文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>文件上传</h1>
<!--
在前端或页面中需要注意的:
1.文件上传时提交的请求方法必须为post
2.在form标签中enctype
enctype="application/x-www-form-urlencoded"为默认值:将数据转换为key/value格式,用于普通数据的提交
上传时需要修改enctype为enctype="multipart/form-data": 告知服务器请求中包含二进制的数据(文件)
3.使用上传组件(上传表单元素) <input type="file">
-->
<form action="upload.do" method="post" enctype="multipart/form-data">
<p>请选择文件:<input type="file" name="file"></p>
<p><button>上传</button></p>
</form>
</div>
</body>
</html>
4.3.2 Controller
在Controller的方法中添加MultipartFile类型的参数,用来接收上传文件。
@Controller
public class UploadController {
/**
* 文件上传: 将本地文件传输至服务端
* 在springmvc中通过MultipartFile对象来接收上传的文件
* MultipartFile对象就是通过文件上传解析器创建的
*/
@RequestMapping("/upload.do")
public String upload(MultipartFile file, HttpServletRequest request) throws IOException {
/**
* 处理上传文件:
* 1.获取文件的基本信息
* 2.指定文件的保存目录
* 3.防止文件名称重复
* 4.复制文件
*/
//获取文件大小
long fileSize = file.getSize();
//获取文件名称
String fileName = file.getOriginalFilename();
System.out.println(fileSize);
System.out.println(fileName);
/**
* 2.指定文件的保存目录
* 第一种:当前项目目录下(不是工作空间中,而是项目发布后的目录)
* 优点:属于项目内部资源,方便访问
* 问题:文件在项目中,如果文件数据量大,不利于项目迁移
* 第二种:服务器的文件系统中的目录
* 优点:项目资源与上传文件分离
* 问题:无法直接访问,需要配置虚拟目录,或搭建文件服务器
*/
String rootPath = request.getServletContext().getRealPath("/upload");
// String rootPath = "c:/upload";
/**
* 3.防止文件名称重复
* 使用新建目录,分开存放文件
* 使用UUID来生成新的文件名称
*/
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy");
SimpleDateFormat sdf2 = new SimpleDateFormat("MM");
Date today = new Date();
String year = sdf1.format(today);
String month = sdf2.format(today);
File dir = new File(rootPath + "/" + year + "/" + month);
if(!dir.exists()){
dir.mkdirs();
}
String newName = UUID.randomUUID().toString().replace("-","") +
fileName.substring(fileName.lastIndexOf("."));
//目标文件
File resultFile = new File(dir.getAbsolutePath() + "/" + newName);
//4.文件传输
file.transferTo(resultFile);
System.out.println("文件上传成功...");
return "success";
}
}
MultipartFile类中常用方法如下:
方法 | 作用 |
getOriginalFilename() | 获取上传文件的原名 |
getSize() | 获取文件的字节大小,单位byte |
transferTo(File dest) | 通过i/o流,将文件存放到指定位置 |
getName() | 获取表单中文件组件的名字 |
getContentType() | 获取文件MIME类型 |
getInputStream() | 获取文件流 |
isEmpty() | 是否为空 |
处理上传文件:
- 文件的保存目录
- 第一种:当前项目目录下(不是工作空间中,而是项目发布后的目录)。 优点:属于项目内部资源,方便访问; 问题:文件在项目中,如果文件数据量大,不利于项目迁移;
- 第二种:服务器的文件系统中的目录。 优点:项目资源与上传文件分离; 问题:无法直接访问,需要配置虚拟目录,或搭建文件服务器;
- 防止文件名称重复。
- 使用新建目录,分开存放文件;
- 使用UUID来生成新的文件名称;
4.4 批量上传
uploads.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>批量上传</h1>
<form action="uploadBatch.do" method="post" enctype="multipart/form-data">
<p>请选择文件1:<input type="file" name="file"></p>
<p>请选择文件2:<input type="file" name="file"></p>
<p>请选择文件3:<input type="file" name="file"></p>
<p><button>上传</button></p>
</form>
</div>
</body>
</html>
接收上传文件的参数为MultipartFile类型的数组即可:
/**
* 批量上传
* 将MultipartFile对象定义为数组类型
*/
@RequestMapping("/uploadBatch.do")
public String uploadBatch(MultipartFile[] file) throws IOException {
for (MultipartFile multipartFile : file) {
multipartFile.transferTo(new File("c:/upload/" + multipartFile.getOriginalFilename()));
}
System.out.println("批量上传成功...");
return "success";
}
4.5 下载
download.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<a href="download.do?name=a.jpg">图片1</a>
<a href="download.do?name=b.jpg">图片2</a>
<a href="download.do?name=c.jpg">图片3</a>
<a href="download.do?name=中文.txt">文件</a>
</div>
</body>
</html>
设置响应头即可:
@Controller
public class DownloadController {
/**
* 文件下载:将服务端的文件传输至客户端
* 页面无需跳转,需要设置下载响应头
*/
@RequestMapping("/download.do")
public void download(String name, HttpServletResponse response) throws Exception {
/**
* 设置下载响应头
* 1.content-disposition对应的值为attachment
* 告知浏览器客户端,响应为回传文件(附件)
* 2.设置下载时文件名称
* "attachment;fileName="+name
* 3.文件名称中文处理
* 使用URLEncoder对象进行转码
*/
// response.addHeader("content-disposition", "attachment");
// response.addHeader("content-disposition", "attachment;fileName="+name);
String filename = URLEncoder.encode(name,"UTF-8");
response.addHeader("content-disposition", "attachment;fileName="+filename);
//通过流进行文件传输
FileInputStream inputStream = new FileInputStream("c:/upload/" + name);
OutputStream outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
while(inputStream.read(buffer) != -1) {
outputStream.write(buffer);
}
outputStream.flush();
inputStream.close();
outputStream.close();
}
}
4.6 加载资源
show.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center;">
<h1>图片展示</h1>
<!--
<p><img src="c:/upload/a.jpg"></p>
错误写法
-->
<p><img src="upload/a.jpg"></p>
<p><img src="/up/a.jpg"></p>
<p><img src="/up/b.jpg"></p>
<p><img src="/up/c.jpg"></p>
</div>
</body>
</html>
在页面中无法访问物理目录(硬盘中的真实目录),所以需要在服务器中配置相对应的虚拟目录:
4.6.1 在Eclipse中配置
1、双击服务列表中的tomcat;
2、打开tomcat配置的Modules;
3、在Web Modules中配置虚拟路径;
4.6.2 在IDEA中配置
1、在菜单栏找到Run菜单,选择其中的Edit Configurations;
2、选择Deployment选项卡,点击加号,选择External Source;
3、选择虚拟路径对应的物理目录;
4、在Application context中配置虚拟路径;
4.6.3 在tomcat中配置
在配置目录conf的server.xml文件中找到<Host>标签,在其中添加如下代码即可。docBase为物理目录,path为虚拟路径。
<Context docBase="c:\upload" path="/up" reloadable="true"/>