<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
</head>
<body>
<form action="/fileUpload"method="post"enctype="multipart/form-data">
<p>账号:<input type="text" name="username"/></p>
<p>头像:<input type="file" name="headImg"/></p>
<input type="submit" value="注册">
</form>
</body>
</html>
【结果预览】:
返回值 | 方法 | 作用 |
---|---|---|
Part | getPart(String name) | 用于获取请求中指定name文件 |
Collection | getParts() | 获取请求中的全部文件 |
返回值 | 方法 | 作用 |
---|---|---|
void | write(String fileName) | 直接把接收到的文件保存到磁盘中 |
void | getContentType() | 获取文件的类型 MIME |
String | getHeader(String name) | 获取请求头信息 |
long | getSize() | 获取文件的大小 |
package cn.simplelife.work._01fileupload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Collection;
import java.util.Scanner;
import java.util.UUID;
/**
* @ClassName FileUploadServlet
* @Description
* @Author simplelife
* @Date 2022/10/28 10:53
* @Version 1.0
*/
@MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
@WebServlet(value = "/register")
public class FileUploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1、上传文件的基本使用
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
// 获取文件
Part headImg = req.getPart("headImg");
// 获取文件提交时的名称
String submittedFileName = headImg.getSubmittedFileName();
// 将文件写入到指定的目录下的文件中
headImg.write("F:\\JavaWeb\\javaweb\\day18\\web\\upload\\" + submittedFileName);
}
}
返回值 | 方法 | 作用 |
---|---|---|
String | getHeader(“contentdisposition”) | Tocmat 8.0 之前使用通过请求头获取文件名,需截取字符串 |
String | getSubmittedFileName() | Tomcat8.0 之后提供的直接获取文件名方式 |
【问题概述】: 若上传得文件名相同会导致覆盖服务器之前已上传的的文件。
【解决方案】: 使用唯一的文件名称作为上传后的文件名称。我们使用UUID来做。
【代码演示】:
package cn.simplelife.work._01fileupload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Collection;
import java.util.Scanner;
import java.util.UUID;
/**
* @ClassName FileUploadServlet
* @Description
* @Author simplelife
* @Date 2022/10/28 10:53
* @Version 1.0
*/
@MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
@WebServlet(value = "/register")
public class FileUploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 2、生成唯一的文件名称----->防止用户上传相同的文件名称覆盖掉之前的文件信息
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
// 获取文件
Part headImg = req.getPart("headImg");
// 获取提交时的文件名称
String submittedFileName = headImg.getSubmittedFileName();
// 生成唯一的文件名称
String filenamePre = UUID.randomUUID().toString();
// 获取文件的拓展名称
String substring = submittedFileName.substring(submittedFileName.lastIndexOf("."));
// 保存文件名称
String realName = filenamePre + substring;
// 保存文件到磁盘
headImg.write("F:\\JavaWeb\\javaweb\\day18\\web\\upload\\" + realName);
}
}
【问题概述】: 文件在磁盘某个位置,不在项目下,无法使用 HTTP 协议访问,所以要把用户上传的文件存放到项目中才可通过 HTTP 协议来访问,且保存的位置路径不可以写绝对路径。
【解决方法】: 可以通过ServletContext 对象的 getRealPath(“项目中保存上传文件的文件夹的相对路径”) 来获取其的绝对路径。
【代码演示】:
package cn.simplelife.work._01fileupload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Collection;
import java.util.Scanner;
import java.util.UUID;
/**
* @ClassName FileUploadServlet
* @Description
* @Author simplelife
* @Date 2022/10/28 10:53
* @Version 1.0
*/
@MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
@WebServlet(value = "/register")
public class FileUploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 3、文件保存位置的问题
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
// 获取文件
Part headImg = req.getPart("headImg");
// 获取文件提交时的文件名称
String submittedFileName = headImg.getSubmittedFileName();
// 生成唯一的文件名称
String realName = UUID.randomUUID().toString() + submittedFileName.substring(submittedFileName.lastIndexOf("."));
// 自动获取项目路径的根路径,然后拼接上给的路径
String baseDir = req.getServletContext().getRealPath("/upload/");
// 将上传的文件写入文件
headImg.write(baseDir + realName);
}
}
【问题概述】: 限制用户恶意上传文件,比如要让用户上传头像,而用户却上传一个非图片文件,比如 JSP 文件。
【解决方案】: 判断用户上传的文件的类型是否符合需要的文件类型。
【代码演示】:
package cn.simplelife.work._01fileupload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Collection;
import java.util.Scanner;
import java.util.UUID;
/**
* @ClassName FileUploadServlet
* @Description
* @Author simplelife
* @Date 2022/10/28 10:53
* @Version 1.0
*/
@MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
@WebServlet(value = "/register")
public class FileUploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 4、文件上传类型约束
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
// 获取文件
Part headImg = req.getPart("headImg");
// 判断文件的类型是否为图片类型,不是图片类型不上传
if (headImg.getContentType().startsWith("image/")) {
// 获取文件上传时的名称
String submittedFileName = headImg.getSubmittedFileName();
// 生成唯一的文件名称
String realName = UUID.randomUUID().toString() + submittedFileName.substring(submittedFileName.lastIndexOf("."));
// 自动获取文件的根路径
String baseDir = getServletContext().getRealPath("/upload/");
// 将上传的文件写入文件
headImg.write(baseDir + realName);
}
}
}
【问题说明】: 文件上传限制大小可提高服务器硬盘的使用率,防止用户恶意上传文件造成服务器磁盘资源紧张。
**【解决方案】:**可以通过设置 @MutipartConfig 的属性做限制
【代码演示】:
package cn.simplelife.work._01fileupload;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Collection;
import java.util.Scanner;
import java.util.UUID;
/**
* @ClassName FileUploadServlet
* @Description
* @Author simplelife
* @Date 2022/10/28 10:53
* @Version 1.0
*/
@MultipartConfig(maxFileSize = 1024 * 500, maxRequestSize = 1024 * 500)
@WebServlet(value = "/register")
public class FileUploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 5、文件上传大小的限制
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
try {
// 获取上传的文件 ---多个文件
Collection<Part> parts = req.getParts();
// 遍历多个文件
for (Part part : parts) {
// 获取每一个文件的文件名称
String contentType = part.getContentType();
if (contentType != null && contentType.startsWith("image/")) {
// 获取每一个文件上传的文件名称
String submittedFileName = part.getSubmittedFileName();
// 生成唯一的文件名称
String realName = UUID.randomUUID().toString() + submittedFileName.substring(submittedFileName.lastIndexOf("."));
// 获取保存的根路径
String baseDir = req.getServletContext().getRealPath("/upload/");
// 写入文件
part.write(baseDir + realName);
}
}
} catch (Exception e) {
e.printStackTrace();
req.setAttribute("error", "亲,文件太大了!");
req.getRequestDispatcher("/register.jsp").forward(req, resp);
}
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/download/cat.png">猫</a>
<a href="${pageContext.request.contextPath}/download/cat.rar">猫</a>
</body>
</html>
【问题概述】: 下载功能已经实现,但是文件放在 WEB-INF 外面不安全,用户只需要拿到下载的超链接都能够下载,实际开发中,我们的文件通常需要用户有一定的权限才能下载。
【解决方法】:
【代码演示】:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/download?fileName=cat.png">猫</a>
<a href="${pageContext.request.contextPath}/download?fileName=cat.rar">猫</a>
</body>
</html>
package cn.simplelife.work._02filedownload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* @ClassName FileDownLoad
* @Description
* @Author simplelife
* @Date 2022/10/28 16:09
* @Version 1.0
*/
@WebServlet(value = "/download")
public class FileDownLoad extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接收用户要下载的文件名称
req.setCharacterEncoding("utf-8");
String fileName = req.getParameter("fileName");
//在响应之前做其他操作
System.out.println("扣钱");
//在项目下找到文件并响应给用户
String realPath = req.getServletContext().getRealPath("/WEB-INF/download/");
// 使用工具类 Files 的 copy 方法获取文件输入流,响应回浏览器
Files.copy(Paths.get(realPath, fileName), resp.getOutputStream());
}
}
【问题概述】: Tomcat 服务器未告知浏览器文件的名称,所以需要手动设置响应头来告知浏览器文件名称。
【代码演示】:
package cn.simplelife.work._02filedownload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* @ClassName FileDownLoad
* @Description
* @Author simplelife
* @Date 2022/10/28 16:09
* @Version 1.0
*/
@WebServlet(value = "/download")
public class FileDownLoad extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接收用户要下载的文件名称
req.setCharacterEncoding("utf-8");
String fileName = req.getParameter("fileName");
//在响应之前做其他操作
System.out.println("扣钱");
//在项目下找到文件并响应给用户
String realPath = req.getServletContext().getRealPath("/WEB-INF/download/");
// 获取浏览器类型
String header = req.getHeader("User-Agent");
// 根据浏览器类型设置文件下载的名称
String name = header.contains("MSIE") ? URLEncoder.encode(fileName, StandardCharsets.UTF_8) : new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
resp.setHeader("Content-Disposition", "attachment;filename=" + name);
//复制文件
//Paths.get(realPath, fileName) 获取到文件的真实路径
//Files.copy(Path,输出流)
Files.copy(Paths.get(realPath, fileName), resp.getOutputStream());
}
}