Nice programing

Jersey Restful 웹 서비스에서 다른 객체와 함께 파일 업로드

nicepro 2021. 1. 7. 21:17
반응형

Jersey Restful 웹 서비스에서 다른 객체와 함께 파일 업로드


직원 데이터와 함께 이미지를 업로드하여 시스템에 직원 정보를 만들고 싶습니다. 저지를 사용하여 다른 휴식 전화로 할 수 있습니다. 그러나 나는 한 번의 휴식으로 성취하고 싶다. 나는 구조 아래에 제공합니다. 이 점에서 어떻게해야하는지 도와주세요.

@POST
@Path("/upload2")
@Consumes({MediaType.MULTIPART_FORM_DATA,MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response uploadFileWithData(
        @FormDataParam("file") InputStream fileInputStream,
        @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
        Employee emp) {

//..... business login

}

시도 할 때마다 Chrome 우편 배달부에 오류가 발생합니다. 내 Employee json의 간단한 구조는 다음과 같습니다.

{
    "Name": "John",
    "Age": 23,
    "Email": "john@gmail.com",
    "Adrs": {
        "DoorNo": "12-A",
        "Street": "Street-11",
        "City": "Bangalore",
        "Country": "Karnataka"
    }
}

하지만 두 번의 다른 호출을해서 할 수는 있지만 한 번의 휴식 호출로 달성하여 직원의 실제 데이터와 파일을받을 수 있도록하고 싶습니다.

이와 관련하여 도움을 요청하십시오.


두 개의 Content-Types를 가질 수 없습니다 (기술적으로는 아래에서 수행하는 작업이지만 멀티 파트의 각 부분으로 분리되어 있지만 주요 유형은 멀티 파트입니다). 그것은 기본적으로 당신이 당신의 방법으로 기대하는 것입니다. 기본 미디어 유형으로 mutlipart json을 함께 기대하고 있습니다. Employee데이터는 여러 부분의 일부가 될 필요가있다. 그래서 당신은 추가 할 수 있습니다 @FormDataParam("emp")을 위해 Employee.

@FormDataParam("emp") Employee emp) { ...

테스트에 사용한 클래스는 다음과 같습니다.

@Path("/multipart")
public class MultipartResource {

    @POST
    @Path("/upload2")
    @Consumes({MediaType.MULTIPART_FORM_DATA})
    public Response uploadFileWithData(
            @FormDataParam("file") InputStream fileInputStream,
            @FormDataParam("file") FormDataContentDisposition cdh,
            @FormDataParam("emp") Employee emp) throws Exception{

        Image img = ImageIO.read(fileInputStream);
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(img)));
        System.out.println(cdh.getName());
        System.out.println(emp);

        return Response.ok("Cool Tools!").build();
    } 
}

먼저 클라이언트 API로 테스트하여 작동하는지 확인했습니다.

@Test
public void testGetIt() throws Exception {

    final Client client = ClientBuilder.newBuilder()
        .register(MultiPartFeature.class)
        .build();
    WebTarget t = client.target(Main.BASE_URI).path("multipart").path("upload2");

    FileDataBodyPart filePart = new FileDataBodyPart("file", 
                                             new File("stackoverflow.png"));
    // UPDATE: just tested again, and the below code is not needed.
    // It's redundant. Using the FileDataBodyPart already sets the
    // Content-Disposition information
    filePart.setContentDisposition(
            FormDataContentDisposition.name("file")
                                    .fileName("stackoverflow.png").build());

    String empPartJson
            = "{"
            + "  \"id\": 1234,"
            + "  \"name\": \"Peeskillet\""
            + "}";

    MultiPart multipartEntity = new FormDataMultiPart()
            .field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
            .bodyPart(filePart);

    Response response = t.request().post(
            Entity.entity(multipartEntity, multipartEntity.getMediaType()));
    System.out.println(response.getStatus());
    System.out.println(response.readEntity(String.class));

    response.close();
}

방금 테스트를 위해 and 필드가 있는 간단한 Employee클래스를 만들었습니다 . 이것은 완벽하게 잘 작동합니다. 이미지를 표시하고 콘텐츠 배치를 인쇄하고 개체를 인쇄 합니다.idnameEmployee

나는 Postman에 너무 익숙하지 않아서 마지막으로 테스트를 저장했습니다 :-)

여기에 이미지 설명 입력

응답을 볼 수 있듯이 잘 작동하는 것 같습니다 "Cool Tools". 그러나 인쇄 된 Employee데이터를 살펴보면 null이라는 것을 알 수 있습니다. 클라이언트 API로 제대로 작동했기 때문에 이상합니다.

미리보기 창을 보면 문제가 있음을 알 수 있습니다.

여기에 이미지 설명 입력

본문 부분 에는 Content-Type헤더 가 없습니다 emp. 클라이언트 API에서 내가 명시 적으로 설정 한 것을 볼 수 있습니다.

MultiPart multipartEntity = new FormDataMultiPart()
        .field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
        .bodyPart(filePart);

그래서 나는 이것이 실제로 완전한 대답의 일부일 뿐이라고 생각합니다 . 말씀 드렸듯이 저는 Postman에 익숙하지 않아서 Content-Type개별 신체 부위에 s 를 설정하는 방법을 모릅니다 . image/png이미지에 대한 자동 이미지 부분 (나는 그것이 단지 파일 확장자에 의해 결정되었다 추측)을 위해 나를 위해 설정되었다. 이것을 알아낼 수 있다면 문제가 해결되어야합니다. 이 작업을 수행하는 방법을 찾으면 답변으로 게시하십시오.


