wlzboy
2025-11-07 2aebbc9601ab439707f69b08e467808df9f7549c
ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
@@ -1,16 +1,10 @@
package com.ruoyi.common.utils.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
@@ -33,6 +27,43 @@
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
    public static final int DEFAULT_READ_TIMEOUT = 60000;
    private static final String BOUNDARY_PREFIX = "----WebKitFormBoundary";
    private static final String LINE_END = "\r\n";
    private static final String TWO_HYPHENS = "--";
    /**
     * 生成唯一的boundary
     */
    private static String generateBoundary() {
        return BOUNDARY_PREFIX + System.currentTimeMillis();
    }
    /**
     * 根据文件名获取Content-Type
     */
    private static String getContentType(String fileName) {
        if (fileName == null) {
            return "application/octet-stream";
        }
        String extension = fileName.toLowerCase();
        if (extension.endsWith(".jpg") || extension.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (extension.endsWith(".png")) {
            return "image/png";
        } else if (extension.endsWith(".gif")) {
            return "image/gif";
        } else if (extension.endsWith(".pdf")) {
            return "application/pdf";
        } else if (extension.endsWith(".doc")) {
            return "application/msword";
        } else if (extension.endsWith(".docx")) {
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        } else {
            return "application/octet-stream";
        }
    }
    /**
     * 向指定 URL 发送GET方法的请求
@@ -299,4 +330,138 @@
            return true;
        }
    }
    /**
     * 发送文件上传请求
     *
     * @param url 请求URL
     * @param params 请求参数(包含文件流)
     * @return 响应内容
     */
    public static String postFile(String url, Map<String, Object> params) {
        return postFile(url, params, null);
    }
    /**
     * 发送文件上传请求(支持自定义文件名)
     *
     * @param url 请求URL
     * @param params 请求参数(包含文件流)
     * @param fileName 文件名(可选,如果为null则使用参数键名)
     * @return 响应内容
     */
    public static String postFile(String url, Map<String, Object> params, String fileName) {
        HttpURLConnection connection = null;
        try {
            // 生成唯一的boundary
            String boundary = generateBoundary();
            log.info("开始文件上传 - URL: {}, fileName: {}, boundary: {}", url, fileName, boundary);
            log.info("参数数量: {}", params.size());
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                log.info("参数: {} = {}", entry.getKey(), entry.getValue() instanceof InputStream ? "InputStream" : entry.getValue());
            }
            // 创建连接
            URL requestUrl = new URL(url);
            connection = (HttpURLConnection) requestUrl.openConnection();
            // 设置请求属性
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Accept-Charset", "utf-8");
            connection.setConnectTimeout(30000);
            connection.setReadTimeout(60000);
            // 构建请求体
            try (OutputStream outputStream = connection.getOutputStream();
                 PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true)) {
                // 写入普通参数
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    Object value = entry.getValue();
                    if (!(value instanceof InputStream)) {
                        writer.append(TWO_HYPHENS).append(boundary).append(LINE_END);
                        writer.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"").append(LINE_END);
                        writer.append("Content-Type: text/plain; charset=UTF-8").append(LINE_END);
                        writer.append(LINE_END);
                        writer.append(value.toString()).append(LINE_END);
                        writer.flush();
                    }
                }
                // 写入文件参数
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    Object value = entry.getValue();
                    if (value instanceof InputStream) {
                        // 确定文件名
                        String actualFileName = fileName != null ? fileName : entry.getKey();
                        writer.append(TWO_HYPHENS).append(boundary).append(LINE_END);
                        writer.append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"; filename=\"").append(actualFileName).append("\"").append(LINE_END);
                        writer.append("Content-Type: ").append(getContentType(actualFileName)).append(LINE_END);
                        writer.append(LINE_END);
                        writer.flush();
                        // 写入文件内容
                        try (InputStream inputStream = (InputStream) value) {
                            byte[] buffer = new byte[4096];
                            int bytesRead;
                            while ((bytesRead = inputStream.read(buffer)) != -1) {
                                outputStream.write(buffer, 0, bytesRead);
                            }
                            outputStream.flush();
                        }
                        writer.append(LINE_END);
                        writer.flush();
                    }
                }
                // 写入结束标记
                writer.append(TWO_HYPHENS).append(boundary).append(TWO_HYPHENS).append(LINE_END);
                writer.flush();
            }
            // 获取响应
            int responseCode = connection.getResponseCode();
            log.info("文件上传响应码:{}", responseCode);
            // 读取响应内容
            StringBuilder response = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(
                            responseCode == HttpURLConnection.HTTP_OK ?
                                    connection.getInputStream() :
                                    connection.getErrorStream(),
                            StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
            }
            if (responseCode != HttpURLConnection.HTTP_OK) {
                log.error("文件上传失败,响应码:{},响应内容:{}", responseCode, response.toString());
                throw new RuntimeException("文件上传失败,响应码: " + responseCode + ",响应内容: " + response.toString());
            }
            log.info("文件上传成功,响应:{}", response.toString());
            return response.toString();
        } catch (Exception e) {
            log.error("文件上传异常:{}", e.getMessage(), e);
            throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
}