Hutool多部分表单:文件上传处理方案
【免费下载链接】hutool 🍬A set of tools that keep Java sweet. 项目地址: https://gitcode.com/gh_mirrors/hu/hutool
还在为Java文件上传的复杂实现而头疼吗?Hutool提供了简洁高效的多部分表单(Multipart Form)处理方案,让你轻松应对各种文件上传场景。本文将深入解析Hutool的多部分表单处理机制,并提供完整的实战指南。
🎯 读完本文你将获得
- ✅ Hutool多部分表单的核心组件解析
- ✅ 文件上传的完整实现流程
- ✅ 上传配置的精细控制方法
- ✅ 服务器端文件接收处理方案
- ✅ 实战案例与最佳实践
📦 Hutool多部分表单核心组件
Hutool通过精心设计的组件体系来处理多部分表单数据,主要包含以下核心类:
| 组件类 | 功能描述 | 核心方法 |
|---|---|---|
MultipartFormData | 多部分表单数据解析器 | parseRequestStream(), getFile(), getParam() |
UploadFile | 上传文件对象封装 | write(), getFileInputStream(), delete() |
UploadSetting | 上传配置管理 | setMaxFileSize(), setMemoryThreshold() |
UploadFileHeader | 文件头部信息 | getFileName(), getContentType() |
组件关系流程图
🚀 客户端文件上传实现
基础文件上传示例
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.core.io.FileUtil;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class FileUploadClient {
/**
* 单文件上传 - 方法一:直接使用form方法
*/
public void uploadSingleFile() {
File file = FileUtil.file("d:\\face.jpg");
HttpResponse response = HttpRequest.post("http://localhost:8080/upload")
.form("file", file) // 文件参数
.form("description", "用户头像") // 普通参数
.form("category", "avatar") // 普通参数
.execute();
System.out.println("上传结果: " + response.body());
}
/**
* 单文件上传 - 方法二:使用Map构建表单
*/
public void uploadSingleFileWithMap() {
File file = FileUtil.file("d:\\face.jpg");
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("city", "北京");
paramMap.put("file", file);
paramMap.put("userId", 12345);
String result = HttpUtil.post("http://localhost:8080/upload", paramMap);
System.out.println("上传结果: " + result);
}
/**
* 多文件上传示例
*/
public void uploadMultipleFiles() {
File file1 = FileUtil.file("d:\\图片1.JPG");
File file2 = FileUtil.file("d:\\图片3.png");
HttpRequest request = HttpRequest.post("http://localhost:8080/upload")
.form("files", file1, file2) // 多个文件使用相同参数名
.form("fileType", "图片")
.form("uploader", "系统管理员");
HttpResponse response = request.execute();
System.out.println("多文件上传结果: " + response.body());
}
/**
* 带自定义头部的文件上传
*/
public void uploadWithCustomHeaders() {
File file = FileUtil.file("D:\\test\\data.xlsx");
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer token123");
headers.put("X-Request-ID", "req_001");
headers.put("md5", "file_md5_hash_value");
Map<String, Object> params = new HashMap<>();
params.put("fileName", file.getName());
params.put("file", file);
params.put("businessType", "EXCEL_IMPORT");
HttpRequest httpRequest = HttpRequest.post("http://api.example.com/upload")
.headerMap(headers, false)
.form(params);
HttpResponse httpResponse = httpRequest.execute();
System.out.println("带头部上传结果: " + httpResponse.body());
}
}
高级配置:分块上传与大文件处理
import cn.hutool.http.HttpRequest;
import cn.hutool.core.lang.Console;
public class AdvancedUploadExample {
/**
* 大文件分块上传配置
*/
public void chunkedUploadLargeFile() {
String url = "http://192.168.1.200:8888/api/upload/large";
HttpRequest httpRequest = HttpRequest.post(url)
.setChunkedStreamingMode(1024 * 1024) // 1MB分块大小
.form("file", new File("D:\\large_file.zip"))
.form("chunkSize", "1048576")
.form("totalChunks", "10");
HttpResponse response = httpRequest.execute();
Console.log("分块上传结果: {}", response.body());
}
/**
* 第三方服务上传示例(SM.MS图床)
*/
public void uploadToThirdPartyService() {
String token = "your_api_token_here";
String url = "https://sm.ms/api/v2/upload";
String result = HttpUtil.createPost(url)
.header("User-Agent", "YourApp/1.0")
.auth(token)
.form("smfile", FileUtil.file("d:/images/photo.png"))
.form("format", "json")
.execute()
.body();
Console.log("图床上传结果: {}", result);
}
}
🖥️ 服务器端文件接收处理
基于Hutool HTTP服务器的文件接收
import cn.hutool.http.HttpUtil;
import cn.hutool.http.server.SimpleServer;
import cn.hutool.core.net.multipart.UploadFile;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.lang.Console;
public class FileUploadServer {
public void startUploadServer() {
SimpleServer server = HttpUtil.createServer(8080)
// 文件上传处理端点
.addAction("/upload", (request, response) -> {
try {
// 检查是否为multipart表单
if (!request.isMultipart()) {
response.write(JSONUtil.toJsonStr("error": "非multipart表单"));
return;
}
// 获取上传的文件
UploadFile[] files = request.getMultipart().getFiles("file");
if (files == null || files.length == 0) {
response.write(JSONUtil.toJsonStr("error": "未找到上传文件"));
return;
}
// 处理每个上传的文件
for (UploadFile file : files) {
String originalFilename = file.getFileName();
String savePath = "uploads/" + originalFilename;
// 保存文件到指定目录
File savedFile = file.write(savePath);
Console.log("文件上传成功: {}", savedFile.getAbsolutePath());
Console.log("文件大小: {} bytes", file.size());
Console.log("文件类型: {}", file.getHeader().getContentType());
}
// 获取普通表单参数
String description = request.getMultipart().getParam("description");
String category = request.getMultipart().getParam("category");
// 返回成功响应
String result = JSONUtil.createObj()
.set("code", 200)
.set("message", "上传成功")
.set("fileCount", files.length)
.set("description", description)
.set("category", category)
.toString();
response.write(result, "application/json");
} catch (Exception e) {
response.write(JSONUtil.toJsonStr("error": "文件处理失败: " + e.getMessage()));
}
})
.start();
Console.log("文件上传服务器已启动在端口 8080");
}
}
完整的服务器端处理类
import cn.hutool.http.server.HttpServerRequest;
import cn.hutool.http.server.HttpServerResponse;
import cn.hutool.core.net.multipart.UploadFile;
import cn.hutool.core.net.multipart.UploadSetting;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.StrUtil;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class FileUploadHandler {
private static final String UPLOAD_DIR = "uploads";
private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
private static final String[] ALLOWED_EXTENSIONS = {"jpg", "jpeg", "png", "gif", "pdf", "txt"};
/**
* 处理文件上传请求
*/
public void handleFileUpload(HttpServerRequest request, HttpServerResponse response) {
try {
// 配置上传设置
UploadSetting uploadSetting = createUploadSetting();
// 解析multipart表单数据
var multipart = request.parseMultipart(uploadSetting);
// 验证和保存文件
Map<String, Object> result = processUploadedFiles(multipart);
// 返回处理结果
response.write(JSONUtil.toJsonStr(result), "application/json");
} catch (Exception e) {
response.write(JSONUtil.toJsonStr("error": "处理失败: " + e.getMessage()), "application/json");
}
}
/**
* 创建上传配置
*/
private UploadSetting createUploadSetting() {
UploadSetting setting = new UploadSetting();
setting.setMaxFileSize(MAX_FILE_SIZE);
setting.setMemoryThreshold(8192); // 8KB以下存内存
setting.setTmpUploadPath("temp_uploads");
setting.setFileExts(ALLOWED_EXTENSIONS);
setting.setAllowFileExts(true); // 只允许指定扩展名
return setting;
}
/**
* 处理上传的文件
*/
private Map<String, Object> processUploadedFiles(MultipartFormData multipart) throws Exception {
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "success");
// 处理文件参数
Map<String, UploadFile[]> fileMap = multipart.getFileMap();
if (!fileMap.isEmpty()) {
Map<String, Object> filesResult = new HashMap<>();
for (Map.Entry<String, UploadFile[]> entry : fileMap.entrySet()) {
String paramName = entry.getKey();
UploadFile[] files = entry.getValue();
for (int i = 0; i < files.length; i++) {
UploadFile file = files[i];
if (file != null && file.isUploaded()) {
String savePath = generateSavePath(file.getFileName());
File savedFile = file.write(savePath);
filesResult.put(paramName + "_" + i, Map.of(
"originalName", file.getFileName(),
"savedPath", savedFile.getAbsolutePath(),
"size", file.size(),
"contentType", file.getHeader().getContentType()
));
}
}
}
result.put("files", filesResult);
}
// 处理普通参数
Map<String, String[]> paramMap = multipart.getParamMap();
if (!paramMap.isEmpty()) {
result.put("params", paramMap);
}
return result;
}
/**
* 生成文件保存路径
*/
private String generateSavePath(String originalFilename) {
String timestamp = String.valueOf(System.currentTimeMillis());
String extension = FileUtil.extName(originalFilename);
String filename = StrUtil.format("{}_{}.{}",
FileUtil.mainName(originalFilename), timestamp, extension);
return UPLOAD_DIR + File.separator + filename;
}
}
⚙️ 高级配置与安全控制
上传安全配置表
| 配置项 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
maxFileSize | -1(无限制) | 10MB | 最大文件大小限制 |
memoryThreshold | 8KB | 64KB | 内存存储阈值 |
tmpUploadPath | 系统临时目录 | 自定义目录 | 临时文件存储路径 |
fileExts | null(所有类型) | 白名单列表 | 允许的文件扩展名 |
isAllowFileExts | true | true | true为白名单,false为黑名单 |
安全配置示例
import cn.hutool.core.net.multipart.UploadSetting;
public class SecurityConfigExample {
/**
* 安全的上传配置
*/
public UploadSetting createSecureUploadSetting() {
UploadSetting setting = new UploadSetting();
// 文件大小限制:最大10MB
setting.setMaxFileSize(10 * 1024 * 1024);
// 内存阈值:64KB以下文件存内存,以上存临时文件
setting.setMemoryThreshold(64 * 1024);
// 临时文件目录
setting.setTmpUploadPath("secure_uploads/temp");
// 只允许特定文件类型(白名单)
String[] allowedExtensions = {
"jpg", "jpeg", "png", "gif",
"pdf", "doc", "docx", "txt",
"xls", "xlsx", "zip", "rar"
};
setting.setFileExts(allowedExtensions);
setting.setAllowFileExts(true); // 白名单模式
return setting;
}
/**
* 图片专用上传配置
*/
public UploadSetting createImageUploadSetting() {
UploadSetting setting = new UploadSetting();
setting.setMaxFileSize(5 * 1024 * 1024); // 5MB
setting.setMemoryThreshold(128 * 1024); // 128KB
setting.setFileExts(new String[]{"jpg", "jpeg", "png", "gif", "webp"});
setting.setAllowFileExts(true);
return setting;
}
/**
* 文档专用上传配置
*/
public UploadSetting createDocumentUploadSetting() {
UploadSetting setting = new UploadSetting();
setting.setMaxFileSize(20 * 1024 * 1024); // 20MB
setting.setMemoryThreshold(256 * 1024); // 256KB
setting.setFileExts(new String[]{"pdf", "doc", "docx", "txt", "rtf"});
setting.setAllowFileExts(true);
return setting;
}
}
🔍 文件上传处理流程
完整的文件上传时序图
sequenceDiagram
participant Client as 客户端
【免费下载链接】hutool 🍬A set of tools that keep Java sweet. 项目地址: https://gitcode.com/gh_mirrors/hu/hutool
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



