1、文件上传
1.1、实现文件上传的三个条件
- 文件上传项 input 类型为 file
- 表单必须是通过 post 提交
- 表单必须是enctype=“multipart/form-data” ,enctype="multipart/form-data(表示用附件的方式发送表单),否则默认就把文件名传递了提交时请求主体发生改变
<form action="${pageContext.request.contextPath}/test01" method="post"
enctype="multipart/form-data">
名称:<input type="text" name="name"><br>
文件:<input type="file" name="file"><br>
<input type="submit" value="提交"><br>
</form>
1.2、配置
- 想要实现文件上传,首先需要引入相关坐标,具体需要用的是
fileupload和io
:<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
- 在引入相关坐标之后,我们还需要对上传文件时用到的工具类
org.springframework.web.multipart.commons.CommonsMultipartResolver
类进行相关配置。
在配置过程中需要给类的一些属性赋值,上述只是一部分属性。<!-- 使用Spring的commonsMultipartResovler配置MultipartResovler用于文件上传 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!--上传文件总大小, 单位为 字节--> <property name="maxUploadSize" value="5242800"/> <!--上传单个文件的大小, 单位为 字节--> <property name="maxUploadSizePerFile" value="5242800"/> <!-- 设置请求的编码格式, 默认为iso-8859-1 --> <property name="defaultEncoding" value="utf-8"/> <!-- 设置上传文件的临时路径 --> <property name="uploadTempDir" value="upload/temp"/> </bean>
1.3、MultipartFile对象
在配置完之后我们就要编写文件上传代码了,SpringMVC 将上传文件时将文件的相关信息以及操作封装到了 MultipartFile 对象中,因此,只需要使用 MultipartFile 类型声明模型类的一个属性即可对被上传文件进行操作。
MultipartFile 接口的相关方法如下:
byte[] getBytes()
:以字节数组的形式返回文件内容。String getContentType()
:返回文件内容类型。InputStream getInputStream()
:返回一个InputStream,从中读取文件内容。String getName()
:返回请求参数的名称。String getOriginalFilename()
:返回上传文件的文件名。long getSize()
:返回文件的大小,单位为字节。boolean isEmpty()
:判断被上传文件是否为空。void transferTo(File destination)
:将上传文件保存到目标目录下。
1.4、实现单文件上传
- 创建前台页面选择文件上传
<form action="${ pageContext.request.contextPath }/upload/singlefile" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="myfile"><br> 文件描述:<textarea rows="3" name="description"></textarea><br> <input type="submit" value="提交"> </form>
- 编写处理上传文件的控制器
@RequestMapping(value = "test09", method = RequestMethod.POST) @ResponseBody //告知 SpringMVC框架 不进行视图跳转,直接进行数据响应 public void test09(@RequestParam("myfiles") MultipartFile multipartFile, HttpServletRequest request) throws IOException { // 获取文件上传到具体文件夹的绝对路径 String realpath = request.getSession().getServletContext().getRealPath("upload"); // 获取上传的文件名 String fileName = multipartFile.getOriginalFilename(); //为了确保上传文件的重名问题,对文件名进行处理 fileName = UUID.randomUUID().toString() +"_"+ fileName // 根据路径构建文件对象 // 在构建过程中一定要注意路径问题 File uploadFile = new File(realpath, fileName); // 判断指定文件夹uploadfiles是否存在,不存在就创建 if (!uploadFile.exists()) { uploadFile.mkdirs(); } // 上传文件 multipartFile.transferTo(uploadFile); }
1.5、多文件上传
多文件上传和单文件上传区别不大,只是多了一个循环上传文件的过程。
- 创建前台页面选择文件上传
<form action="${ pageContext.request.contextPath }/test10" method="post" enctype="multipart/form-data"> 名称:<input type="text" name="name"><br> 文件1:<input type="file" name="uploadFiles"><br> 文件2:<input type="file" name="uploadFiles"><br> 文件3:<input type="file" name="uploadFiles"><br> <input type="submit" value="提交"><br> </form>
- 编写处理上传文件的控制器
@RequestMapping(value = "test10", method = RequestMethod.POST) @ResponseBody //告知 SpringMVC框架 不进行视图跳转,直接进行数据响应 public void test10(@RequestParam("uploadFiles") MultipartFile [] multipartFiles, HttpServletRequest request) throws IOException { // 获取文件上传到具体文件夹的绝对路径 String realpath = request.getSession().getServletContext().getRealPath("upload"); for(MultipartFile multipartFile: multipartFiles){ // 获取上传的文件名 String fileName = multipartFile.getOriginalFilename(); fileName = UUID.randomUUID().toString() +"_"+ fileName // 根据路径构建文件对象 // 在构建过程中一定要注意路径问题,最好写成绝对路径 File uploadFile = new File(realpath, fileName); // 判断指定文件夹uploadfiles是否存在,不存在就创建 if (!uploadFile.exists()) { uploadFile.mkdirs(); } // 上传文件 multipartFile.transferTo(uploadFile); } }
2、文件下载
文件下载的实现有两种方式,一种是通过超链接实现下载,另一种是通过程序编码方式实现下载。前者虽然实现简单,但暴露了文件的真实位置,而且文件需要放在 web 程序的目录下才能下载。后者能够增加安全访问控制,还可以从任意位置提供下载数据,可以将文件存放web程序目录以外,也可以将文件存放在数据库中。
通过程序编码实现下载需要设置两个响应报头:
Content-Type
:告诉浏览器其输出的内容不是普通文本文件或者HTML文件,而是一个保存到本地的文件,需要设置该报头的值为application/x-msdownload
。在不知道文件的类型型时,也可以设置值为application/octet-stream
,该属性值表示任意的字节流。Content-Disposition
:告诉浏览器不直接处理相应实体内容,由用户选择将相应的实体内容保存到一个文件中,需要设置值为attachment;filename=xxx
,指定接收程序处理数据内容的方式。在HTTP应用中,attachment
是标准的方式,后面指定的filename
参数表示保存文件名称,对于中文名称,需要通过编码转换,否则会出现乱码。
@RequestMapping(value = "test11")
public void test11(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取下载的文件路径
String realpath = request.getSession().getServletContext().getRealPath("upload");
// 设置下载文件时的响应报头
response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename=" + toUTF8String(fileName));
// 获取文件输入流
FileInputStream in = new FileInputStream(new File(realpath, fileName));
// 获得响应对象的输出流,用于向客户端输出二进制数据
ServletOutputStream out = response.getOutputStream();
out.flush();
int aRead = 0;
byte[] b = new byte[1024];
// 写到响应输出流
while ((aRead = in.read(b)) != -1 && in != null) {
out.write(b, 0, aRead);
}
out.flush();
// 关闭IO对象
in.close();
out.close();
}
/**
* 下载时保存中文文件名的字符编码转换方法
*/
public String toUTF8String(String str) {
StringBuffer sb = new StringBuffer();
int len = str.length();
for (int i = 0; i < len; i++) {
// 取出字符串中的每个字符
char c = str.charAt(i);
// Unicode码值为0-255时,不作处理
if (c >= 0 && c <= 255) {
sb.append(c);
} else {
// 转换成utf-8编码
byte[] b;
try {
b = Character.toString(c).getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO: handle exception
e.printStackTrace();
b = null;
}
// 转换为%HH的字符串形式
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0) {
k &= 255;
}
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}