从Java客户端到Grails web应用程序的可恢复上传?

从Java客户端到Grails web应用程序的可恢复上传?,java,grails,upload,inputstream,resume-upload,Java,Grails,Upload,Inputstream,Resume Upload,在谷歌搜索了将近两个工作日,并尝试了我在网上发现的几种不同的可能性之后,我在这里提出了这个问题,希望我能最终得到答案 首先,我想做的是: 我正在开发一个客户机和一个服务器应用程序,目的是在一台服务器上的多个客户机之间交换大量大型文件。客户端是在纯Java(JDK1.6)中开发的,而web应用程序是在Grails(2.0.0)中开发的 由于客户端的目的是允许用户交换大量的大文件(通常每个文件大约2GB),因此我必须以某种方式实现它,以便上传是可恢复的,即用户可以随时停止和恢复上传 以下是我迄今为止

在谷歌搜索了将近两个工作日,并尝试了我在网上发现的几种不同的可能性之后,我在这里提出了这个问题,希望我能最终得到答案

首先,我想做的是: 我正在开发一个客户机和一个服务器应用程序,目的是在一台服务器上的多个客户机之间交换大量大型文件。客户端是在纯Java(JDK1.6)中开发的,而web应用程序是在Grails(2.0.0)中开发的

由于客户端的目的是允许用户交换大量的大文件(通常每个文件大约2GB),因此我必须以某种方式实现它,以便上传是可恢复的,即用户可以随时停止和恢复上传

以下是我迄今为止所做的: 实际上,我做到了我想做的事情,将大文件流式传输到服务器,同时仍然能够使用原始套接字暂停和恢复上传。我会向服务器发送一个常规请求(使用Apache的HttpClient库),让服务器向我发送一个免费使用的端口,然后在服务器上打开一个ServerSocket并从客户端连接到该特定的套接字

