springMVC的上传和下载 Day33 2018-12-23
springMVC的上传和下载
1. 文件上传
上传文件必须将表单的
method
设置为post
,并且将enctype
设置为multipart/form-data
。在
springmvc
中实现文件上传有两种方式:1、使用
Apache Commons FileUpload
元件。2、利用
servlet3.0
及其更高版本的内置支持。
-
MultipartFile
常用方法:
返回参数 | 方法 |
---|---|
byte[] getBytes() |
返回文件的内容作为一个字节数组。 |
String getContentType() |
返回文件的内容类型。 |
InputStream getInputStream() |
返回InputStream读取文件的内容。 |
String getName() |
返回表单中文件组件的名字。 |
String getOriginalFilename() |
返回上传文件的原名 |
long getSize() |
返回文件的大小,以字节byte为单位。 |
boolean isEmpty() |
返回是否上传文件是空的,也就是说,没有文件 选择多部分形式或所选的文件中没有的内容。 |
void transferTo(File dest) |
接收到的文件转移到给定的目标文件。 |
1.1 配置tomcat虚拟路径
编辑
server
文件(%tomcathome%\conf\server.xml)
我们打算建立一个images的虚拟目录,只要在%tomcathome%\conf\server.xml
文件,在<host>
标签中加入文件中加入如下代码即可:
<Context debug="0" docBase="D:\APPFile\images" path="/images" reloadable="true"/>
注意,此时path一定要写,因为我们此时没有新建xml文件了,所以一定要指明web。
配置文件属性的含义:
-
docBase
为希望将文件存储到的物理目录的绝对路径。 -
path
为访问文件时的虚拟目录。 -
reloadable
属性的设置有些用处,当reloadable=true
时,相关文件改变,Tomcat先停止webapp
并释放内存,然后重新加载webapp
。这样以来可以省去手工部署web app
工程的时间。和开发工具一起使用可以稍微提高点工作效。
2.使用 Apache Commons FileUpload
元件上传
2.1 添加jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
2.2 springmvc配置
spring MVC
上下文中没有装配multipartResolver
,不能处理文件上传
bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 上传文件大小上限,单位为字节(10MB) -->
<property name="maxUploadSize">
<value>10485760</value>
</property>
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
</bean>
2.3 Controller
@Controller
@RequestMapping(value = "/file")
public class FileUploadController {
@RequestMapping(value = "/{formName}")
public String loginForm(@PathVariable String formName) {
// 动态跳转页面
return "file/" + formName;
}
// 上传文件会自动绑定到MultipartFile中
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(HttpServletRequest request, @RequestParam("description") String description,
@RequestParam("file") MultipartFile file) throws Exception {
System.out.println(description);
// 如果文件不为空,写入上传路径
if (!file.isEmpty()) {
// 上传文件路径
// String path = request.getServletContext().getRealPath("/images/");
//图片服务器路径
String path = "D:\\QYAPP\\images\\";
// 上传文件名 原始文件名
String filename = file.getOriginalFilename();
//创建新文件,路径为:图片服务器路径+新文件名
File filepath = new File(path, filename);
// 判断路径是否存在,如果不存在就创建一个
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
// 将上传文件保存到一个目标文件当中
file.transferTo(new File(path + File.separator + filename));
return "file/" + "success";
} else {
return "file/" + "error";
}
}
}
2.4 jsp
uploadForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传</title>
</head>
<body>
<h2>文件上传</h2>
<form action="upload" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>文件描述:</td>
<td><input type="text" name="description"></td>
</tr>
<tr>
<td>请选择文件:</td>
<td><input type="file" name="file"></td>
</tr>
<tr>
<td><input type="submit" value="上传"></td>
</tr>
</table>
</form>
</body>
</html>
3. 使用对象接收上传文件
3.1 实体类
public class User implements Serializable{
private String username;
private MultipartFile image;
private String path;
//省略get/set方法
}
3.2 Controller层
@RequestMapping(value="/register")
public String register(HttpServletRequest request,
@ModelAttribute User user,
Model model)throws Exception{
System.out.println(user.getUsername());
// 如果文件不为空,写入上传路径
if(!user.getImage().isEmpty()){
// 上传文件路径
//String path = request.getServletContext().getRealPath("/images/");
//图片服务器路径
String path = "D:\\QYAPP\\images\\";
// 上传文件名
String filename = user.getImage().getOriginalFilename();
File filepath = new File(path,filename);
// 判断路径是否存在,如果不存在就创建一个
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
// 将上传文件保存到一个目标文件当中
user.getImage().transferTo(new File(path+File.separator+ filename));
//虚拟图片路径
String imagePath = request.getRequestURL().toString();
imagePath = imagePath.substring(0, getIndexAtStr(imagePath, "/", 3))+"images"+File.separator+ filename;
System.out.println(imagePath);
user.setPath(imagePath);
// 将用户添加到model
model.addAttribute("user", user);
return "file/" + "userInfo";
}else{
return "file/" + "error";
}
}
/**
* 返回字符出现第num次的位置索引
* @param str 字符串
* @param key 指定字符串
* @param num 在字符串中出现的次数
* @return
*/
public static int getIndexAtStr(String str,String key,int num){
int count = 0;
int index = 0;
while((index=str.indexOf(key,index))!=-1){
//System.out.println("index="+index);
index = index+key.length();//根据在字符串中出现的位置,计数一次,下次从该位置后重新查找出现新的位置
count++;
if(count==num) break;//第几次跳槽循环
}
//return count;
return index;
}
3.3 jsp
3.3.1 registerForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户注册</title>
</head>
<body>
<h2>用户注册</h2>
<form action="register" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>请上传头像:</td>
<td><input type="file" name="image"></td>
</tr>
<tr>
<td><input type="submit" value="注册"></td>
</tr>
</table>
</form>
</body>
</html>
3.3.2 userInfo.jsp
<a href="download?filename=${requestScope.user.image.originalFilename}">
${requestScope.user.image.originalFilename }
</a>
<img alt="${requestScope.user.image.originalFilename }" src="${requestScope.user.path }">
4. Spring MVC 文件下载
页面给出 超链接,
href
的属性等于下载文件的路径,即可下载
springMVC
提供了一个ResponseEntity
类型,可以定义返回的HttpHeaders
和HttpStatus
。
4.1 Controller层
@RequestMapping(value="/download")
public ResponseEntity<byte[]> download(HttpServletRequest request,
@RequestParam("filename") String filename,
Model model)throws Exception{
// 下载文件路径
//String path = request.getServletContext().getRealPath("/images/");
//图片服务器路径
String path = "D:\\QYAPP\\images\\";
File file = new File(path+File.separator+ filename);
HttpHeaders headers = new HttpHeaders();
// 下载显示的文件名,解决中文名称乱码问题
String downloadFielName = new String(filename.getBytes("UTF-8"),"iso-8859-1");
// 通知浏览器以attachment(下载方式)打开图片
headers.setContentDispositionFormData("attachment", downloadFielName);
// application/octet-stream : 二进制流数据(最常见的文件下载)。
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 201 HttpStatus.CREATED
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
headers, HttpStatus.CREATED);
}
5. 利用servlet3.0及其更高版本的内置支持上传文件
有了
Servlet3
,就不再需要Commons FileUpload
和Commons IO
元件了。在servlet3
及以上版本的容器进行上传文件,处理已上传文件的Servlets
必须以@MultipartConfig
进行标注。下列是可能在MultipartConfig
标注类型中出现的属性,它们都是可选的:
maxFileSize
:上传问件的最大容量,默认值为-1,表示没有限制。大于指定值的文件将遭到拒绝。maxRequestSize
:表示多部分HTTP请求允许的最大容量,默认值为-1。location
:表示在part调用write方法时,要将已上传文件保存的磁盘中的位置。fileSizeThreshold
:上传文件超出这个容量界限时,会被写入磁盘。
5.1 配置web.xml
(1)web.xml
Spring MVC
的DispatcherServlet
处理大部分或所有请求,如果要以@MultipartConfig
进行标注,需要修改源代码。这是不可取的,不过,Servlet3
中有一个比较容易的方法,能使一个servlet
变成一个MultipartConfig Servlet
,即给部署描述符(web.xml
)中的servlet
声明赋值。以下代码与用@MultipartConfig
给DispatcherServlet
进行标注的效果一样。
<!-- springMVC配置 前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- 用servlet3及其更高版本上传文件,给DispatcherServlet添加MultipartConfig标注 -->
<multipart-config>
<max-file-size>20848820</max-file-size>
<max-request-size>418018841</max-request-size>
</multipart-config>
</servlet>
5.2 springmvc配置
<!-- 用servlet3及其更高版本上传文件,使用一个不同的多部分解析器multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
5.3 Controller层(多图上传)
@RequestMapping(value="/multiUpload")
public String multiUpload(HttpServletRequest request, @ModelAttribute User user,//@RequestParam("username") String username,
@RequestParam("files") MultipartFile[] files,
Model model)throws Exception{
/*User user = new User();
user.setUsername(username);*/
List<String> listImagePath=new ArrayList<String>();
/*List<MultipartFile> files = null;
//得到多部分解析器
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
//判断request是否有文件上传,即多部分
if(multipartResolver.isMultipart(request)){
//转换为多部分request
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
//取得multipartRequest中的所有文件
files = multipartRequest.getFiles("files");
}*/
//虚拟图片路径
String imagePath = request.getRequestURL().toString();
imagePath = imagePath.substring(0, getIndexAtStr(imagePath, "/", 3))+"images/";
/** 图片按类别存储 */
/** 支持多图片上传 */
//if(files != null && files.size() > 0){
if(files != null && files.length>0) {
int i = 0;
//图片服务器路径
String file_path = "D:\\QYAPP\\images\\";
String filename = "jpg";
//根据类别名创建文件夹
File dir = new File(file_path + filename);
if(!dir.exists() || !dir.isDirectory()){
dir.mkdir();
}
for(MultipartFile file : files){
if(file != null && file.getOriginalFilename() != null && file.getOriginalFilename().length()>0){
//原始文件名
String originalFileName = file.getOriginalFilename();
//新文件名,添加原始文件名后缀
String newFileName = UUID.randomUUID() + originalFileName.substring(originalFileName.lastIndexOf("."));
//创建新文件,路径为:图片服务器路径+文件夹名+新文件名
File newFile = new File(file_path + filename + "\\" + newFileName);
//将内存中的数据写入磁盘
file.transferTo(newFile);
i++;
listImagePath.add(imagePath+ filename + "\\" + newFileName);
user.setImage(file);
}
}
// 将用户添加到model
model.addAttribute("listImagePath", listImagePath);
user.setPath(listImagePath.get(0));
model.addAttribute("user", user);
return "file/" + "userInfo";
}else{
return "file/" + "error";
}
}
5.4 jsp
5.4.1 multiUploadForm.jsp
<form action="multiUpload" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>文件描述:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>请选择文件:</td>
<td><input type="file" name="files"></td>
<td><input type="file" name="files"></td>
<td><input type="file" name="files"></td>
</tr>
<tr>
<td><input type="submit" value="上传"></td>
</tr>
</table>
</form>
5.4.2 userInfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件下载</title>
</head>
<body>
<h3>文件下载</h3>
<a href="download?filename=${requestScope.user.image.originalFilename}">
${requestScope.user.image.originalFilename }
</a>
<img alt="${requestScope.user.image.originalFilename }" src="${requestScope.user.path }">
<c:forEach items="${listImagePath}" var="image">
<img src="${image}"><br/>
</c:forEach>
</body>
</html>
6.总结:
以上两种方式,在pojo类和
controller
类以及jsp
中的代码并无不同,只是第二种方式需要在web.xml
中对DispatcherServlet
添加multipart-config
标注,并且两种方法在springmvc
中配置的多部分解析器的bean不同。其余代码无需改变。
- 多图上传见 5.3