<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="java.io.*,java.util.*,javax.servlet.*,javax.servlet.http.*" %> <%@ page import="java.rmi.ServerException" %> <%@ page import="java.nio.charset.Charset" %> <%@ page import="java.nio.charset.StandardCharsets" %> <% //定义上传文件的最大字节数,这里设置的数值是 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("

" + saveFile + "文件已经存在.

"); 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("文件上传成功"); } else { // 如果上传的数据类型不是 "multipart/form-data",则输出提示信息,告知用户需要上传该类型的文件 String content = request.getContentType(); out.print("上传的文件类型是" + content + "类型的,请上传目录mutipart/form-data类型的文件"); } } catch (Exception ex) { // 如果在文件上传过程中出现任何异常,捕获异常并抛出一个 ServerException,将原始异常的消息传递进去,方便在更上层进行统一的异常处理和日志记录等操作 throw new ServerException(ex.getMessage()); } %>