Какой правильный способ отправить файл из веб-сервиса REST клиенту?
Я только начал разрабатывать службы REST, но я столкнулся с трудной ситуацией: отправка файлов из моей службы REST моему клиенту. До сих пор я узнал, как отправлять простые типы данных (строки, целые числа и т.д.), Но отправка файла - это другое дело, поскольку существует так много форматов файлов, что я не знаю, где я должен начинать. Моя служба REST выполняется на Java, и я использую Джерси, я отправляю все данные с использованием формата 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? Спасибо за любую помощь, которую вы можете дать.
Ответы
Ответ 1
Я не рекомендую кодировать двоичные данные в base64 и обертывать его в JSON. Это просто лишний раз увеличит размер ответа и замедлит работу.
Просто используйте данные GET и application/octect-stream
, используя один из методов factory javax.ws.rs.core.Response
(часть JAX-RS API, поэтому вы не заперты в Джерси):
@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)
должен также справиться с этим.
Ответ 2
Если вы хотите вернуть файл для загрузки, особенно если вы хотите интегрироваться с некоторыми файлами 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 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();
}
Ответ 3
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>
Ответ 4
Поскольку вы используете JSON, я бы Base64 кодировал его перед отправкой через провод.
Если файлы большие, попробуйте посмотреть BSON или другой формат, который лучше с двоичными передачами.
Вы также можете заархивировать файлы, если они хорошо сжимаются, до того, как их кодирует base64.