1、文件下载
文件下载的最重要的一点是设置响应头的Content-disposition
为attachmen;filename=要下载的文件的名字
,然后得到文件的输入流写入本地即可 1. 常规方法
/**
* 第一种文件下载的方法:使用原生的Servlet API
*
* @param filename 下载的文件名,SpringMVC会根据请求参数自动注入
* @param request
* @param response
* @throws UnsupportedEncodingException
*/
@RequestMapping(value="/download1",method=RequestMethod.GET)
public void download(@ResuestParam("filename")String fileName,
HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
response.setContentType("text/html;charset=utf-8");
//解析文件在服务器中的真实路径
String filePath = request.getServletContext().getRealPath("/download/" + fileName);
//System.out.println(filePath);
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//设置响应头告诉客户端浏览器,这个请求是要下载文件
long fileLength = new File(filePath).length();
response.setContentType("application/x-msdownload;");
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
response.setHeader("Content-Length", String.valueOf(fileLength));
//向客户端浏览器写文件数据
bis = new BufferedInputStream(new FileInputStream(filePath));
bos = new BufferedOutputStream(response.getOutputStream());
byte[] buff = new byte[1024];
int len;
while (-1 != (len = bis.read(buff, 0, buff.length))) {
bos.write(buff, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != bis) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != bos) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2. 使用SpringMVC提供的 ResponseEntity<T>类型,使用它可以很方便地定义返回的HttpHeaders和HttpStatus。
/**
*第二种文件下载的方式:使用SpringMVC提供的esponseEntity类型
* @param filename 下载的文件的名字,通过前端页面的请求参数带过来后SpringMVC会自动注入
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value = "/download2",method = RequestMethod.GET)
public ResponseEntity<byte[]> download(String filename, HttpServletRequest request) throws IOException {
System.out.println(filename);
//得到文件在服务器上的真实物理路径
String filePath = request.getServletContext().getRealPath("/download/" + filename);
/**
* 两个把下载文件转成byte[]的办法:一种是把要下载的文件封装成一个File对象,把这个对象交给FileCopyUtils.copyToByteArray(file)
*/
File file = new File(filePath);
/**
* 另一种方法是:自己写一个转换的方法,如下
*/
/*FileInputStream fis = new FileInputStream(filePath);
byte[] file = new byte[fis.available()];
fis.read();
fis.close();*/
String downFileName = new String(filename.getBytes("utf-8"), "iso-8859-1");
HttpHeaders headers = new HttpHeaders();
//这是文件下载关键:设置contentDisposition为attachment
headers.setContentDispositionFormData("attachment", downFileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileCopyUtils.copyToByteArray(file), headers, HttpStatus.OK);
}
下载页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
pageContext.setAttribute("ctp",request.getContextPath());
%>
<html>
<head>
<title>下载高清图片</title>
</head>
<body>
<h2>高清壁纸下载</h2>
<table>
<tr>
<th>
<img src="../..${ctp}/download/18.jpg" width="420px" height="320px"><br/>
<button><a href="download1?filename=18.jpg">使用Servlet API下载</a></button>
<button><a href="download2?filename=18.jpg">使用SpringMVC框架下载</a></button>
</th>
<th>
<img src="../..${ctp}/download/13.jpg" width="420px" height="320px"><br/>
<button><a href="download1?filename=13.jpg">使用Servlet API下载</a></button>
<button><a href="download2?filename=13.jpg">使用SpringMVC框架下载</a></button>
</th>
<th>
<img src="../..${ctp}/download/14.jpg" width="420px" height="320px"><br/>
<button><a href="download1?filename=14.jpg">使用Servlet API下载</a></button>
<button><a href="download2?filename=14.jpg">使用SpringMVC框架下载</a></button>
</th>
</tr>
<tr>
<th>
<img src="../..${ctp}/download/15.jpg" width="420px" height="320px"><br/>
<button><a href="download1?filename=15.jpg">使用Servlet API下载</a></button>
<button><a href="download2?filename=15.jpg">使用SpringMVC框架下载</a></button>
</th>
<th>
<img src="../..${ctp}/download/16.jpg" width="420px" height="320px"><br/>
<button><a href="download1?filename=16.jpg">使用Servlet API下载</a></button>
<button><a href="download2?filename=16.jpg">使用SpringMVC框架下载</a></button>
</th>
<th>
<img src="../..${ctp}/download/17.jpg" width="420px" height="320px"><br/>
<button><a href="download1?filename=17.jpg">使用Servlet API下载</a></button>
<button><a href="download2?filename=17.jpg">使用SpringMVC框架下载</a></button>
</th>
</tr>
</table>
</body>
</html>
测试结果

