首页 文章

将文件从REST Web服务发送到客户端的正确方法是什么?

提问于
浏览
83

我刚刚开始开发REST服务,但我遇到了一个困难的情况:从我的REST服务发送文件到我的客户端 . 到目前为止,我已经掌握了如何发送简单数据类型(字符串,整数等),但发送文件是另一回事,因为有太多的文件格式,我不知道我应该在哪里开始 . 我的REST服务是基于Java的,我使用的是Jersey,我使用JSON格式发送所有数据 .

我读过有关base64编码的内容,有人说这是一种很好的技术,有人说这不是因为文件大小问题 . 什么是正确的方法?这就是我项目中一个简单的资源类看起来的样子:

import java.sql.SQLException;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriInfo;

import com.mx.ipn.escom.testerRest.dao.TemaDao;
import com.mx.ipn.escom.testerRest.modelo.Tema;

@Path("/temas")
public class TemaResource {

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public List<Tema> getTemas() throws SQLException{

        TemaDao temaDao = new TemaDao();        
        List<Tema> temas=temaDao.getTemas();
        temaDao.terminarSesion();

        return temas;
    }
}

我猜测发送文件的代码是这样的:

import java.sql.SQLException;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/resourceFiles")
public class FileResource {

    @GET
    @Produces({application/x-octet-stream})
    public File getFiles() throws SQLException{ //I'm not really sure what kind of data type I should return

        // Code for encoding the file or just send it in a data stream, I really don't know what should be done here

        return file;
    }
}

我应该使用什么样的注释?我见过有人推荐 @GET 使用 @Produces({application/x-octet-stream}) ,这是正确的方法吗?我需要浏览文件的文件 . 任何人都可以指导我如何发送文件?我应该使用base64对其进行编码以将其作为JSON对象发送吗?或者不需要编码将其作为JSON对象发送?感谢您提供的任何帮助 .

