1

我有一个 java servlet 可以生成一些报告。当用户选择报告时,它会在数据库上进行查询并将 xls 报告流式传输到客户端。全部以同步方式进行。问题是有时我有很多记录要从数据库中获取,我想提供更好的用户体验,允许用户在报告处理时做其他事情,并以某种方式弹出链接时过程结束。是否有 Java 库或一些技术可以避免长时间等待并实现该目标?

现在我已经准备了一段代码,它以异步方式完成报告并向注册客户端发送一封电子邮件,其中包含下载文件的 url,但它必须用其他东西替换,因为我不能再通过电子邮件进行交流。

提前致谢

4

3 回答 3

1

这是我对此的看法,我不知道有哪个库可以完全满足您的需求,您可能需要在这里进行一些自定义开发。

  • 我相信你已经实现了异步服务,完成后会发送一封电子邮件通知。与其发送电子邮件,不如让该线程更新某种作业表——数据库表中的条目或某些应用程序/会话范围的映射。
  • 有一个 servlet/restful ws
  • 在某个 url 上公开该作业表。定期轮询 url。Ajax poll 是 js 库 JQuery、Prototype 中的标准功能。
  • 当您收到某个报告已完成的响应时,显示一些弹出窗口,或者可能是客户端的 facebook you-have-notification 之类的东西。

我在这里没有考虑过身份验证/授权问题,您也需要注意这一点。

希望这可以帮助

于 2012-10-14T15:27:14.217 回答
0

用于下载我的图像文件的多线程客户端服务器程序。由于有四个文件要下载,客户端进行了 4 次连接尝试。这不仅限于 4 个,但 FileServer 发送的文件将在第四次尝试后重复。保存对话框和文件保存在不同的线程中完成,以免妨碍文件下载。

这是文件服务器...

public class FileServer {
    private final ExecutorService exec = Executors.newCachedThreadPool();

    final String[] fileNames = {
            "C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 1.jpg",
            "C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 2.jpg",
            "C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 3.jpg",
            "C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 4.jpg"

    };

    public void start() throws IOException {
        ServerSocket socket = new ServerSocket(7777);
        System.out.println("Waiting for client message...");

        while (!exec.isShutdown()) {
            try {
                for (final String fileName : fileNames){
                     final Socket conn = socket.accept();

                    exec.execute(new Runnable() {
                        public void run() {
                            sendFile(conn,fileName);

                        }
                    });
                }
            } catch (RejectedExecutionException e) {
                if (!exec.isShutdown())
                    log("task submission rejected", e);
            }
        }
    }

    public void stop() {
        System.out.println("Shutting down server...");
        exec.shutdown();
    }

    private void log(String msg, Exception e) {
        Logger.getAnonymousLogger().log(Level.WARNING, msg, e);
    }

    public void sendFile(Socket conn, String fileName) {
        File myFile = new File(fileName);
        if (!myFile.exists()) {
            log("File does not exist!",null);
        }

        // file does exist
        System.out.println(Thread.currentThread().getName());
        System.out.println("AbsolutePath:" + myFile.getAbsolutePath());
        System.out.println("length: " + myFile.length());

        if (myFile.exists()) {
            try {
                ObjectOutputStream oos = new ObjectOutputStream(
                conn.getOutputStream());
                oos.writeObject(myFile);
                oos.close();
            } catch (IOException e) {
                log("IOException Error", e);
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {

        FileServer fs = new FileServer();
        fs.start();
    }
}

这是文件服务器客户端...

public class FileServerClient {

    private final ExecutorService exec = Executors.newCachedThreadPool();
    Frame myFrame = new Frame();
    List<File> fileList = new ArrayList<File>();

    public void receiveFileFromServer() throws Exception{

        Socket sock = null;
        InputStream socketInputStream = null;
        String host = "localhost";
        int port = 7777;

        for (int i=0;i<4;i++) {

            sock = new Socket(host, port);
            socketInputStream = sock.getInputStream();
            System.out.println("Connection successful...");

            // recieve the file
            ObjectInputStream ois = new ObjectInputStream(socketInputStream);

            // file from server is deserialized
            final File myfile = (File) ois.readObject();
            fileList.add(myfile);

            // deserialized file properties 
            System.out.println("AbsolutePath: " + myfile.getAbsolutePath());
            System.out.println("FileName:" + myfile.getName());
            System.out.println("length" + myfile.length());
            exec.execute(new Runnable() {
                public void run() {

                    saveFile(myfile);

                }
            });

        }

    }

    private void saveFile(File myfile) {
        FileDialog fileDialog = new FileDialog(myFrame,
                "Choose Destination for "+ myfile.getName(), FileDialog.SAVE);
        fileDialog.setDirectory(null);
        fileDialog.setFile("enter file name here");
        fileDialog.setVisible(true);

        String targetFileName = fileDialog.getDirectory()
                + fileDialog.getFile() + ".jpg";

        System.out.println("File will be saved to: " + targetFileName);

        copyBytes(myfile, targetFileName);
    }

    private void copyBytes(File originalFile, String targetFileName) {

        try {
            FileInputStream in = new FileInputStream(originalFile);
            FileOutputStream out = new FileOutputStream(targetFileName);
            int c;

            while ((c = in.read()) != -1) {
                out.write(c);
            }
            out.close();
            in.close();

        } catch (Exception e) {
            log("IOException Error", e);
        }

    }

    private void log(String msg, Exception e) {
        Logger.getAnonymousLogger().log(Level.WARNING, msg, e);
    }

    public static void main(String[] args) throws Exception {

        FileServerClient client = new FileServerClient();

        client.receiveFileFromServer();

    }

}
于 2012-10-14T13:41:06.290 回答
0

您可以从客户端发出异步请求。让我们假设您的客户是一个 html 页面。当用户选择报告并单击“提交”时,您可以使用报告参数触发 ajax 请求(jquery 对此很有用)。最好在用户主页上保留一个部分,上面写着“准备好的报告”之类的内容。然后,客户可以转到准备好的报告部分下载报告。如上面评论中所述,您可能还必须实现一个弹出窗口,通知用户请求的报告已准备好。当 ajax 请求成功返回时显示弹出窗口。但是,客户端可能在报告完成时已注销,因此最好在用户登录时在“准备好的报告”部分中再次提供下载链接。

于 2012-10-14T15:52:29.680 回答