泽西客户端上传进度

我有一个jersey客户端需要上传一个足够大的文件来要求进度条。
问题是,对于需要几分钟的上传,我看到一旦应用程序启动,转移的字节就会变为100%。 然后打印“完成”字符串需要几分钟。
就好像字节被发送到一个缓冲区,我正在读取transfert到缓冲区的速度而不是实际的上传速度 。 这使得进度条无用。

这是非常简单的代码:

ClientConfig config = new DefaultClientConfig(); Client client = Client.create(config); WebResource resource = client.resource("www.myrestserver.com/uploads"); WebResource.Builder builder = resource.type(MediaType.MULTIPART_FORM_DATA_TYPE); FormDataMultiPart multiPart = new FormDataMultiPart(); FileDataBodyPart fdbp = new FileDataBodyPart("data.zip", new File("data.zip")); BodyPart bp = multiPart.bodyPart(fdbp); String response = builder.post(String.class, multiPart); 

为了获得进度状态,我在调用builder.post之前添加了一个ContainerListenerfilter。

 final ContainerListener containerListener = new ContainerListener() { @Override public void onSent(long delta, long bytes) { System.out.println(delta + " : " + long); } @Override public void onFinish() { super.onFinish(); System.out.println("on finish"); } }; OnStartConnectionListener connectionListenerFactory = new OnStartConnectionListener() { @Override public ContainerListener onStart(ClientRequest cr) { return containerListener; } }; resource.addFilter(new ConnectionListenerFilter(connectionListenerFactory)); 

它应该足以为java.io.File提供自己的MessageBodyWriter,它会触发某些事件或通知某些侦听器进度发生变化

 @Provider() @Produces(MediaType.APPLICATION_OCTET_STREAM) public class MyFileProvider implements MessageBodyWriter { public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return File.class.isAssignableFrom(type); } public void writeTo(File t, Class type, Type genericType, Annotation annotations[], MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException { InputStream in = new FileInputStream(t); try { int read; final byte[] data = new byte[ReaderWriter.BUFFER_SIZE]; while ((read = in.read(data)) != -1) { entityStream.write(data, 0, read); // fire some event as progress changes } } finally { in.close(); } } @Override public long getSize(File t, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { return t.length(); } } 

并使您的客户端应用程序简单地使用此新提供程序:

 ClientConfig config = new DefaultClientConfig(); config.getClasses().add(MyFileProvider.class); 

要么

 ClientConfig config = new DefaultClientConfig(); MyFileProvider myProvider = new MyFileProvider (); cc.getSingletons().add(myProvider); 

您还必须包含一些算法来识别接收进度事件时传输的文件。

编辑:

我刚发现HTTPUrlConnection默认使用缓冲。 要禁用缓冲,您可以执行以下操作:

  1. httpUrlConnection.setChunkedStreamingMode(chunklength) – 禁用缓冲并使用分块传输编码发送请求
  2. httpUrlConnection.setFixedLengthStreamingMode(contentLength) – 禁用缓冲,但对流式传输一些约束:必须发送确切的字节数

所以我建议你的问题的最终解决方案使用第一个选项,看起来像这样:

 ClientConfig config = new DefaultClientConfig(); config.getClasses().add(MyFileProvider.class); URLConnectionClientHandler clientHandler = new URLConnectionClientHandler(new HttpURLConnectionFactory() { @Override public HttpURLConnection getHttpURLConnection(URL url) throws IOException { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setChunkedStreamingMode(1024); return connection; } }); Client client = new Client(clientHandler, config); 

在Jersey 2.X中,我使用了WriterInterceptor将输出流包装为Apache Commons IO CountingOutputStream的子类,该子类跟踪写入并通知我的上传进度代码(未显示)。

 public class UploadMonitorInterceptor implements WriterInterceptor { @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { // the original outputstream jersey writes with final OutputStream os = context.getOutputStream(); // you can use Jersey's target/builder properties or // special headers to set identifiers of the source of the stream // and other info needed for progress monitoring String id = (String) context.getProperty("id"); long fileSize = (long) context.getProperty("fileSize"); // subclass of counting stream which will notify my progress // indicators. context.setOutputStream(new MyCountingOutputStream(os, id, fileSize)); // proceed with any other interceptors context.proceed(); } } 

然后我在客户端注册了这个拦截器,或者在你想要使用拦截器的特定目标上注册了这个拦截器。