4 回答

  • 5

    我不建议在base64中编码二进制数据并将其包装在JSON中 . 它只会不必要地增加响应的大小并减慢速度 .

    只需使用GET和 application/octect-stream 使用javax.ws.rs.core.Response(JAX-RS API的一部分,因此您没有锁定到Jersey)的工厂方法之一来提供文件数据:

    @GET
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getFile() {
      File file = ... // Initialize this to the File path you want to serve.
      return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
          .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
          .build();
    }
    

    如果你没有实际的 File 对象,但 InputStreamResponse.ok(entity, mediaType)也应该能够处理它 .

  • -3

    如果你想返回一个要下载的文件,特别是如果你想要与文件上传/下载的一些javascript库集成,那么下面的代码应该做的工作:

    @GET
    @Path("/{key}")
    public Response download(@PathParam("key") String key,
                             @Context HttpServletResponse response) throws IOException {
        try {
            //Get your File or Object from wherever you want...
                //you can use the key parameter to indentify your file
                //otherwise it can be removed
            //let's say your file is called "object"
            response.setContentLength((int) object.getContentLength());
            response.setHeader("Content-Disposition", "attachment; filename="
                    + object.getName());
            ServletOutputStream outStream = response.getOutputStream();
            byte[] bbuf = new byte[(int) object.getContentLength() + 1024];
            DataInputStream in = new DataInputStream(
                    object.getDataInputStream());
            int length = 0;
            while ((in != null) && ((length = in.read(bbuf)) != -1)) {
                outStream.write(bbuf, 0, length);
            }
            in.close();
            outStream.flush();
        } catch (S3ServiceException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        }
        return Response.ok().build();
    }
    
  • 107

    将机器地址从localhost更改为您希望客户端连接的IP地址,以便调用下面提到的服务 .

    客户端调用REST Web服务:

    package in.india.client.downloadfiledemo;
    
    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response.Status;
    
    import com.sun.jersey.api.client.Client;
    import com.sun.jersey.api.client.ClientHandlerException;
    import com.sun.jersey.api.client.ClientResponse;
    import com.sun.jersey.api.client.UniformInterfaceException;
    import com.sun.jersey.api.client.WebResource;
    import com.sun.jersey.multipart.BodyPart;
    import com.sun.jersey.multipart.MultiPart;
    
    public class DownloadFileClient {
    
        private static final String BASE_URI = "http://localhost:8080/DownloadFileDemo/services/downloadfile";
    
        public DownloadFileClient() {
    
            try {
                Client client = Client.create();
                WebResource objWebResource = client.resource(BASE_URI);
                ClientResponse response = objWebResource.path("/")
                        .type(MediaType.TEXT_HTML).get(ClientResponse.class);
    
                System.out.println("response : " + response);
                if (response.getStatus() == Status.OK.getStatusCode()
                        && response.hasEntity()) {
                    MultiPart objMultiPart = response.getEntity(MultiPart.class);
                    java.util.List<BodyPart> listBodyPart = objMultiPart
                            .getBodyParts();
                    BodyPart filenameBodyPart = listBodyPart.get(0);
                    BodyPart fileLengthBodyPart = listBodyPart.get(1);
                    BodyPart fileBodyPart = listBodyPart.get(2);
    
                    String filename = filenameBodyPart.getEntityAs(String.class);
                    String fileLength = fileLengthBodyPart
                            .getEntityAs(String.class);
                    File streamedFile = fileBodyPart.getEntityAs(File.class);
    
                    BufferedInputStream objBufferedInputStream = new BufferedInputStream(
                            new FileInputStream(streamedFile));
    
                    byte[] bytes = new byte[objBufferedInputStream.available()];
    
                    objBufferedInputStream.read(bytes);
    
                    String outFileName = "D:/"
                            + filename;
                    System.out.println("File name is : " + filename
                            + " and length is : " + fileLength);
                    FileOutputStream objFileOutputStream = new FileOutputStream(
                            outFileName);
                    objFileOutputStream.write(bytes);
                    objFileOutputStream.close();
                    objBufferedInputStream.close();
                    File receivedFile = new File(outFileName);
                    System.out.print("Is the file size is same? :\t");
                    System.out.println(Long.parseLong(fileLength) == receivedFile
                            .length());
                }
            } catch (UniformInterfaceException e) {
                e.printStackTrace();
            } catch (ClientHandlerException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        public static void main(String... args) {
            new DownloadFileClient();
        }
    }
    

    服务响应客户:

    package in.india.service.downloadfiledemo;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    
    import com.sun.jersey.multipart.MultiPart;
    
    @Path("downloadfile")
    @Produces("multipart/mixed")
    public class DownloadFileResource {
    
        @GET
        public Response getFile() {
    
            java.io.File objFile = new java.io.File(
                    "D:/DanGilbert_2004-480p-en.mp4");
            MultiPart objMultiPart = new MultiPart();
            objMultiPart.type(new MediaType("multipart", "mixed"));
            objMultiPart
                    .bodyPart(objFile.getName(), new MediaType("text", "plain"));
            objMultiPart.bodyPart("" + objFile.length(), new MediaType("text",
                    "plain"));
            objMultiPart.bodyPart(objFile, new MediaType("multipart", "mixed"));
    
            return Response.ok(objMultiPart).build();
    
        }
    }
    

    JAR需要:

    jersey-bundle-1.14.jar
    jersey-multipart-1.14.jar
    mimepull.jar
    

    WEB.XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        id="WebApp_ID" version="2.5">
        <display-name>DownloadFileDemo</display-name>
        <servlet>
            <display-name>JAX-RS REST Servlet</display-name>
            <servlet-name>JAX-RS REST Servlet</servlet-name>
            <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
            <init-param>
                 <param-name>com.sun.jersey.config.property.packages</param-name> 
                 <param-value>in.india.service.downloadfiledemo</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>JAX-RS REST Servlet</servlet-name>
            <url-pattern>/services/*</url-pattern>
        </servlet-mapping>
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    </web-app>
    
  • 5

    由于您使用的是JSON,我会在通过网络发送之前对Base64进行编码 .

    如果文件很大,请尝试查看BSON,或其他一些二进制传输更好的格式 .

    如果文件压缩得很好,你也可以压缩文件,然后再对base64进行编码 .

相关问题