2、文件上传
文件上传这里使用的是commons-fileupload-1.4
,他需要依赖commons-io
,他们的Maven依赖如下:
<!--文件上传-->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
(1)单文件上传
<!--单文件上传-->
<h3>单文件上传</h3>
<form action="${ctp}/uploadImg" method="post" enctype="multipart/form-data">
头像: <input type="file" name="headerImg"/><br/>
用户名:<input type="text" name="username"/><br/>
<button type="submit">提交</button><br/>
</form>
//单个文件上传
@RequestMapping("/uploadImg")
public String ImgUpload(
@RequestParam("username") String userName,
@RequestParam("headerImg") MultipartFile file,
HttpServletRequest request,
Model model) {
String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
try {
//得到服务器上传文件的文件夹物理路径
String realPath = request.getServletContext().getRealPath("/upload/");
File dir=new File(realPath+date+"//");
if(!dir.exists()){
boolean res=dir.mkdir();
if(!res){
model.addAttribute("msg", "文件上传失败!请重试!");
return null;
}
}
//解析文件后缀名
String fileName = file.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
if(".jpg".equals(suffix)||".png".equals(suffix)||".gif".equals(suffix)||".jpeg".equals(suffix)||"bmp".equals(suffix)) {
//给上传的文件重新命名
File newFileName = new File(dir.toString() + "//" + System.currentTimeMillis() + suffix);
//保存文件到服务器
file.transferTo(newFileName);
model.addAttribute("msg", "文件上传成功!");
}else{
model.addAttribute("msg","文件上传失败!只支持jpeg, jpg, png, gif, bmp 格式的图片文件");
}
} catch (Exception e) {
model.addAttribute("msg", "文件上传失败!");
}
return "fileUpLoad";
}
<?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:context="http://www.springframework.org/schema/context"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--文件上传解析器的id是固定的,必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--上传的文件总大小50M-->
<property name="maxUploadSize" value="#{1024*1024*50}"/>
<!--单个文件最大5M-->
<property name="maxUploadSizePerFile" value="#{1024*1024*5}"/>
<!--默认的字符编码:utf-8-->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
</beans>
(2)多文件上传 其实多文件上传也很简单,单文件上传是在Controller的处理方法中使用MultipartFile对象作为参数接收前端上传过来的文件,而多文件上传则使用MultipartFile对象数组来接收。
<h3>一次选一个文件,一次提交上传多个文件</h3>
<form action="${ctp}/upload2" method="post" enctype="multipart/form-data">
头像: <input type="file" name="headerImg"/><br/>
图片: <input type="file" name="headerImg"/><br/>
资料: <input type="file" name="headerImg"/><br/>
文件: <input type="file" name="headerImg"/><br/>
用户名:<input type="text" name="username"/><br/>
<button type="submit">提交</button><br/>
</form>
@Controller
public class FileUpLoadController {
@RequestMapping("/upload2")
public String upload(@RequestParam("username") String userName,
@RequestParam("headerImg") MultipartFile[] files,
HttpServletRequest request,
Model model) {
String realPath = request.getServletContext().getRealPath("/upload/");
File dir = new File(realPath + date +"//"+userName+"//");
if (!dir.exists()) {
boolean res = dir.mkdirs();
if (!res) {
model.addAttribute("msg", "文件上传失败!请重试!");
return null;
}
}
for (MultipartFile file : files) {
uploadFile(dir.toString(), file, model);
}
return "fileUpLoad";
}
public void uploadFile(String path, MultipartFile file, Model model) {
try {
if (!file.isEmpty()) {
String fileName = file.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
//给上传的文件重新命名
File newFileName = new File(path + "//" + System.currentTimeMillis() + suffix);
System.out.println(newFileName);
//保存文件到服务器
file.transferTo(newFileName);
model.addAttribute("msg", "文件上传成功!");
}
} catch (Exception e) {
model.addAttribute("msg", "文件上传失败!" + e);
}
}
}
同样的,使用MultipartFile数组接收前端上传过来的多个文件,也需要在springmvc的配置文件进行配置,具体配置与上述单文件上传的springmvc.xml配置没差别。这样,就可以进行多文件上传了。
多种文件上传情景综合 当然,项目开发中,场景可能并不是这么简单,上述的多文件上传是一个个文件选择后一起上传(即多个name相同的input标签),那要是我项目中只要一个input标签就可以一次性多个文件呢?又或者一个页面中既要一个个选择的多文件上传,又要一次性选择的多文件上传,还要有单文件上传呢?没问题,MultipartFile[]
通吃,代码也很easy,下面直接上代码。
页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
pageContext.setAttribute("ctp",request.getContextPath());
%>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="${ctp}/upload3" method="post" enctype="multipart/form-data">
<!--一次选择一个文件的多文件上传-->
头像: <input type="file" name="headerImg"/><br/>
<!--一次选择一个文件的多文件上传 -->
<input type="file" name="img"/><br/>
<input type="file" name="img"/><br/>
<input type="file" name="img"/><br/>
<!--一次选多个文件的多文件上传 -->
图片:<input type="file" name="pic" multiple/><br/>
用户名:<input type="text" name="username"/><br/>
<button type="submit">提交</button><br/>
</form>
${msg}
</body>
</html>
控制器
@RequestMapping("/upload3")
public String upload(@RequestParam("username") String userName,
@RequestParam("headerImg") MultipartFile[] files1,
@RequestParam("img") MultipartFile[] files2,
@RequestParam("pic") MultipartFile[] files3,
HttpServletRequest request,
Model model) {
String realPath = request.getServletContext().getRealPath("/upload/");
File dir = new File(realPath + date +"//"+userName+"//");
if (!dir.exists()) {
boolean res = dir.mkdirs();
if (!res) {
model.addAttribute("msg", "文件上传失败!请重试!");
return null;
}
}
for (MultipartFile file : files1) {
uploadFile(dir.toString(), file, model);
}
for (MultipartFile file : files2) {
uploadFile(dir.toString(), file, model);
}
for (MultipartFile file : files3) {
uploadFile(dir.toString(), file, model);
}
return "fileUpLoad";
}
public void uploadFile(String path, MultipartFile file, Model model) {
try {
if (!file.isEmpty()) {
String fileName = file.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
//给上传的文件重新命名
File newFileName = new File(path + "//" + System.currentTimeMillis() + suffix);
System.out.println(newFileName);
//保存文件到服务器
file.transferTo(newFileName);
model.addAttribute("msg", "文件上传成功!");
}
} catch (Exception e) {
model.addAttribute("msg", "文件上传失败!" + e);
}
}
测试结果

