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})
, 이것이 올바른 방법입니까? 내가 보내는 파일은 특정 파일이므로 클라이언트가 파일을 찾아 볼 필요가 없습니다. 누구든지 파일을 어떻게 보내야하는지 안내해 줄 수 있습니까? JSON 객체로 보내려면 base64를 사용하여 인코딩해야합니까? 또는 JSON 객체로 보내기 위해 인코딩이 필요하지 않습니까? 도움을 주셔서 감사합니다.
답변
바이너리 데이터를 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
객체는 없지만 InputStream
, Response.ok(entity, mediaType)
는이를 처리 할 수 있어야합니다.
답변
다운로드 할 파일을 반환하려는 경우, 특히 파일 업로드 / 다운로드의 일부 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();
}
답변
아래에 언급 된 서비스를 호출하기 위해 클라이언트가 연결할 IP 주소로 머신 주소를 localhost에서 변경합니다.
REST 웹 서비스를 호출하는 클라이언트 :
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>
답변
JSON을 사용했기 때문에 유선을 통해 보내기 전에 Base64 인코딩합니다.
파일이 크면 BSON 또는 바이너리 전송에 더 적합한 다른 형식을 살펴보십시오.
파일이 잘 압축되면 base64로 인코딩하기 전에 압축 할 수도 있습니다.