文章目录
文件上传下载
HTTP请求会包含一个请求头,其中"Content-Type"字段告诉服务器正在发送什么类型的数据。根据发送的数据类型,浏览器和服务器会采取适应的处理方式。
"multipart/form-data"是一种常见的POST数据提交的方式。当表单中使用文件上传字段时,经常需要使用这个值。表单以multipart/form-data方式发送的数据必须以一种特殊编码方式进行编码,使得多个部分可以作为一个整体发送。这种情况常出现在同时发送文件和其他表单数据时。
表单类型有三种常见的MIME类型:
- "application/x-www-form-urlencoded",这是默认类型,适合发送简单的文本数据。
- "multipart/form-data",适合发送包含所有类型的数据,包括文件数据。
- "text/plain",虽不常用,但有其特殊用途,用于发送未经编码的文本数据。
文件上传
在HTML表单中,如果要提交的数据包含文件类型(如:图片,文档等),"enctype"属性需要被设置为"multipart/form-data"。
1)导入依赖:
xml
<dependency>
<groupId>com.liferay</groupId>
<artifactId>org.apache.commons.fileupload</artifactId>
<version>1.2.2.LIFERAY-PATCHED-1</version>
</dependency>
2)前端界面:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>demo</title>
<style type="text/css">
input[type="submit"] {
outline: none;
border-radius: 5px;
cursor: pointer;
background-color: #31B0D5;
border: none;
width: 70px;
height: 35px;
font-size: 20px;
}
img {
border-radius: 50%;
}
form {
position: relative;
width: 200px;
height: 200px;
}
input[type="file"] {
position: absolute;
left: 0;
top: 0;
height: 200px;
opacity: 0;
cursor: pointer;
}
</style>
<script type="text/javascript">
function prev(event) {
//获取展示图片的区域
var img = document.getElementById("prevView");
//获取文件对象
let file = event.files[0];
//获取文件阅读器
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
//给 img 的 src 设置图片 url
img.setAttribute("src", this.result);
}
}
</script>
</head>
<body>
<!-- 表单的 enctype 属性要设置为 multipart/form-data -->
<form action="/zzz" enctype="multipart/form-data" method="post">
家居图: <img alt="" height="200" id="prevView" width="200">
<input id="" name="pic" onchange="prev(this)" type="file"/>
家居名: <input name="name" type="text"><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
3)后端接收并保存:
java
package com.lhs;
import org.apache.commons.fileupload.FileItem;
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.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
public class myServlet02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {
// 检查请求的enctype标头是否为multipart/form-data,这意味着请求包含上载的文件
if (ServletFileUpload.isMultipartContent(req)) {
// 创建一个新的文件项工厂和文件上传对象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
// 设置请求头的字符编码为UTF-8,解决中文乱码问题
servletFileUpload.setHeaderEncoding("utf-8");
try {
// 解析请求,将每个表单字段和文件作为单独的项目
List<FileItem> list = servletFileUpload.parseRequest(req);
System.out.println(list);
// 迭代这些项目
for (FileItem fileItem : list) {
// 查看项目是否是一个表单字段还是一个文件
if (!fileItem.isFormField()) {
// 定义要上传文件的路径
String filePath = "/upload/";
// 计算出文件应该被保存的绝对路径
String realPath = req.getServletContext().getRealPath(filePath);
System.out.println(realPath);
// 如果文件路径不存在,那么就创建文件路径
if (!Files.isDirectory(Path.of(realPath))) {
Files.createDirectory(Path.of(realPath));
}
// 获取文件的原名
String name = fileItem.getName();
// 指定文件的新名字,然后写入磁盘
fileItem.write(new File(realPath + "/" + UUID.randomUUID() + "_" + name));
// 设置响应类型和编码,然后将成功消息写入响应
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("上传成功");
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
System.out.println("不是表单");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4)文件按日期分组存储:
java
//获取当前本地日期
LocalDate localDate = LocalDate.now();
//从日期中获取年份
int year = localDate.getYear();
//从日期中获取月份
int month = localDate.getMonth().getValue();
//从日期中获得日期
int day = localDate.getDayOfMonth();
//通过年、月、日构造文件路径字符串
String filePath = "/upload/" + year + "/" + month + "/" + day + "/";
//获取此文件路径的真实路径
String realPath = req.getServletContext().getRealPath(filePath);
if (!Files.isDirectory(Path.of(realPath))) {
//创建该路径下的所有目录
Files.createDirectories(Path.of(realPath));
}
文件下载
在Http响应中,当Content-Disposition的值设置为"attachment",那么浏览器通常会尝试下载并保存的响应数据,而不是直接在浏览器中显示它。
1)前端界面:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>demo</title>
</head>
<body>
<h1>文件下载</h1>
<a href="/zzz?name=1.png">点击下载图片1</a><br/><br>
<a href="/zzz?name=2.png">点击下载图片2</a><br/><br>
</body>
</html>
2)将资源存放在web/download目录下
3)后端返回资源:
java
package com.lhs;
import org.apache.commons.io.IOUtils;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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.net.URLEncoder;
public class myServlet02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {
// 设置请求编码格式为utf-8
req.setCharacterEncoding("utf-8");
// 获取下载资源名
String name = req.getParameter("name");
// 构建文件的完整路径
String fullPath = "/download/" + name;
ServletContext servletContext = req.getServletContext();
// 获取文件的MIME类型
String mimeType = servletContext.getMimeType(fullPath);
// 设置响应的内容类型
resp.setContentType(mimeType);
// 设置响应头,使得浏览器接收到这个响应后,会下载文件,而不是直接打开
// filename参数指定下载后的文件名,这里需要进行URL编码,以防文件名有特殊字符
resp.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(name));
// 获取要下载的文件的输入流
InputStream resourceAsStream = servletContext.getResourceAsStream(fullPath);
// 获取响应的输出流
ServletOutputStream outputStream = resp.getOutputStream();
// 使用Apache的IOUtils工具类,把文件的输入流复制到响应输出流,实现文件下载
IOUtils.copy(resourceAsStream, outputStream);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}