Servlet实现文件上传和下载
- 文件上传
- 还是使用表单提交,action还是按照以前规定来指定,method指定为post
- enctype:encodetype编码类型默认是application/X-www-form-urlencoded即url编码这种编码不适二进制文件数据的提交,一股是适用文本
- 如果是要进行二进制文件的提交enctype要指定multipart/form-data表示表单提交的数据是有多个部分组成,也就是可以提交二进制数据和文本数据
- 文件上传的代码演示
- 前端部分
- 需要指定表单的类型为:"enctype=multipart/form-data",请求方式为post
<%--
Created by IntelliJ IDEA.
User: 韩顺平
Version: 1.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 指定了base标签 -->
<base href="<%=request.getContextPath()+"/"%>>">
<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");
//获取文件对象
var file = event.files[0];
//获取文件阅读器: Js的一个类,直接使用即可
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
//给img的src设置图片url
img.setAttribute("src", this.result);
}
}
</script>
</head>
<body>
<!-- 表单的enctype属性要设置为multipart/form-data
enctype="multipart/form-data" 表示提交的数据是多个部分构造,有文件和文本
-->
<form action="fileUpLoad" method="post" enctype="multipart/form-data">
家居图: <img src="2.jpg" alt="" width="200" height="200" id="prevView">
<%-- 小伙伴愿意完成自己测试--%>
<input type="file" name="pic" id="" value="" onchange="prev(this)"/>
家居名: <input type="text" name="name"><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
- 后端部分
- 通过ServletFileUpload类的isMultipartContent()方法进行判断是不是文件表单,通过判断进行分类处理
- 创建一个DiskFileItemFactory对象,用于构建解析表单的工具对象(ServletFileUpload)
- 处理乱码问题,将ServletFileUpload表单解析工具对象的编码设置为utf-8
- 通过ServletFileUpload对象的parseRequest()方法,将表单提交的每一个表单项都封装成一个FileItem对象,并返回一个存放所有表单项FileItem对象的List集合
- 使用FileItem对象的isFormField()方法判断表单项是文本,还是文件
- 通过FileItem对象的write()方法可以将文件拷贝到指定的目录下
- 防止文件名重复可以使用,"UUID+时间戳+源文件名"的方式命名文件
package com.hsp.servlet; /**
* @Projectname: fileupdown
* @Filename: ${NAME}
* @Author: 杨逸
* @Data:2023/4/16 16:18
* @Description: TODO
*/
import com.hsp.utils.WebUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public class FileUpLoadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.判断表单是否是文件表单
//使用ServletFileUpload类的isMultipartContent()方法进行判断
if (ServletFileUpload.isMultipartContent(request)) {
//2.创建一个DiskFileItemFactory对象,用于构建解析表单的工具对象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//3.创建一个ServletFileUpload工具对象,需要传入一个DiskFileItemFactory对象
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
//处理上传文件名是中文是的乱码问题
//设置表单解析工具的编码
servletFileUpload.setHeaderEncoding("utf-8");
try {
//4.使用ServletFileUpload工具对象的parseRequest()方法,
// 将表单提交的每一个表单项都封装成一个FileItem对象,
// 并返回一个存放所有表单项FileItem对象的List集合
List<FileItem> fileItemList = servletFileUpload.parseRequest(request);
//遍历对每一个表单项进行处理
for (FileItem fileItem : fileItemList) {
System.out.println(fileItem);
//判断该表单项是不是文本类型的,
if (fileItem.isFormField()) {//返回true,是文本
//获得文本的字符串
String string = fileItem.getString("utf-8");
System.out.println("文本内容" + string);
} else {//返回false,是文件类型的
//获得文件名
String name = fileItem.getName();
System.out.println("文件名=" + name);
//将上传的文件保存到指定的路径
String path = "/upload";
//获得项目的全路径
String contextPath = getServletContext().getRealPath(path);
//根据当前时间创建保存上传文件的目录
String date = WebUtils.getDate();
contextPath = contextPath +date;
//创建保存文件的目录
File file = new File(contextPath);
//判断目录是否已经存在
if (!file.exists()){
//如果不存在就创建
file.mkdirs();
}
//文件拷贝前,对文件名进行处理,解决文件名重复的问题
//通过"UUID+时间戳+源文件名"的拼接,防止因文件名重复导致文件被覆盖的问题
UUID uuid = UUID.randomUUID();
name = uuid + "_" + System.currentTimeMillis() + "_" +name;
//将上传的文件拷贝到指定的位置
String fileFullPath = contextPath + "/" +name;
fileItem.write(new File(fileFullPath));
// 返回响应信息
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("上传成功!");
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
} else {
}
}
}
- 文件下载
- 文件下载需要设置http的响应头,Content-Disposition:表示下载的数据的展示方式,比如是内联形式(网页形式或者网页一部分)或者是文件下载方式attachment,默认是网页的形式
- 总体思路:使用输入流读取要下载的资源,然后使用http响应的输出流返回给客户端
- 文件下载代码演示
- 前端部分
<%--
Created by IntelliJ IDEA.
User: 杨逸
Date: 2023/4/16
Time: 17:45
Version: 1.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件下载</title>
<base href="<%=getServletConfig().getServletContext().getContextPath()%>/ "/>
</head>
<body>
<h1>文件下载</h1>
<a href="fileDownload?name=1.png">下载图片</a><br><br>
<a href="fileDownload?name=韩顺平Java工程师课程-JavaWeb.pdf">下载JavaWeb基础笔记</a><br>
</body>
</html>
- 后端部分
- 下载文件需要给http响应设置context-type的MIME类型,
- 给http响应设置Content-Disposition,指定响应的显示形式
- 这里要考虑不同浏览器的编码问题,chrome浏览器是URL编码,firefox浏览器是BASE64
package com.hsp.servlet; /**
* @Projectname: fileupdown
* @Filename: ${NAME}
* @Author: 杨逸
* @Data:2023/4/16 17:47
* @Description: TODO
*/
import org.apache.commons.io.IOUtils;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Base64;
import static javax.xml.crypto.dsig.Transform.BASE64;
@WebServlet(name = "FileDownloadServlet", value = "/FileDownloadServlet")
public class FileDownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//在下载之前需要准备好要被下载的文件,保证out目录下有该资源
//设置编码
request.setCharacterEncoding("utf-8");
//获得请求下载的文件名
String name = request.getParameter("name");
//通过servletContext获得要下载文件的MIME类型
ServletContext servletContext = getServletContext();
String download = "/download";//保存下载资源的路径
String mimeType = servletContext.getMimeType(download + name);
//给http响应设置context-type的MIME类型,
response.setContentType(mimeType);
//给http响应设置Content-Disposition,指定响应的显示形式
//这里要考虑不同浏览器的编码问题
//firefox与其他的浏览器不太一样,需要单独设置
if (request.getHeader("User-Agent").contains("firefox")){
//如果是firefox浏览器,使用的是base64编码
Base64.Encoder encoder = Base64.getEncoder();
response.setHeader("Content-Dispositon","attachment;filename=?UTF-8?B" + encoder.encode(name.getBytes("utf-8"))+"?=");
}else {
//如果是其他浏览器,如chrome,ie,使用的是url编码
response.setHeader("Content-Dispositon","attachment;filename=" + URLEncoder.encode(name,"utf-8"));
}
//读取要下载的文件,准备返回给客户端
InputStream resourceAsStream = servletContext.getResourceAsStream(download +"/"+ name);
//获得用于返回数据的输出流,用于返回二进制数据
ServletOutputStream outputStream = response.getOutputStream();
//使用工具类,将输入流关联的文件,拷贝到输出流,并返回给客户端
IOUtils.copy(resourceAsStream,outputStream);//这里拷贝和返回一起完成
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}