2016-03-28 17 views
0

Ich schreibe ein GWT-Service-Servlet, Instanz von RemoteServiceServlet, und gegeben die DateiID vom Client, das Ziel ist es, Datei von DB zu holen und es auf den Client zu schieben. Das Servlet gibt eine Fehlermeldung als String-Objekt zurück.Datei mit GWT RemoteServiceServlet herunterladen

Was mache ich falsch?

Ich recherchiere das im Netz und einige Leute behaupten, dass es nicht vom RemoteServiceServlet getan werden kann ?!

In meinem Fall muss der Server zuerst eine Datei aus der Datenbank holen, dann kann er sie an den Client senden, also muss ich ihn zuerst vorbereiten. Gibt es eine Möglichkeit, einen Download auf den Client zu "pushen", oder muss ich ein dediziertes Servlet nur für den Download schreiben? Kann jemand mir einen Beispielcode geben, wie man das macht?

Danke!

Dies ist der Code, den ich bisher haben und die Ausnahme erzeugt sie:

public class MyServiceImpl extends RemoteServiceServlet implements MyService { 
    @Override 
    public String getFile(Long fileId) { 
     String errors = null; 
     File file = fetchFileByID(fileId); 
     try { 
      if (file != null && file.exists()) { 
       String name = fileLink.getName(); 
       HttpServletResponse response = getThreadLocalResponse(); 
       long fileLen = file.length(); 
       if (fileLen > Integer.MAX_VALUE) 
        throw new IllegalStateException("File too large, cannot download using the browser."); 
       int length = (int) fileLen; 
       // do not cache 
       response.setHeader("Expires", "0"); 
       response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); 
       response.setHeader("Pragma", "public"); 
       // content length is needed for MSIE 
       response.setContentLength(length); 
       response.setHeader("Content-Type", "application/octet-stream;"); 
       response.setHeader("Content-Disposition", "attachment;filename=\"" + name + "\""); 
       OutputStream os = response.getOutputStream(); 
       FileInputStream is = new FileInputStream(file); 
       BufferedInputStream buf = new BufferedInputStream(is); 

       int readBytes=0; 
       while((readBytes=buf.read())!=-1) { 
         os.write(readBytes); 
       } 
       os.flush(); 
       buf.close(); 
      } else { 
       errors = "File not found."; 
      } 
     } catch (IOException e) { 
      errors = e.getMessage(); 
     } finally { 
      if (file != null) 
       file.delete(); 
     } 
     return errors; 
    } 
} 

Server erzeugt eine Ausnahme:

Starting Jetty on port 8888 
    [WARN] /saluweb/SaluService 
java.lang.RuntimeException: Unable to report failure 
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doUnexpectedFailure(AbstractRemoteServiceServlet.java:107) 
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:67) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:755) 
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848) 
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:686) 
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501) 
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137) 
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557) 
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231) 
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086) 
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:428) 
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193) 
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020) 
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) 
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) 
    at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:68) 
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) 
    at org.eclipse.jetty.server.Server.handle(Server.java:370) 
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:489) 
    at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:960) 
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1021) 
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:865) 
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240) 
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82) 
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:668) 
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52) 
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) 
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: java.io.IOException: Closed 
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:140) 
    at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:117) 
    at com.google.gwt.user.server.rpc.RPCServletUtils.writeResponse(RPCServletUtils.java:375) 
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.writeResponse(RemoteServiceServlet.java:460) 
    at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:313) 
    at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62) 
... 27 more 
+0

Haben Sie versucht, die Datei direkt auszulesen und dann Ihr Servlet zu testen? Vielleicht dauert Ihr Datenbankzugriff zu lange? In einer Anwendung (ich weiß) wird die Datei zuerst in ein Byte-Array gestellt und dann out.write, out.flush und out.close aufgerufen. Und es funktioniert. Ich kann auch Mockrunner (für Servlets) zum Testen empfehlen, funktioniert super mit GWT. – Akkusativobjekt

+1

Werfen Sie einen Blick auf [diese Frage] (http://stackoverflow.com/questions/2822667/download-dynamic-file-with-gwt). Sie können keine Stream-Binärdaten von einem RPC-Aufruf zurückgeben. Dies muss über ein Standard-Servlet erfolgen. – Baz

+0

Danke Baz, das führte mich zu einer Lösung :) über die Rückgabe eines Dateinamens, und Client-Seite ein dediziertes Download-Servlet aufrufen. Vielen Dank! – Marcin

Antwort

0

ich von Sripathi Krishnan fand heraus, dass Sie nicht Binärdatei streamen im RPC-Aufruf - siehe diesen Beitrag https://stackoverflow.com/a/2823184/1431879

Die Lösung sollte dem Vorschlag von SSR folgen und Download Servlet implementieren - siehe diesen Beitrag https://stackoverflow.com/a/13739960/1431879

Dies jedoch erstellt ein Popup, das von Browsern blockiert wurde. Wenn eine Datei auf dem Server bereit und die URL bereits vorbereitet ist, gibt mein RPC den Dateinamen zurück, und der Client verwendet ihn, um den direkten Download von einem dedizierten Servlet anzufordern. Ich habe einen iFrame für Downloads erstellt. Ich fand einen ausgezeichneten Beitrag von Thad wie hier zu tun, dass http://grokbase.com/p/gg/google-web-toolkit/13264b94q6/how-to-download-a-file-from-server-without-browser-opening-new-window

Hier ist ein direktes Zitat aus seinem Amt ist:

Ich habe eine Reihe von Orten, an denen der Benutzer ein Servlet Datei erzeugt herunterladen. Ich damit umgehen allgemein mit mehreren Schritten

1) In meiner App HTML, habe ich einen IFRAME

2) In meiner App Entrypoint, ich

private static final String DOWNLOAD_IFRAME deklarieren = " __gwt_downloadFrame "; privater statischer Rahmen downloadFrame; ...

Wickeln Sie das IFRAME:

@Override public void onModuleLoad() { downloadFrame = Frame.wrap (. Document.get() getElementById (DOWNLOAD_IFRAME)); ...

Methode Geben Sie für

public static void downloadURL (String url) { downloadFrame herunterzuladen.setUrl (URL); }

3) Jedes Mal, wenn ein Download fertig ist, sagen wir in der onSuccess() eines RPC-Aufruf

MyApp.downloadURL (url);