SpringMVC的请求数据参数化的处理机制,使得上传中小型文件变得方便、快捷。在前端页面,与传统开发模式一样,使用标签来添加文件,同时为form表单设置:enctype="multipart/form-data" 的属性,当此类型的表单被提交后,SpringMVC会对multipart类型的数据进行解析。
在SpringMVC中,MultipartFile类主要用来接收并转换request请求中的multipart类型的文件数据。执行Controller获得MultipartFile类型的参数后,就可以使用该参数进行文件的处理了。
MultipartFile类的常用方法:
方法名 | 返回值 | 说明 |
---|---|---|
getContentType() | String | 获取文件MIME类型。 |
getInputStream() | InputStream | 获取文件流。 |
getName() | String | 获取form表单中的文件组件的名字。 |
getOriginalFilename() | String | 获取上传文件的原名。 |
getSize() | long | 获取文件的大小,单位为byte。 |
isEmpty() | boolean | 判断文件是否为空。 |
transferTo(File dest) | void | 将数据保存到一个目标文件中。 |
下面通过实现一个图片上传与下载的实例,来了解SpringMVC上传与下载文件的配置和操作,执行结果图如下:
使用SpringMVC上传文件,首先需要在SpringMVC的核心配置文件springmvc.xml中配置multipart类型解析器,具体配置语句如下:
注意:在该配置中,id="multipartResolver"属性是必须加上的,并且值是固定的。如果不加该id属性,则项目在运行时会报异常。
使用SpringMVC上传文件,其内部实现也使用Apache开源上传软件包fileupload与io包(如下图),所以要将这两个jar包的依赖引入工程中。下载地址如下:
commons-fileupload.jar下载地址
commons-io.jar下载地址
如果使用Maven,则pom.xml文件配置如下:
commons-fileupload
commons-fileupload
1.4
commons-io
commons-io
2.6
创建名为FileUpload.jsp的页面,编写上传图片的前端页面代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
SpringMVC实现文件上传与下载
在该页面中,添加了一个包含enctype="multipart/form-data" 的属性的form表单,并且其中包含一个的文件上传标签。
编写处理该上传与下载请求的Controller控制器类的方法。
package com.pjb.mvc.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 文件上传与下载控制器
* @author pan_junbiao
**/
@Controller
@RequestMapping("file")
public class FileController
{
@Autowired
private HttpServletRequest request;
@Autowired
private HttpServletResponse response;
//目录名称
private String _dirName = "/UploadImages/";
/**
* 上传文件
*/
@RequestMapping("uploadFile")
public String uploadFile(Model model, MultipartFile file, String userName)
{
try
{
if (file.isEmpty())
{
model.addAttribute("message", "请求选择要上传的文件");
return "/FileUpload.jsp";
}
//上传的图片的原始名称
String originalFilename = file.getOriginalFilename();
//判断文件大小
long size = file.getSize();
if (size > 1048576)
{
model.addAttribute("message", "文件大于1M,不能上传");
return "/FileUpload.jsp";
}
//获取文件后缀名,并转换为小写
String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
//只能上传图片,过滤不可上传的文件类型
String fileExit = ".jpg|.jpeg|.gif|.bmp|.png|";
if (fileExit.indexOf(suffix) <= -1)
{
model.addAttribute("message", "对不起!请上传图片");
return "/FileUpload.jsp";
}
//目录路径
String dirPath = request.getServletContext().getRealPath(_dirName);
//判断文件目录是否存在,不存在则创建
File dirFile = new File(dirPath);
if (!dirFile.exists())
{
dirFile.mkdirs();
}
//新的文件名称(格式为:yyyyMMddHHmmss+随机4位数+后缀名)
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); //设置日期格式
int randomNum = (int) (1000 + Math.random() * (9999 - 1000 + 1)); //随机4位数
String newFileName = df.format(new Date()) + randomNum + suffix;
//上传文件
File newFile = new File(dirPath+newFileName);
file.transferTo(newFile);
//返回成功
model.addAttribute("message", "文件上传成功");
model.addAttribute("newFileName", newFileName);
return "/FileUpload.jsp";
}
catch (Exception ex)
{
model.addAttribute("message", "文件上传失败");
return "/FileUpload.jsp";
}
}
/**
* 下载文件
*/
@RequestMapping("downloadFile")
public ResponseEntity downloadFile(String fileName)
{
try
{
if(fileName==null || fileName.length()==0)
{
return null;
}
request.setCharacterEncoding("UTF-8");
//目录路径
String dirPath = request.getServletContext().getRealPath(_dirName);
//获取文件
File file = new File(dirPath+fileName);
//判断文件是否存在
if(!file.exists())
{
return null;
}
//解决文件名乱码
String downloadFileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
//读取二进制文件
byte[] body = null;
InputStream is = new FileInputStream(file);
body = new byte[is.available()];
is.read(body);
//通知浏览器以attachment(下载方式)打开图片
response.setHeader("Content-Disposition", "attchement;filename=" + downloadFileName);
//application/octet-stream二进制流数据(最常见的文件下载)。
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
//文件下载的Http协议中的状态最好使用HttpStatus.OK。
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity entity = new ResponseEntity(body, statusCode);
return entity;
}
catch (Exception ex)
{
ex.toString();
return null;
}
}
}
当需要上传多张图片时,可以在页面创建多个name相同的标签,这样就可以提交多张图片。或者利用移动端HTML5的特性,一个input一次性选择多张图片。多张图片的选择方式主要以前端设计为主,不过多介绍,这里主要介绍后台的处理逻辑,因为不论前端的图片选择模式如何,后台的上传处理逻辑是相同的。在处理图片上传的Controlller方法中,在参数中使用MultipartFile类的数组来接收相同name的文件资源,代码如下:
/**
* 上传多个文件
*/
@RequestMapping("uploadFiles")
public String uploadFiles(Model model, @RequestParam("files") MultipartFile[] files)
{
//利用数组的方式来处理多张图片,处理过程忽略...
}
注意:假设前端文件input的name为“files”,那么Controller方法中的MultipartFile数组的前面要添加@RequestParam("files")注解,表示解析所有名为files的文件资源,将其添加至MultipartFile数组(这里MultipartFile数组的名称仅为参数名称,可以任意命名),该注解不可以省略。