Hutool多部分表单:文件上传处理方案

Hutool多部分表单:文件上传处理方案

【免费下载链接】hutool 🍬A set of tools that keep Java sweet. 【免费下载链接】hutool 项目地址: 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()

组件关系流程图

mermaid

🚀 客户端文件上传实现

基础文件上传示例

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最大文件大小限制
memoryThreshold8KB64KB内存存储阈值
tmpUploadPath系统临时目录自定义目录临时文件存储路径
fileExtsnull(所有类型)白名单列表允许的文件扩展名
isAllowFileExtstruetruetrue为白名单,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. 【免费下载链接】hutool 项目地址: https://gitcode.com/gh_mirrors/hu/hutool

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值