目录
1. 文章说明
2. JavaWeb实现文件上传下载
2.1 JavaWeb实现文件上传的步骤
2.2 JavaWeb实现文件上传代码
2.3 文件上传的HTTP协议说明
2.4 JavaWeb实现文件下载
3. SpringMVC实现文件上传下载
3.1 SpringMVC实现文件上传的步骤
1. 文章说明
文件上传在Web项目开发中是一个很重要的功能点,随着技术(框架)的更新变化,不同的技术对文件上传有不同的实现方式。在上传和下载文件的使用操作上,新的技术比旧的技术实现了更便捷(更容易上手)操作方式,这是因为新技术对旧技术进行了更深层次的封装,屏蔽了底层的一些实现细节,但是这也导致我们在使用新技术的时候,大多数时候只是停留在会使用的层面,而不明白这些技术的演变过程和底层实现原理,本篇文章就从传统的JavaWeb 到 SpringMVC 再到SpringBoot实现文件上传的方式做一个总结。
2. JavaWeb实现文件上传下载
2.1 JavaWeb实现文件上传的步骤
- 引入可以实现文件上传的两个jar包 commons-fileupload-1.2.1.jar 和 commons-io-1.4.jar
- 写一个如下要求的form表单
- 表单提交方式必须为post
- form标签的enctype属性值必须为multipart/form-data 【enctype=multipart/form-data表示提交的数据以多段(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器,因为客户端是以流的形式把信息发送给服务器段,所以在服务器段接收的时候,也需要以流的形式进行接收】
- form表单中使用 input="file"添加要上传的文件
- 编写服务器代码(Servlet程序)接收并处理上传的数据
2.2 JavaWeb实现文件上传代码
- file_upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="http://localhost:8080/book/uploadServlet"
enctype="multipart/form-data" method="post">
用户名:<input type="text" name="username"><br/>
头 像:<input type="file" name="photo"><br/>
<input type="submit" value="提交">
</form>
</body>
</body>
</html>
2. UploadServlet.java
package com.example.web;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 判断上传的数据是否为多段数据
if(ServletFileUpload.isMultipartContent(req)){
// 2. 创建FileItemFactory工厂实现类
FileItemFactory fileItemFactory = new DiskFileItemFactory();
// 3. 创建用于解析上传数据的工具类ServletFileUpload类
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
try {
// 4. 解析上传的数据,得到每一个表单项FileItem
List<FileItem> fileItems = servletFileUpload.parseRequest(req);
// 5. 循环判断每一个表单项,是普通表单项还是文件表单项
for (FileItem fileItem : fileItems) {
if(fileItem.isFormField()){
// 普通表单项
System.out.println("表单项的name值:"+fileItem.getFieldName());
System.out.println("表单项的value值:"+fileItem.getString("UTF-8"));
}else {
// 文件表单项
System.out.println("表单项的name值:"+fileItem.getFieldName());
System.out.println("上传的文件名:"+fileItem.getName());
// 保存文件到服务器指定路径下
fileItem.write(new File("D:\\"+fileItem.getName()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2.3 文件上传的HTTP协议说明
说明:图中 “上传的文件的数据” 并没有显示出要上传的文件数据,是因为浏览器检测到是二进制流的文件数据,就不再展示在此处了(Chrome浏览器不展示,FireFox浏览器会展示上传的文件的二进制流数据)
2.4 JavaWeb实现文件下载
1. DownloadFileServlet
package com.example.web;
import org.apache.commons.io.IOUtils;
import sun.misc.BASE64Encoder;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
public class DownloadFileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、获取要下载的文件名(此处为了演示方便,写死在代码中)
String downloadFileName = "3.jpg";
//2、读取要下载的文件内容 (通过ServletContext对象可以读取)
ServletContext servletContext = getServletContext();
//3、获取要下载的文件类型
String mimeType = servletContext.getMimeType("/pages/file/" + downloadFileName);
System.out.println("下载的文件类型:" + mimeType);
//4、在回传前,通过响应头告诉客户端返回的数据类型
resp.setContentType(mimeType);
//5、还要告诉客户端收到的数据是用于下载使用(还是使用响应头来告诉客户端)
// Content-Disposition响应头,表示收到的数据怎么处理
// attachment表示附件,表示下载使用
// filename= 表示指定下载的文件名
// url编码是把汉字转换成为%xx%xx的格式
if (req.getHeader("User-Agent").contains("Firefox")) {
// 如果是火狐浏览器使用Base64编码
resp.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" + new BASE64Encoder().encode("中国.jpg".getBytes("UTF-8")) + "?=");
} else {
// 如果不是火狐,是IE或谷歌,使用URL编码操作
resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中国.jpg", "UTF-8"));
}
/**
* /斜杠被服务器解析表示地址为http://ip:prot/工程名/ 映射 到代码的Web目录
*/
InputStream resourceAsStream = servletContext.getResourceAsStream("/pages/file/" + downloadFileName);
// 获取响应的输出流
OutputStream outputStream = resp.getOutputStream();
//3、把下载的文件内容回传给客户端 ,读取输入流中全部的数据,复制给输出流,输出给客户端
IOUtils.copy(resourceAsStream, outputStream);
}
}
2. 文件下载的HTTP协议头
- 火狐浏览器
- 谷歌浏览器
3. SpringMVC实现文件上传下载
3.1 SpringMVC实现文件上传的步骤
- 在pom.xml文件中导入文件上传所需的jar包坐标
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
- 要求form表单提交方式为post,且添加属性enctype=multipartr/form-data
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试文件上传和下载</title>
</head>
<body>
<a th:href="@{/testDown}">通过ResponseEntity下载服务器中的文件到客户端</a><br/>
<form th:action="@{/testUp}" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"><br/>
头 像:<input type="file" name="photo"><br>
<input type="submit" value="上传">
</form>
</body>
</html>
- SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息,需要在SpringMVC的配置文件中添加如下配置:
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons."></bean>
- SpringMVC中的控制器方法
// 文件上传
@RequestMapping("/testUp")
public String testUp(MultipartFile photo,HttpSession session,String username) throws IOException {
// 可以通过控制器方法的形参获取普通表单项的内容
System.out.println("username = " + username);
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
System.out.println("fileName = " + fileName);
//处理文件重名问题
String hzName = fileName.substring(fileName.lastIndexOf("."));
System.out.println("hzName = " + hzName);
fileName = UUID.randomUUID() + hzName;
System.out.println("hzName = " + hzName);
//获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
System.out.println("photoPath = " + photoPath);
File file = new File(photoPath);
if(!file.exists()){
file.mkdir();
}
String finalPath = photoPath + File.separator + fileName;
System.out.println("finalPath = " + finalPath);
//实现上传功能,需要使用到 commons-fileupload-1.2.1.jar 及其所依赖的 commons-io-1.4.jar
photo.transferTo(new File(finalPath));
return "success";
}
// 文件下载
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
System.out.println("realPath = " + realPath);
//创建输入流
InputStream is = new FileInputStream(realPath);
//创建字节数组
//byte[] bytes = new byte[is.available()];
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream out = new ByteArrayOutputStream();
while ((len = is.read(buffer)) != -1){
out.write(buffer,0,len);
}
byte[] bytes = out.toByteArray();
//将流读到字节数组中
//is.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字
headers.add("Content-Disposition", "attachment;filename=1.jpg");
String mimeType = servletContext.getMimeType("/static/img/1.jpg");
headers.add("Content-Type",mimeType);
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}