Téléchargement de fichiers avec d'autres objets dans le service web restful De Jersey

je veux créer une information d'employé dans le système en téléchargeant une image avec les données d'employé. Je peux le faire avec différents appels de repos en utilisant jersey. Mais je veux réaliser dans un appel reste. Je fournis sous la structure. S'il vous plaît aidez-moi à faire à cet égard.

@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

}

chaque fois que j'essaie de le faire, je reçois une erreur dans Chrome postman. La structure simple de mon employé json est donnée ci-dessous.

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

Toutefois, je peux le faire en faisant deux différents d'appel, mais que je veux réaliser dans un appel reste afin que je puisse recevoir le fichier, ainsi que les données réelles de l'employé.

vous demander de l'aide à cet égard.

43
demandé sur Paul Samsotha 2014-12-22 22:59:14

6 réponses

vous ne pouvez pas en avoir deux Content-Type s (bien techniquement c'est ce que nous faisons ci-dessous, mais ils sont séparés avec chaque partie du multipart, mais le type principal est multipart). C'est ce que vous attendez de votre méthode. Vous attendez mutlipart!--24-->et JSON ensemble comme le type de média principal. Employee les données doivent faire partie du multipart. Ainsi, vous pouvez ajouter un @FormDataParam("emp") pour les Employee.

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

Voici la classe que j'ai utilisée pour test

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

tout d'abord je viens de tester avec l'API client pour m'assurer que ça fonctionne

@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
            = "{\n"
            + "    \"id\": 1234,\n"
            + "    \"name\": \"Peeskillet\"\n"
            + "}\n"
            + "";

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

je viens de créer un simple Employee classe id et name champ de test. Cela fonctionne parfaitement bien. Il affiche l'image, IMPRIME la disposition du contenu, et imprime le Employee objet.

Je ne suis pas trop familier avec Postman, donc j'ai gardé ce test pour la fin : -)

enter image description here

Il semble fonctionner bien aussi, comme vous pouvez voir la réponse "Cool Tools". Mais si l'on regarde l'imprimé Employee data, on verra que c'est nul. Ce qui est bizarre car avec l'API client ça a bien fonctionné.

si nous regardons la fenêtre de prévisualisation, nous verrons le problème

enter image description here

Il n'y a pas de Content-Type en-tête emp partie du corps. Vous pouvez voir dans l'API client que je l'ai explicitement défini

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

alors je suppose que c'est vraiment seulement partie d'une réponse complète. Comme je l'ai dit, Je ne suis pas familier avec Postman donc je ne sais pas comment mettre Content-Types pour les différentes parties du corps. image/png car l'image a été automatiquement définie pour moi pour la partie image (je suppose que c'était juste déterminé par l'extension du fichier). Si vous pouvez comprendre cela, alors le problème devrait être résolu. S'il vous plaît, si vous trouvez comment faire cela, poster une réponse.


Et juste pour exhaustivité...

configurations de base:

Dépendance:

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

config du Client:

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

config Server:

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

UPDATE

comme vous pouvez le voir sur le client Postman, certains clients ne sont pas en mesure de définir le type de contenu des différentes parties, ce qui inclut le navigateur, en ce qui concerne c'est la capacité par défaut quand on utilise FormData (js).

nous ne pouvons pas nous attendre à ce que le client trouve quelque chose autour de cela, donc ce que nous pouvons faire, c'est quand nous recevons les données, définir explicitement le type de contenu avant de désérialiser. Par exemple,

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

c'est un peu de travail supplémentaire pour obtenir le POJO, mais c'est une meilleure solution que de forcer le client à essayer de trouver sa propre solution.

75
répondu Paul Samsotha 2018-09-06 18:12:13

vous pouvez accéder au fichier Image et aux données d'un formulaire en utilisant les données du formulaire MULTIPART en utilisant le code ci-dessous.

@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
répondu zameer 2017-05-11 13:21:13

votre ApplicationConfig doit enregistrer la MultiPartFeature.classe de glassfish.Jersey.Média.. afin d'activer le téléchargement de fichier

@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
répondu pitaside 2016-01-04 18:08:44

je veux ajouter un commentaire sur peeskillet, mais n'ont pas de 50 points de réputation, d'où l'ajout d'une réponse:

quand j'ai essayé @peeskillet solution avec le client De Jersey 2.21.1, il y avait 400 erreur. Il a travaillé quand j'ai ajouté la suite dans mon code:

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

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

au lieu de MediaType hardcodé.MULTIPART_FORM_DATA in post request call.

0
répondu mkag 2017-02-03 09:25:39

j'ai utilisé de téléchargement de fichiers exemple,

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

dans ma classe de ressource j'ai la méthode ci-dessous

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

dans mon attachService.java j'ai ci-dessous la méthode

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

        }

dans Dao, j'ai

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

dans mon HBM de la cartographie est de la forme

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

Ce travail pour tous les types de fichiers comme .PDF.,TXT,.PNG etc.,

-2
répondu Raman B 2016-07-20 06:37:00

définir le "type de contenu: multipart / form-data" du côté du client et qui devrait faire le travail

-4
répondu A S 2018-03-13 19:52:30