使用GWT RemoteServiceServlet下载文件

时间:2016-03-28 19:54:29

标签: java file servlets gwt download

我正在编写一个GWT服务servlet,RemoteServiceServlet的实例,并且客户端给出了fileID,目标是从DB获取文件并将其推送到客户端。 servlet将任何错误消息作为String对象返回。

我做错了什么?

我正在网上研究这个,有些人声称无法通过RemoteServiceServlet完成这项工作?!

在我的情况下,服务器必须首先从数据库中获取文件,然后它可以将其发送到客户端,所以我必须先准备它。有没有办法将下载“推”到客户端,或者我是否必须编写专用的servlet才能下载?有人可以给我一个示例代码怎么做?

谢谢!

这是我到目前为止的代码以及它生成的异常:

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

服务器生成异常:

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

1 个答案:

答案 0 :(得分:0)

我从Sripathi Krishnan发现你无法在RPC调用中传输二进制数据文件 - 请参阅这篇文章https://stackoverflow.com/a/2823184/1431879

解决方案是遵循SSR的建议并实施下载Servlet - 请参阅此帖https://stackoverflow.com/a/13739960/1431879

然而,这创建了一个被浏览器阻止的弹出窗口。但是在服务器和已准备好的URL上准备好文件后,我的RPC返回文件名,客户端使用它来请求从专用servlet直接下载。我为下载创建了一个iframe。我在Thad找到了一篇优秀的帖子http://grokbase.com/p/gg/google-web-toolkit/13264b94q6/how-to-download-a-file-from-server-without-browser-opening-new-window

以下是他的帖子的直接引用:

我有很多地方可以让用户下载生成的servlet 文件。我通过几个步骤来处理这个问题

1)在我的应用程序的HTML中,我放了一个IFRAME

2)在我的应用程序的EntryPoint中,我声明了

private static final String DOWNLOAD_IFRAME =“__ gwt_downloadFrame”; private static Frame downloadFrame; ...

包装IFRAME:

@覆盖 public void onModuleLoad(){ downloadFrame = Frame.wrap(Document.get()的getElementById(DOWNLOAD_IFRAME)。); ...

提供下载方法

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

3)每当下载准备就绪时,请参考RPC调用的onSuccess()

MyApp.downloadURL(URL);