MultipartFile[]就是如此强大,不管单个多个,逻辑处理一样,所以建议在项目开发中使用MultipartFile[]作为文件的接收参数。
3、重要方法和参数
1、MutipartFile类的一些常用方法:
- String getContentType() //获取文件MIME类型
- InputStream getInputStream() //获取文件流
- String getName() //获取表单中文件组件的名字
- String getOriginalFilename() //获取上传文件的原名
- long getSize() //获取文件的字节大小,单位byte
- boolean isEmpty() //是否为空
- void transferTo(File dest) //保存文件到服务器指定路径
2、CommonsMultipartResolver的属性解析
- defaultEncoding:表示用来解析request请求的默认编码格式,当没有指定的时候根据Servlet规范会使用默认值ISO-8859-1。当request自己指明了它的编码格式的时候就会忽略这里指定的defaultEncoding。
- uploadTempDir:设置上传文件时的临时目录,默认是Servlet容器的临时目录。
- maxUploadSize:设置允许上传的总的最大文件大小,以字节为单位计算。当设为-1时表示无限制,默认是-1。
- maxUploadSizePerFile:跟maxUploadSize差不多,不过maxUploadSizePerFile是限制每个上传文件的大小,而maxUploadSize是限制总的上传文件大小。
- maxInMemorySize:设置在文件上传时允许写到内存中的最大值,以字节为单位计算,默认是10240。
- resolveLazily:为true时,启用推迟文件解析,以便在UploadAction中捕获文件大小异常。