【问题标题】:HttpClient and upload progress - ProgressListener missingHttpClient 和上传进度 - 缺少 ProgressListener
【发布时间】:2011-07-16 06:44:02
【问题描述】:

我查看了 HttpClient 进度代码,但仍有一些问题无法找到答案 在哪里获取这个 ProgressListener 来放置构造函数参数?以及如何正确使用代码?请帮忙

这里是代码

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;

public class CountingMultipartEntity extends MultipartEntity {

    private final ProgressListener listener;

    public CountingMultipartEntity(final ProgressListener listener) {
        super();
        this.listener = listener;
    }

    public CountingMultipartEntity(final HttpMultipartMode mode, final ProgressListener listener) {
        super(mode);
        this.listener = listener;
    }

    public CountingMultipartEntity(HttpMultipartMode mode, final String boundary,
            final Charset charset, final ProgressListener listener) {
        super(mode, boundary, charset);
        this.listener = listener;
    }

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

    public static interface ProgressListener {
        void transferred(long num);
    }

    public static class CountingOutputStream extends FilterOutputStream {

        private final ProgressListener listener;
        private long transferred;

        public CountingOutputStream(final OutputStream out,
                final ProgressListener listener) {
            super(out);
            this.listener = listener;
            this.transferred = 0;
        }


        public void write(byte[] b, int off, int len) throws IOException {
            out.write(b, off, len);
            this.transferred += len;
            this.listener.transferred(this.transferred);
        }

        public void write(int b) throws IOException {
            out.write(b);
            this.transferred++;
            this.listener.transferred(this.transferred);
        }
    }
}

我可以实现这样的接口吗?

...
public static interface ProgressListener {
        void transferred(long num);
    }
    public static class Progress implements ProgressListener
    {

      public void transferred(long num) {
//            // update the progress bar or whatever else you might want to do

        }

    }
...

但是对于这个包含 HttpClient 的外部类,我该如何初始化 ProgressListener 呢?

CountingMultiPartEntity entity = new CountingMultiPartEntity(new ProgressListener() {

        public void transferred(long num) {
            // update the progress bar or whatever else you might want to do
        }
    });