그리고 완전성을 위해 ...

기본 구성 :

의존:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>${jersey2.version}</version>
</dependency>

클라이언트 구성 :

final Client client = ClientBuilder.newBuilder()
    .register(MultiPartFeature.class)
    .build();

서버 구성 :

// Create JAX-RS application.
final Application application = new ResourceConfig()
    .packages("org.glassfish.jersey.examples.multipart")
    .register(MultiPartFeature.class);

최신 정보

따라서 Postman 클라이언트에서 볼 수 있듯이 일부 클라이언트는 FormData(js)를 사용할 때의 기본 기능과 관련하여 브라우저를 포함하여 개별 부분의 Content-Type을 설정할 수 없습니다 .

클라이언트가이 문제를 해결하기를 기대할 수 없으므로 데이터를 수신 할 때 역 직렬화하기 전에 명시 적으로 Content-Type을 설정해야합니다. 예를 들면

@POST
@Path("upload2")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFileAndJSON(@FormDataParam("emp") FormDataBodyPart jsonPart,
                                  @FormDataParam("file") FormDataBodyPart bodyPart) { 
     jsonPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
     Employee emp = jsonPart.getValueAs(Employee.class);
}

POJO를 얻는 것은 약간의 추가 작업이지만 클라이언트가 자신의 솔루션을 찾으려고 강요하는 것보다 더 나은 솔루션입니다.


Asides

  • 이 주석 에는 기본 HttpUrlConnection이 아닌 다른 커넥터를 사용하는 경우 관심이있을 수 있는 대화 가 있습니다.

아래 코드를 이용하여 MULTIPART FORM DATA를 이용하여 Form에서 Image File 및 Data에 접근 할 수 있습니다.

@POST
@Path("/UpdateProfile")
@Consumes(value={MediaType.APPLICATION_JSON,MediaType.MULTIPART_FORM_DATA})
@Produces(value={MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Response updateProfile(
    @FormDataParam("file") InputStream fileInputStream,
    @FormDataParam("file") FormDataContentDisposition contentDispositionHeader,
    @FormDataParam("ProfileInfo") String ProfileInfo,
    @FormDataParam("registrationId") String registrationId) {

    String filePath= "/filepath/"+contentDispositionHeader.getFileName();

    OutputStream outputStream = null;
    try {
        int read = 0;
        byte[] bytes = new byte[1024];
        outputStream = new FileOutputStream(new File(filePath));

        while ((read = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, read);
        }

        outputStream.flush();
        outputStream.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (outputStream != null) { 
            try {
                outputStream.close();
            } catch(Exception ex) {}
        }
    }
}

ApplicationConfig는 파일 업로드를 활성화하기 위해 glassfish.jersey.media ..에서 MultiPartFeature.class를 등록해야합니다.

@javax.ws.rs.ApplicationPath(ResourcePath.API_ROOT)
public class ApplicationConfig extends ResourceConfig {  
public ApplicationConfig() {
        //register the necessary headers files needed from client
        register(CORSConfigurationFilter.class);
        //The jackson feature and provider is used for object serialization
        //between client and server objects in to a json
        register(JacksonFeature.class);
        register(JacksonProvider.class);
        //Glassfish multipart file uploader feature
        register(MultiPartFeature.class);
        //inject and registered all resources class using the package
        //not to be tempered with
        packages("com.flexisaf.safhrms.client.resources");
        register(RESTRequestFilter.class);
    }

나는 peeskillet에 대한 의견을 추가하고 싶지만 평판 포인트가 50이 아니므로 답변으로 추가합니다.

Jersey 클라이언트 2.21.1에서 @peeskillet 솔루션을 시도했을 때 400 오류가 발생했습니다. 클라이언트 코드에 다음을 추가하면 작동했습니다.

  MediaType contentType = MediaType.MULTIPART_FORM_DATA_TYPE;
  contentType = Boundary.addBoundary(contentType);

  Response response = t.request().post(
        Entity.entity(multipartEntity, contentType));

요청 후 호출에서 하드 코딩 된 MediaType.MULTIPART_FORM_DATA 대신.


파일 업로드 예제를 사용했습니다.

http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/

내 리소스 클래스에는 아래 방법이 있습니다.

@POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response  attachupload(@FormDataParam("file") byte[] is,
@FormDataParam("file") FormDataContentDisposition fileDetail,
@FormDataParam("fileName") String flename){
attachService.saveAttachment(flename,is);
}

내 attachService.java에는 아래 방법이 있습니다.

 public void saveAttachment(String flename,  byte[] is) {
            // TODO Auto-generated method stub
         attachmentDao.saveAttachment(flename,is);

        }

Dao에서 나는 가지고있다

attach.setData(is);
attach.setFileName(flename);

내 HBM 매핑에서

<property name="data" type="binary" >
            <column name="data" />
</property>

이것은 .PDF, .TXT, .PNG 등과 같은 모든 유형의 파일에서 작동합니다.

참조 URL : https://stackoverflow.com/questions/27609569/file-upload-along-with-other-object-in-jersey-restful-web-service

반응형