You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中使用HttpClient获取文件上传进度并跨类调用

Tracking File Upload Progress with Apache HttpClient & Sharing It Across Classes

Absolutely, you can track file upload progress using a wrapper class for HttpEntity and a listener pattern to share that progress with other classes. Let's break this down step by step, adjusting your existing code to handle file uploads and add progress tracking.

Step 1: Define a Progress Listener Interface

First, create an interface so other classes can subscribe to progress updates. This decouples the progress tracking logic from your HttpClient code:

public interface UploadProgressListener {
    void onProgressUpdate(long bytesUploaded, long totalBytes);
}

Step 2: Create a Progress-Tracking Entity Wrapper

We'll wrap the HttpEntity (used for file uploads) to intercept the write operation and calculate progress. This class extends HttpEntityWrapper to override the write behavior:

import org.apache.http.HttpEntity;
import org.apache.http.entity.HttpEntityWrapper;
import java.io.IOException;
import java.io.OutputStream;

public class ProgressTrackingEntity extends HttpEntityWrapper {
    private final UploadProgressListener listener;

    public ProgressTrackingEntity(HttpEntity entity, UploadProgressListener listener) {
        super(entity);
        this.listener = listener;
    }

    @Override
    public void writeTo(OutputStream outstream) throws IOException {
        super.writeTo(new CountingOutputStream(outstream, listener, getContentLength()));
    }

    private static class CountingOutputStream extends OutputStream {
        private final OutputStream delegate;
        private final UploadProgressListener listener;
        private final long totalBytes;
        private long bytesWritten = 0;

        public CountingOutputStream(OutputStream delegate, UploadProgressListener listener, long totalBytes) {
            this.delegate = delegate;
            this.listener = listener;
            this.totalBytes = totalBytes;
        }

        @Override
        public void write(int b) throws IOException {
            delegate.write(b);
            bytesWritten++;
            listener.onProgressUpdate(bytesWritten, totalBytes);
        }

        @Override
        public void write(byte[] b) throws IOException {
            delegate.write(b);
            bytesWritten += b.length;
            listener.onProgressUpdate(bytesWritten, totalBytes);
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            delegate.write(b, off, len);
            bytesWritten += len;
            listener.onProgressUpdate(bytesWritten, totalBytes);
        }

        @Override
        public void flush() throws IOException {
            delegate.flush();
        }

        @Override
        public void close() throws IOException {
            delegate.close();
        }
    }
}

Step 3: Modify Your HttpClient Code for File Uploads & Progress Tracking

Your original code uses StringEntity for JSON payloads. For file uploads, we'll use MultipartEntityBuilder to create a multipart form, then wrap it with our ProgressTrackingEntity. Here's the updated method:

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;

public static SusResponseDTO uploadFileRequest(String url, File fileToUpload, Map<String, String> requestHeaders, UploadProgressListener progressListener) {
    CloseableHttpClient httpClient = null;
    HttpPost httpPost = null;
    CloseableHttpResponse response = null;
    SusResponseDTO susResponseDTO = null;

    try {
        httpClient = HttpClients.createDefault();
        httpPost = new HttpPost(url);

        // Build multipart entity for file upload
        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
        entityBuilder.addBinaryBody(
            "file", // Name of the file parameter expected by your server
            fileToUpload,
            ContentType.DEFAULT_BINARY,
            fileToUpload.getName()
        );
        HttpEntity originalEntity = entityBuilder.build();

        // Wrap the entity with our progress tracker
        HttpEntity progressTrackingEntity = new ProgressTrackingEntity(originalEntity, progressListener);
        httpPost.setEntity(progressTrackingEntity);

        // Add request headers
        for (final Entry<String, String> h : requestHeaders.entrySet()) {
            httpPost.addHeader(h.getKey(), h.getValue());
        }

        // Execute the upload request
        response = httpClient.execute(httpPost);

        if (response.getStatusLine().getStatusCode() != 200) {
            throw new SusException(FAILED_HTTP_ERROR_CODE + response.getStatusLine().getStatusCode());
        }

        // Parse response using your existing logic
        for (org.apache.http.Header header : response.getAllHeaders()) {
            if (header.getName().equals(SERVER) && header.getValue().contains(MASTER_SERVER)) {
                susResponseDTO = JsonUtils.jsonStreamToObject(response.getEntity().getContent(), SusResponseDTO.class);
                break;
            }
        }
        if (susResponseDTO == null) {
            HttpEntity entity = response.getEntity();
            String responseString = EntityUtils.toString(entity, DEFAULT_ENCODING);
            Map<String, String> map = JsonUtils.jsonToMap(responseString, Map.class);
            susResponseDTO = JsonUtils.jsonToObject(map.get(RESPONSE_ENTITY), SusResponseDTO.class);
        }

    } catch (final IOException e) {
        ExceptionLogger.logException(e, SuSClient.class);
        throw new SusException(e, SuSClient.class);
    } finally {
        IOUtils.safeClose(response);
        IOUtils.safeClose(httpClient);
    }
    return susResponseDTO;
}

Step 4: Use the Listener in Another Class

Any class can implement UploadProgressListener to receive real-time progress updates. For example, a monitoring class or UI component:

public class UploadProgressMonitor implements UploadProgressListener {
    @Override
    public void onProgressUpdate(long bytesUploaded, long totalBytes) {
        double progressPercentage = (bytesUploaded * 100.0) / totalBytes;
        System.out.printf("Upload Progress: %.2f%% (%d/%d bytes)%n", progressPercentage, bytesUploaded, totalBytes);
        
        // Here you can update UI elements, log progress to a file, or trigger other business logic
        // If updating UI, make sure to run on the UI thread (e.g., SwingUtilities.invokeLater() or Android's runOnUiThread())
    }
}

To use it, pass an instance of your listener when calling the upload method:

File targetFile = new File("/path/to/your/file.pdf");
Map<String, String> headers = Map.of("Authorization", "Bearer your-auth-token");
UploadProgressMonitor monitor = new UploadProgressMonitor();

SusResponseDTO uploadResponse = uploadFileRequest("https://your-upload-api.com/upload", targetFile, headers, monitor);

Key Notes

  • Thread Safety: If you're updating UI components from the listener, ensure those updates run on the UI thread to avoid concurrency issues.
  • Reusability: The ProgressTrackingEntity and UploadProgressListener are generic, so you can reuse them across all your file upload methods.
  • Error Handling: The listener tracks bytes written, but you still need to handle exceptions in the main HttpClient method as you already do.

内容的提问来源于stack exchange,提问作者Noman Arshad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:06:46