【问题讨论】:

    标签: java file-io file-upload multifile-uploader


    【解决方案1】:

    如果您还没有任何实现ProgressListener 接口的类,您需要自己构建它。对于监听器之类的东西,这通常是通过匿名内部类来完成的。

    CountingMultipartEntity entity = new CountingMultipartEntity(new ProgressListener() {
        @Override
        public void transferred(long num) {
            // update the progress bar or whatever else you might want to do
        }
    });
    

    【讨论】:

    • 我想知道 ProgressListener 是什么库?因为我得到了 fileNotFound :( 我有 HttpClient 4
    • 对于 HttpClient,HttpMultipartMode 模式参数是什么意思?
    • 引用:“如果您还没有任何实现 ProgressListener 接口的类,您将需要自己构建它。对于侦听器之类的东西,这通常使用匿名内部实现班级。”我没有接口实现:(我从未见过这个领域的任何例子。你能告诉我吗?
    • 请告诉我如何构造 ProgressListener 实现,因为我对代码样式感到困惑 :( ProgressListener 是一个内部接口,所以我可以把它做成一个外部接口吗?我不明白......
    • 您发布的代码中已经定义了ProgressListener 接口。您可以使用普通的独立类、命名内部类或匿名内部类来实现它。有很多关于使用这些的文章,请参阅任何关于向 Swing 组件添加事件侦听器的文章。一个例子是download.oracle.com/javase/tutorial/uiswing/events/…
    【解决方案2】:

    您应该将 ProgressListener 导入到您要调用的类中

    import com.blahblah.YourProjectName.CustomMultipartEntity.ProgressListener;
    

    我正在使用一个名为“CustomMultipartEntity”的类似类,不要忘记更改它的名称。

    CustomMultipartEntity 类的实现是:

    package com.blahblah.YourProjectName;
    import java.io.FilterOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.nio.charset.Charset;
    import org.apache.http.entity.mime.HttpMultipartMode;
    import org.apache.http.entity.mime.MultipartEntity;
    public class CustomMultipartEntity extends MultipartEntity
    {
    
    
    private final ProgressListener listener;
    
    public CustomMultipartEntity(final ProgressListener listener)
    {
        super();
        this.listener = listener;
    }
    
    public CustomMultipartEntity(final HttpMultipartMode mode, final ProgressListener listener)
    {
        super(mode);
        this.listener = listener;
    }
    
    public CustomMultipartEntity(HttpMultipartMode mode, final String boundary, final Charset charset, final ProgressListener listener)
    {
        super(mode, boundary, charset);
        this.listener = listener;
    }
    
    @Override
    public void writeTo(final OutputStream outstream) throws IOException
    {
        super.writeTo(new CountingOutputStream(outstream, this.listener));
    }
    
    public static interface ProgressListener
    {
        void transferred(long num);
    }
    
    public static class CountingOutputStream extends FilterOutputStream
    {
    
        private final ProgressListener listener;
        private long transferred;
    
        public CountingOutputStream(final OutputStream out, final ProgressListener listener)
        {
            super(out);
            this.listener = listener;
            this.transferred = 0;
        }
    
        public void write(byte[] b, int off, int len) throws IOException
        {
            out.write(b, off, len);
            this.transferred += len;
            this.listener.transferred(this.transferred);
        }
    
        public void write(int b) throws IOException
        {
            out.write(b);
            this.transferred++;
            this.listener.transferred(this.transferred);
        }
    }
    }
    

    这是一个示例调用:

    CustomMultipartEntity reqEntity = new CustomMultipartEntity(new ProgressListener() {
    
                        public void transferred(long num) {
                            if((int) ((num / (float) totalSize) * 100) > 0)
                                progressHandler(num);
                        }
                    });
    

    【讨论】:

      【解决方案3】:

      我在这里找到了这个:https://www.baeldung.com/httpclient-post-http-request#get-file-upload-progress

      这个想法是,在您(通常)创建实体之后,将其包装到另一个实体中,同时指定一个侦听器对象,该对象将在字节传输到远程主机时收到通知。在基本示例中,此通知仅包含一个百分比(传输的字节数 / 总字节数 * 100),但您可以根据需要对其进行扩展。

      为了完整起见,这里是上面链接中列出的代码:

      你从一个界面开始:

      public interface ProgressListener {
          void progress(float percentage);
      }
      

      接下来是实体包装器:

      import org.apache.http.HttpEntity;
      import org.apache.http.entity.HttpEntityWrapper;
      
      public class ProgressEntityWrapper extends HttpEntityWrapper {
          private ProgressListener listener;
      
          public ProgressEntityWrapper(HttpEntity entity, ProgressListener listener) {
              super(entity);
              this.listener = listener;
          }
      
          @Override
          public void writeTo(OutputStream outstream) throws IOException {
              super.writeTo(new CountingOutputStream(outstream, listener, getContentLength()));
          }
      }
      

      最后你有了输出流,它可以跟踪进度:

      public class CountingOutputStream extends FilterOutputStream {
          private ProgressListener listener;
          private long transferred;
          private long totalBytes;
      
          public CountingOutputStream(
            OutputStream out, ProgressListener listener, long totalBytes) {
              super(out);
              this.listener = listener;
              transferred = 0;
              this.totalBytes = totalBytes;
          }
      
          @Override
          public void write(byte[] b, int off, int len) throws IOException {
              out.write(b, off, len);
              transferred += len;
              listener.progress(getCurrentProgress());
          }
      
          @Override
          public void write(int b) throws IOException {
              out.write(b);
              transferred++;
              listener.progress(getCurrentProgress());
          }
      
          private float getCurrentProgress() {
              return ((float) transferred / totalBytes) * 100;
          }
      }
      

      免责声明:以上内容只是从上述链接复制/粘贴。 (同时添加一些导入并删除 static 修饰符)

      这对我来说效果很好。请务必在响应中指定Content-Length 标头,否则totalBytes 的值将是-1,这将导致计算失败。

      专业提示:您可以通过发送更少的通知以牺牲精度为代价来稍微优化一下。我会尝试这样的事情:

      public CounterOutputStream(OutputStream out, ProgressListener listener, long totalBytes) {
          super(out);
          final ProgressListener xl = listener;
          this.listener = new ProgressListener() {
              private int p = 0;
      
              @Override
              public void progress(float percentage) {
                  if (Math.floor(percentage) > p) {
                      p = (int) percentage;
                      xl.progress(percentage);
                  }
              }
          };
          transferred = 0;
          this.totalBytes = totalBytes;
      }
      

      另一个免责声明:我还没有实际测试过CounterOutputStream的上述新版本的构造函数。

      您可以像这样使用所有这些:

      HttpEntity entity = MultipartEntityBuilder.create()
        .setMode(HttpMultipartMode.RFC6532)
        .addTextBody("Part1", "Some text", Constants.CT_U8_TEXT)
        .addTextBody("Part2", moreText, Constants.CT_U8_TEXT)
        .addTextBody("Part3", someVariable, Constants.CT_U8_TEXT)
        .build()
      ;
      
      // This instruction here:
      entity = new ProgressEntityWrapper(
        entity
        , percentage -> LOG.info("Upload at: " + percentage)
      );
      
      HttpUriRequest post = RequestBuilder
        .post(url)
        .setEntity(entity)
        .build()
      ;
      
      // etc...
      

      【讨论】:

        猜你喜欢
        • 2014-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-09
        • 2016-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多