2012-07-20 23 views
7

मेरे पास एक जर्सी क्लाइंट है जिसे प्रगति पट्टी की आवश्यकता के लिए पर्याप्त फ़ाइल अपलोड करने की आवश्यकता है।
समस्या यह है कि, अपलोड के लिए कुछ मिनटों की आवश्यकता होती है, मुझे लगता है कि जैसे ही एप्लिकेशन शुरू हो गया है, मुझे बाइट्स 100% पर स्थानांतरित करने के लिए स्थानांतरित किया गया है। फिर "समाप्त" स्ट्रिंग को मुद्रित करने में कुछ मिनट लगते हैं।
ऐसा लगता है जैसे बाइट को बफर में भेजा गया था, और मैं वास्तविक अपलोड गति की बजाय ट्रांसफर-टू-द बफर गति पढ़ रहा था। इससे प्रगति पट्टी बेकार हो जाती है।
जर्सी क्लाइंट अपलोड प्रगति

यह बहुत ही सरल कोड है:

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); 

प्रगति राज्य प्राप्त करने के लिए मैं एक ContainerListener फिल्टर जोड़ दिया है, obviouslt बुला builder.post से पहले:

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)); 

उत्तर

3

यह प्रदान करने के लिए पर्याप्त होना चाहिए java.io.File के लिए आपके पास MessageBodyWriter है जो कुछ घटनाओं को आग लगती है या कुछ श्रोताओं को प्रगति के रूप में सूचित करती है

@Provider() 
@Produces(MediaType.APPLICATION_OCTET_STREAM) 
public class MyFileProvider implements MessageBodyWriter<File> { 

    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<String, Object> 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 द्वारा बफरिंग का उपयोग करता है। अक्षम कर देता है बफरिंग और अनुरोध भेजने के लिए

  • httpUrlConnection.setFixedLengthStreamingMode (ContentLength) chunked स्थानांतरण एन्कोडिंग का उपयोग करता - - अक्षम कर देता है बफरिंग और लेकिन विज्ञापन कुछ

    1. httpUrlConnection.setChunkedStreamingMode (chunklength): और बफरिंग आप चीजों की जोड़ी कर सकता है निष्क्रिय करने के लिए स्ट्रीमिंग के लिए की कमी: बाइट्स की सही संख्या

    भेजा जाना चाहिए तो मेरा सुझाव है आपकी समस्या का अंतिम समाधान 1 विकल्प का उपयोग करता है और इस प्रकार दिखाई देगा:

    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); 
    
  • +0

    धन्यवाद टॉमसज़, यह उत्तर बहुत अच्छा है। तथ्य यह है कि आपने क्लाइंट को कॉन्फ़िगर करने के दो तरीके प्रदान किए हैं वास्तव में सराहनीय और स्पष्टीकरणपूर्ण है। दुर्भाग्य से, समस्या बनी रहती है। मैंने system.out.println (...) को entityStream.write के बाद बस रखा है, लेकिन नतीजा यह है कि मैं दूसरी फाइलों में बड़ी फ़ाइलों (> 10 एमबी) लिखता हूं, और फिर "असली" अपलोड होने पर यह जम जाता है।तथ्य यह है कि इस समाधान के साथ भी होता है कि समस्या कहीं और है। आपके उत्तर के लिए, मैं इसे स्वीकार नहीं कर सकता लेकिन मैं एक और विशिष्ट प्रश्न शुरू कर सकता हूं जहां मुझे इसे सही के रूप में चिह्नित करने में खुशी होगी। :-) – AgostinoX

    +0

    मैंने एक इकाई को जोड़ने की कोशिश की Stream.flush(); EntstStream.write (...) के बाद बस बफर पर लिखने के बजाय सॉकेट में वास्तविक लेखन को मजबूर करने के लिए। वही परिणाम :-( – AgostinoX

    +0

    ठीक है, अच्छा जवाब, यह काम करता है। दोनों तरीकों से, यह श्रोताओं के साथ और कस्टम फ़ाइल प्रदाता के साथ है। शायद यह जोर दिया जाना चाहिए कि समाधान दूसरा भाग है, शायद इसे शीर्ष पर ले जा रहा है। फ़ाइल प्रदाता श्रोताओं के विकल्प के रूप में दिलचस्प है। इसके अलावा, यह जर्सी आर्किटेक्चर को स्पष्ट करने में मदद करता है, इसलिए मैं इसे रखता हूं, लेकिन सवाल के सीधे जवाब के रूप में नहीं। – AgostinoX

    3

    जर्सी 2.X में, मैंने WriterInterceptor का उपयोग किया है ताकि अपाचे कॉमन्स 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(); 
        } 
    
    } 
    

    मैं तो या विशिष्ट लक्ष्यों जहां इंटरसेप्टर उपयोग करना चाहते हैं ग्राहक के साथ इस इंटरसेप्टर पंजीकृत,।

    संबंधित मुद्दे