wake-up-neo.net

Datei-Upload zusammen mit anderen Objekten in Jersey

Ich möchte eine Mitarbeiterinformation im System erstellen, indem Sie ein Bild zusammen mit den Mitarbeiterdaten hochladen. Ich kann es mit verschiedenen Ruheanrufen mit Trikot machen. Aber ich möchte in einem Ruhezustand erreichen . Ich gebe unterhalb der Struktur. Bitte helfen Sie mir, wie Sie diesbezüglich tun können.

@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

}

Bei jedem Versuch erhalte ich eine Fehlermeldung in Chrome Postman. Die einfache Struktur meines Employee Json ist unten angegeben.

{
    "Name": "John",
    "Age": 23,
    "Email": "[email protected]",
    "Adrs": {
        "DoorNo": "12-A",
        "Street": "Street-11",
        "City": "Bangalore",
        "Country": "Karnataka"
    }
}

Ich kann es jedoch mit zwei verschiedenen Anrufen tun, aber ich möchte in einem Ruhezustand erreichen, dass ich die Datei sowie die tatsächlichen Daten des Angestellten erhalten kann.

Bitten Sie um Hilfe in dieser Hinsicht.

48
Sambit

Sie können nicht zwei Content-Type Haben (technisch gesehen machen wir das unten, aber sie sind mit jedem Teil des Multiparts getrennt, aber der Haupttyp ist Multipart). Das ist im Grunde, was Sie mit Ihrer Methode erwarten. Sie erwarten, dass als Hauptmedientyp mehrere Teile und json verwendet werden. Die Employee Daten müssen Teil des Multiparts sein. Sie können also eine @FormDataParam("emp") für die Employee hinzufügen.

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

Hier ist die Klasse, die ich zum Testen verwendet habe

@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();
    } 
}

Zuerst habe ich nur mit der Client-API getestet, um sicherzustellen, dass es funktioniert

@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();
}

Ich habe gerade eine einfache Employee -Klasse mit einem id - und name -Feld zum Testen erstellt. Das funktioniert einwandfrei. Es zeigt das Bild, druckt die Inhaltsdisposition und druckt das Objekt Employee.

Ich kenne mich mit Postman nicht so gut aus, also habe ich diese Tests zum Schluss gespeichert :-)

enter image description here

Es scheint auch gut zu funktionieren, wie Sie die Antwort sehen können "Cool Tools". Wenn wir uns jedoch die gedruckten Employee -Daten ansehen, werden wir feststellen, dass sie null sind. Was seltsam ist, weil es mit der Client-API gut funktioniert hat.

Wenn wir uns das Vorschaufenster ansehen, werden wir das Problem sehen

enter image description here

Es gibt keinen Content-Type - Header für den Hauptteil von emp. Sie können in der Client-API sehen, dass ich es explizit festgelegt habe

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

Ich denke, das ist wirklich nur ein Teil einer vollständigen Antwort. Wie gesagt, ich kenne mich mit Postman nicht aus. Daher weiß ich nicht, wie man Content-Type Für einzelne Körperteile einstellt. Das image/png Für das Bild wurde automatisch für den Bildteil festgelegt (ich denke, es wurde nur durch die Dateierweiterung bestimmt). Wenn Sie dies herausfinden können, sollte das Problem gelöst sein. Bitte, wenn Sie herausfinden, wie das geht, posten Sie es als Antwort.


Und nur der Vollständigkeit halber ...

Grundlegende Konfigurationen:

Abhängigkeit:

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

Client-Konfiguration:

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

Serverkonfiguration:

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

AKTUALISIEREN

Wie Sie auf dem Postman-Client sehen können, können einige Clients den Inhaltstyp einzelner Teile nicht festlegen. Dies schließt den Browser hinsichtlich seiner Standardfunktionen ein, wenn FormData (js) verwendet wird.

Wir können nicht davon ausgehen, dass der Client dies herausfindet. Wir können also beim Empfang der Daten den Inhaltstyp vor der Deserialisierung explizit festlegen. Zum Beispiel

@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);
}

Es ist ein wenig mehr Arbeit, um das POJO zu bekommen, aber es ist eine bessere Lösung, als den Kunden zu zwingen, zu versuchen, eine eigene Lösung zu finden.


Nebenbei

  • Es gibt eine Konversation in diese Kommentare , die Sie möglicherweise interessiert, wenn Sie einen anderen Connector als die Standard-HttpUrlConnection verwenden.
86
Paul Samsotha

Sie können auf die Image-Datei und Daten von einem Formular aus mit MULTIPART FORM DATA zugreifen.

@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) {}
        }
    }
}
1
zameer

Ich möchte einen Kommentar zu peeskillet hinzufügen, habe aber keine 50 Reputationspunkte und füge als Antwort hinzu:

Als ich die @peeskillet-Lösung mit dem Jersey-Client 2.21.1 ausprobierte, gab es 400 Fehler. Es hat funktioniert, als ich folgendes in meinen Client-Code eingefügt habe:

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

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

anstelle von fest codiertem MediaType.MULTIPART_FORM_DATA beim Aufruf nach der Anforderung.

0
mkag

Ihre ApplicationConfig sollte die MultiPartFeature.class von glassfish.jersey.media .. registrieren, um das Hochladen von Dateien zu ermöglichen

@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);
    }
0
pitaside