这就是问题所在: 事实上,这至少有两个问题:

  • 我自己打开这些端口,所以我必须自己管理打开和使用的端口。这很容易出错
  • 我实际上绕过了Grails管理大量(并发)连接的能力
  • 最后,这里是我现在应该做的事情和问题: 由于我上面提到的问题是不可接受的,我现在应该使用Java的URLConnection/HttpURLConnection类,同时仍然坚持使用Grails

    连接到服务器并发送简单的请求一点问题都没有,一切正常。当我尝试使用流(客户端中连接的OutputStream和服务器中请求的InputStream)时,问题就开始了。打开客户机的OutputStream并将数据写入其中非常简单。但对我来说,从请求的InputStream读取数据似乎是不可能的,因为该数据流似乎总是空的

    示例代码 下面是服务器端(Groovy控制器)的一个示例:

    正如我提到的,问题是,
    request.inputStream
    总是产生一个空的inputStream,因此我永远无法从中读取任何内容(当然)。但这正是我想要做的(这样我就可以将要上传到服务器的文件流化,从InputStream读取并保存到一个文件),这是相当令人失望的

    我尝试了不同的HTTP方法不同的数据有效负载,并且一遍又一遍地重新排列代码,但似乎无法解决问题

    我希望找到什么 当然,我希望找到解决我问题的办法。任何东西都值得高度赞赏:提示、代码片段、库建议等等。也许我甚至都搞错了,需要走完全不同的方向


    那么,我如何实现从Java客户机到Grails web应用程序的相当大(二进制)文件的可恢复文件上载,而不必手动打开服务器端的端口呢?

    HTTP GET方法具有用于范围检索的特殊头文件:大多数下载程序都使用它从服务器进行可恢复下载

    据我所知,在POST/PUT请求中使用此标题没有标准实践,但这取决于您,对吗?您可以制作非常标准的Grails控制器,它将接受标准的http上传,标题类似于
    范围:bytes=500-999
    。控制器应该把500个上传的字节从客户端放到文件中,从位置500开始

    在这种情况下,您不需要打开任何套接字,也不需要制定自己的协议等


    p.S.500字节只是一个例子,可能您使用的是更大的部件。

    客户端Java编程:

        public class NonFormFileUploader {
        static final String UPLOAD_URL= "http://localhost:8080/v2/mobileApp/fileUploadForEOL";
    
    
        static final int BUFFER_SIZE = 4096;
    
        public static void main(String[] args) throws IOException {
            // takes file path from first program's argument
            String filePath = "G:/study/GettingStartedwithGrailsFinalInfoQ.pdf";
            File uploadFile = new File(filePath);
    
            System.out.println("File to upload: " + filePath);
    
            // creates a HTTP connection
            URL url = new URL(UPLOAD_URL);
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setDoOutput(true);
            httpConn.setRequestMethod("POST");
            // sets file name as a HTTP header
            httpConn.setRequestProperty("fileName", uploadFile.getName());
    
            // opens output stream of the HTTP connection for writing data
            OutputStream outputStream = httpConn.getOutputStream();
    
            // Opens input stream of the file for reading data
            FileInputStream inputStream = new FileInputStream(uploadFile);
    
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = -1;
    
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                System.out.println("bytesRead:"+bytesRead);
                outputStream.write(buffer, 0, bytesRead);
                outputStream.flush();
            }
    
            System.out.println("Data was written.");
            outputStream.flush();
            outputStream.close();
            inputStream.close();
    
            int responseCode = httpConn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // reads server's response
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        httpConn.getInputStream()));
                String response = reader.readLine();
                System.out.println("Server's response: " + response);
            } else {
                System.out.println("Server returned non-OK code: " + responseCode);
            }
        }
     }
    
    服务器端Grails程序:

        public class NonFormFileUploader {
        static final String UPLOAD_URL= "http://localhost:8080/v2/mobileApp/fileUploadForEOL";
    
    
        static final int BUFFER_SIZE = 4096;
    
        public static void main(String[] args) throws IOException {
            // takes file path from first program's argument
            String filePath = "G:/study/GettingStartedwithGrailsFinalInfoQ.pdf";
            File uploadFile = new File(filePath);
    
            System.out.println("File to upload: " + filePath);
    
            // creates a HTTP connection
            URL url = new URL(UPLOAD_URL);
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setDoOutput(true);
            httpConn.setRequestMethod("POST");
            // sets file name as a HTTP header
            httpConn.setRequestProperty("fileName", uploadFile.getName());
    
            // opens output stream of the HTTP connection for writing data
            OutputStream outputStream = httpConn.getOutputStream();
    
            // Opens input stream of the file for reading data
            FileInputStream inputStream = new FileInputStream(uploadFile);
    
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = -1;
    
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                System.out.println("bytesRead:"+bytesRead);
                outputStream.write(buffer, 0, bytesRead);
                outputStream.flush();
            }
    
            System.out.println("Data was written.");
            outputStream.flush();
            outputStream.close();
            inputStream.close();
    
            int responseCode = httpConn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // reads server's response
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        httpConn.getInputStream()));
                String response = reader.readLine();
                System.out.println("Server's response: " + response);
            } else {
                System.out.println("Server returned non-OK code: " + responseCode);
            }
        }
     }
    
    控制器内部:

    在服务类内部:

    def fileUploadForEOL(请求){
    def状态=假;
    整数代码=500
    def map=[:]
    试一试{
    字符串文件名=request.getHeader(“文件名”);
    文件保存文件=新文件(保存目录+文件名);
    System.out.println(“==beginheaders===”);
    枚举名称=request.getHeaderNames();
    while(names.hasMoreElements()){
    字符串headerName=names.nextElement();
    System.out.println(headerName+“=”+request.getHeader(headerName));
    }
    System.out.println(“=======结束头========\n”);
    //打开读取数据请求的输入流
    InputStream InputStream=request.getInputStream();
    //打开输出流以写入文件
    FileOutputStream outputStream=新的FileOutputStream(保存文件);
    字节[]缓冲区=新字节[缓冲区大小];
    int bytesRead=inputStream.read(缓冲区);
    长计数=字节读取
    while(字节读取!=-1){
    写入(缓冲区,0,字节读取);
    bytesRead=inputStream.read(缓冲区);
    计数+=字节读取
    }
    println“计数:”+计数
    System.out.println(“数据接收”);
    outputStream.close();
    inputStream.close();
    System.out.println(“文件写入:”+saveFile.getAbsolutePath());
    代码=200
    }捕获(例外e){
    log(java.util.logging.Level.SEVERE,“fileUploadForEOL中的异常”,e);
    }最后{
    地图
    
        public class NonFormFileUploader {
        static final String UPLOAD_URL= "http://localhost:8080/v2/mobileApp/fileUploadForEOL";
    
    
        static final int BUFFER_SIZE = 4096;
    
        public static void main(String[] args) throws IOException {
            // takes file path from first program's argument
            String filePath = "G:/study/GettingStartedwithGrailsFinalInfoQ.pdf";
            File uploadFile = new File(filePath);
    
            System.out.println("File to upload: " + filePath);
    
            // creates a HTTP connection
            URL url = new URL(UPLOAD_URL);
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setDoOutput(true);
            httpConn.setRequestMethod("POST");
            // sets file name as a HTTP header
            httpConn.setRequestProperty("fileName", uploadFile.getName());
    
            // opens output stream of the HTTP connection for writing data
            OutputStream outputStream = httpConn.getOutputStream();
    
            // Opens input stream of the file for reading data
            FileInputStream inputStream = new FileInputStream(uploadFile);
    
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = -1;
    
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                System.out.println("bytesRead:"+bytesRead);
                outputStream.write(buffer, 0, bytesRead);
                outputStream.flush();
            }
    
            System.out.println("Data was written.");
            outputStream.flush();
            outputStream.close();
            inputStream.close();
    
            int responseCode = httpConn.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // reads server's response
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        httpConn.getInputStream()));
                String response = reader.readLine();
                System.out.println("Server's response: " + response);
            } else {
                System.out.println("Server returned non-OK code: " + responseCode);
            }
        }
     }
    
    def fileUploadForEOL(){
        def result
        try{
            result = mobileAppService.fileUploadForEOL(request);
        }catch(Exception e){
            log.error "Exception in fileUploadForEOL service",e
        }
        render result as JSON
    }
    
        def fileUploadForEOL(request){
        def status = false;
        int code = 500
        def map = [:]
        try{
        String fileName = request.getHeader("fileName");
        File saveFile = new File(SAVE_DIR + fileName);
    
        System.out.println("===== Begin headers =====");
        Enumeration<String> names = request.getHeaderNames();
        while (names.hasMoreElements()) {
            String headerName = names.nextElement();
            System.out.println(headerName + " = " + request.getHeader(headerName));        
        }
        System.out.println("===== End headers =====\n");
    
        // opens input stream of the request for reading data
        InputStream inputStream = request.getInputStream();
    
        // opens an output stream for writing file
        FileOutputStream outputStream = new FileOutputStream(saveFile);
    
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead = inputStream.read(buffer);
    
        long count =  bytesRead
    
        while(bytesRead != -1) {
            outputStream.write(buffer, 0, bytesRead);
          bytesRead = inputStream.read(buffer);
          count += bytesRead
        }
         println "count:"+count
        System.out.println("Data received.");
        outputStream.close();
        inputStream.close();
    
        System.out.println("File written to: " + saveFile.getAbsolutePath());
    
        code = 200
    
        }catch(Exception e){
            mLogger.log(java.util.logging.Level.SEVERE,"Exception in fileUploadForEOL",e);
        }finally{
            map <<["code":code]
        }
        return map
    }