|
|
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
|
|
<!-- JSP 页面指令,设置页面内容类型为 HTML,字符编码为 UTF-8,表明该页面使用 Java 语言编写 -->
|
|
|
<%@ page import="java.io.*,java.util.*,javax.servlet.*,javax.servlet.http.*" %>
|
|
|
<!-- 导入多个 Java 相关的包,用于处理输入输出、集合操作、Servlet 相关功能以及 HTTP 相关功能等,方便后续代码中使用这些类和接口 -->
|
|
|
<%@ page import="java.rmi.ServerException" %>
|
|
|
<!-- 导入用于处理服务器端异常的类,可能用于在出现问题时抛出合适的异常信息 -->
|
|
|
<%@ page import="java.nio.charset.Charset" %>
|
|
|
<%@ page import="java.nio.charset.StandardCharsets" %>
|
|
|
<!-- 导入字符编码相关的类和标准字符编码常量,用于处理字符编码转换等操作,比如后续将字节数组转换为字符串时指定编码 -->
|
|
|
|
|
|
<html>
|
|
|
<head>
|
|
|
<title></title>
|
|
|
</head>
|
|
|
<body>
|
|
|
<%
|
|
|
//定义上传文件的最大字节数,这里设置的数值是 102400 * 102400 字节(不过这个数值看起来可能过大,也许是示例或特殊需求,通常会根据实际情况合理设置大小限制)
|
|
|
int MAX_SIZE = 102400 * 102400;
|
|
|
//创建根路径的保存变量,后续用于拼接出文件上传后的保存路径,初始时只是声明,还未赋值具体内容
|
|
|
String rootPath;
|
|
|
//声明文件读入类,用于从请求流中读取上传的数据,初始化为 null,后续会在合适的逻辑中进行实例化
|
|
|
DataInputStream in = null;
|
|
|
//声明文件输出流类,用于将上传的数据写入到服务器端的文件中,初始化为 null,后续会在合适的逻辑中进行实例化
|
|
|
FileOutputStream fileOut = null;
|
|
|
//取得互联网程序(即当前 Servlet 上下文对应的应用程序)的绝对地址,例如获取到类似项目部署在服务器上的根目录路径
|
|
|
String realPath = request.getSession().getServletContext().getRealPath("/");
|
|
|
//对获取到的绝对路径进行处理,截取掉其中 "\out" 及之后的部分,可能是为了获取到项目更合适的基础路径(具体取决于项目结构和需求)
|
|
|
realPath = realPath.substring(0, realPath.indexOf("\\out"));
|
|
|
// out.print(realPath);
|
|
|
// 创建文件的保存目录,将处理后的路径与 "\web\upload\" 拼接起来,形成文件最终要保存的目录路径,这里假设项目中有这样一个用于存放上传文件的目录结构
|
|
|
rootPath = realPath + "\\web\\upload\\";
|
|
|
//取得客户端上传的数据类型,例如判断是否是 "multipart/form-data" 这种常见的文件上传类型的数据格式
|
|
|
String contentType = request.getContentType();
|
|
|
try {
|
|
|
// 判断客户端上传的数据类型是否是 "multipart/form-data",如果是则进行文件上传相关的处理逻辑
|
|
|
if (contentType.indexOf("multipart/form-data") >= 0) {
|
|
|
// 读入上传数据,通过从请求输入流创建 DataInputStream 对象,以便按字节读取客户端上传的数据
|
|
|
in = new DataInputStream(request.getInputStream());
|
|
|
// 获取上传数据的总长度(字节数),用于后续循环读取数据以及判断是否超过设定的最大字节限制
|
|
|
int formDataLength = request.getContentLength();
|
|
|
// 检查上传的数据长度是否超过了预先定义的最大字节数,如果超过则输出提示信息并终止当前方法执行(直接返回)
|
|
|
if (formDataLength > MAX_SIZE) {
|
|
|
out.print("上传的字节不可以超过" + MAX_SIZE + "字节");
|
|
|
return;
|
|
|
}
|
|
|
// 保存上传文件的数据,创建一个字节数组,大小为上传数据的总长度,用于存放从请求中读取到的字节数据
|
|
|
byte dataBytes[] = new byte[formDataLength];
|
|
|
int byteRead = 0;
|
|
|
int totalBytesRead = 0;
|
|
|
// 上传的数据保存在 byte 数组里面,通过循环从输入流中读取数据,每次读取一部分字节,直到读取完所有上传的数据
|
|
|
while (totalBytesRead < formDataLength) {
|
|
|
byteRead = in.read(dataBytes, totalBytesRead, formDataLength);
|
|
|
totalBytesRead += byteRead;
|
|
|
}
|
|
|
// 根据 byte 数组创建字符串,使用指定的 UTF-8 编码将字节数组转换为字符串,方便后续对上传数据内容进行字符串相关的操作(比如提取文件名等信息)
|
|
|
String file = new String(dataBytes, StandardCharsets.UTF_8);
|
|
|
// 取得上传数据的文件名,通过对转换后的字符串进行一系列的截取操作,从包含文件名信息的字符串中提取出真正的文件名(处理了包含文件名的特定格式字符串)
|
|
|
String saveFile = file.substring(file.indexOf("filename=\"") + 10);
|
|
|
saveFile = saveFile.substring(0, saveFile.indexOf("\n"));
|
|
|
saveFile = saveFile.substring(saveFile.lastIndexOf("\\") + 1, saveFile.indexOf("\""));
|
|
|
int lastIndex = contentType.lastIndexOf("=");
|
|
|
// 取得数据的分隔字符串,从上传数据的类型字符串(例如 "multipart/form-data; boundary=----WebKitFormBoundaryxxx")中提取出用于分隔不同部分的边界字符串(boundary)
|
|
|
String boundary = contentType.substring(lastIndex + 1, contentType.length());
|
|
|
// 创建保存路径的文件名,将前面确定的文件保存目录路径与提取出的文件名拼接起来,形成完整的文件保存路径(包含文件名和目录)
|
|
|
String fileName = rootPath + saveFile;
|
|
|
int pos;
|
|
|
pos = file.indexOf("filename = \"");
|
|
|
pos = file.indexOf("\n", pos) + 1;
|
|
|
pos = file.indexOf("\n", pos) + 1;
|
|
|
pos = file.indexOf("\n", pos) + 1;
|
|
|
int boundaryLocation = file.indexOf(boundary, pos) - 4;
|
|
|
// 取得文件数据的开始的位置,通过对文件内容字符串进行一系列操作,先获取相关子字符串,再计算其字节长度来确定文件数据在整个上传数据中的起始位置
|
|
|
int startPos = ((file.substring(0, pos)).getBytes()).length;
|
|
|
int endPos = ((file.substring(0, boundaryLocation)).getBytes()).length;
|
|
|
File checkFile = new File(fileName);
|
|
|
// 检查要保存的文件是否已经存在,如果存在则输出提示信息并终止当前方法执行(直接返回)
|
|
|
if (checkFile.exists()) {
|
|
|
out.println("<p>" + saveFile + "文件已经存在.</p>");
|
|
|
return;
|
|
|
}
|
|
|
// 检查上传文件的目录是否存在,如果不存在则创建该目录(包括上级目录等,会递归创建),确保文件保存的目录是存在的
|
|
|
File fileDir = new File(rootPath);
|
|
|
if (!fileDir.exists()) {
|
|
|
fileDir.mkdirs();
|
|
|
}
|
|
|
// 创建文件的输出类,通过指定文件保存路径实例化 FileOutputStream,用于将上传的数据写入到对应的文件中
|
|
|
fileOut = new FileOutputStream(fileName);
|
|
|
// 保存文件的数据,将之前读取到的字节数组中对应文件数据部分写入到文件输出流中,实现文件在服务器端的保存
|
|
|
fileOut.write(dataBytes, startPos, (endPos - startPos));
|
|
|
fileOut.close();
|
|
|
out.print("<b>文件上传成功</b>");
|
|
|
} else {
|
|
|
// 如果上传的数据类型不是 "multipart/form-data",则输出提示信息,告知用户需要上传该类型的文件
|
|
|
String content = request.getContentType();
|
|
|
out.print("上传的文件类型是" + content + "类型的,请上传目录mutipart/form-data类型的文件");
|
|
|
}
|
|
|
} catch (Exception ex) {
|
|
|
// 如果在文件上传过程中出现任何异常,捕获异常并抛出一个 ServerException,将原始异常的消息传递进去,方便在更上层进行统一的异常处理和日志记录等操作
|
|
|
throw new ServerException(ex.getMessage());
|
|
|
}
|
|
|
%>
|
|
|
</body>
|
|
|
</html> |