从REST Web服务发送文件到客户端的正确方法是什么?
我刚刚开始开发REST服务,但遇到了一个困难的情况:从我的REST服务发送文件到我的客户端。 到目前为止,我已经掌握了如何发送简单的数据types(string,整数等),但发送文件是一个不同的问题,因为有太多的文件格式,我不知道我应该甚至开始。 我的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; } }
我应该使用什么样的注释? 我见过一些人推荐使用@Produces({application/x-octet-stream})
@GET
,那是正确的方法吗? 我发送的文件是特定的,所以客户端不需要浏览文件。 任何人都可以指导我如何发送文件? 我应该使用base64将其编码为JSON对象吗? 或者编码没有必要把它作为一个JSON对象发送? 感谢您的帮助。
我不build议在base64中编码二进制数据,并用JSON包装它。 它会不必要地增加响应的大小,减慢速度。
使用GET和application/octect-stream
使用javax.ws.rs.core.Response
一个工厂方法(JAX-RS API的一部分,因此不会被locking到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
对象,但是InputStream
, Response.ok(entity, mediaType)
应该能够处理。
如果你想返回一个文件被下载,特别是如果你想要集成一些file upload/下载的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(); }
Kindly change the machine address from localhost to ip address you want your client to connect with to call below mentioned service. **CLIENT TO CALL REST WEBSERVICE** 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(); } } **SERVICE TO RESPONSE CLIENT** 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 NEEDED** 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>
既然你使用JSON,我会Base64编码,然后通过电线发送。
如果文件很大,请尝试查看BSON或其他一些更好的二进制传输格式。
你也可以压缩文件,如果它们压缩的很好,在base64编码之前。