文章目录
- 文件上传下载
- 文件上传
- 文件下载
文件上传下载
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)导入依赖:
<dependency><groupId>com.liferay</groupId><artifactId>org.apache.commons.fileupload</artifactId><version>1.2.2.LIFERAY-PATCHED-1</version>
</dependency>
2)前端界面:
<!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 设置图片 urlimg.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)后端接收并保存:
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 {@Overrideprotected 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("不是表单");}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
4)文件按日期分组存储:
//获取当前本地日期
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)前端界面:
<!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)后端返回资源:
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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception {// 设置请求编码格式为utf-8req.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);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}