web-dev-qa-db-fra.com

Essayer de télécharger un fichier sur un serveur JAX-RS (maillot)

J'essaie de télécharger un fichier et d'autres données de formulaire à l'aide d'un client multipart/form-data avec Jersey. Je télécharge sur un service Web REST utilisant également Jersey. Voici le code du serveur:

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public String create(@FormDataParam("file") InputStream file,
        @FormDataParam("file") FormDataContentDisposition fileInfo,
        @FormDataParam("name") String name,
        @FormDataParam("description") String description) {
    Ingredient ingredient = new Ingredient();
    ingredient.setName(name);
    ingredient.setDescription(description);
    ingredient.setImageName(fileInfo.getFileName());
    ingredient.setImagePath(context.getRealPath("/resources/uploads/"));
    // TODO save the file.
    try {
        JSONObject json = new JSONObject();
        try {
            ingredientService.create(ingredient);
        } catch (final InvalidParameterException ex) {
            logger.log(Level.INFO, ex.getMessage());
            json.put("result", false);
            json.put("error", ex.getMessage());
            return json.toString();
        } catch (final GoodDrinksException ex) {
            logger.log(Level.WARNING, null, ex);
            json.put("result", false);
            json.put("error", ex.getMessage());
            return json.toString();
        }
        json.put("ingredient", JsonUtil.ingredientToJSON(ingredient));
        return json.put("result", true).toString();
    } catch (JSONException ex) {
        logger.log(Level.SEVERE, null, ex);
        return "{\"result\",false}";
    }
}

J'ai testé le code du serveur en utilisant un formulaire HTML de base sur mon bureau et cela fonctionne bien. Le problème semble être dans le client. Voici le code client pertinent.

ClientConfig config = new DefaultClientConfig();
client = Client.create(config);
client.addFilter(new LoggingFilter());
webResource = client.resource("http://localhost:8080/webapp/resources").path("ingredient");
FormDataMultiPart fdmp = new FormDataMultiPart();
if (file != null) {
    fdmp.bodyPart(new FileDataBodyPart("file", file, MediaType.APPLICATION_OCTET_STREAM_TYPE));
}
fdmp.bodyPart(new FormDataBodyPart("name", ingredient.getName()));
fdmp.bodyPart(new FormDataBodyPart("description", ingredient.getDescription()));

ClientResponse response = webResource.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(ClientResponse.class, fdmp);
String string = response.getEntity(String.class);
logger.log(Level.INFO, "response: {0}", string);

Je reçois une réponse 400 du serveur "La requête envoyée par le client était syntaxiquement incorrecte"

Voici le message qui sort du logger, celui-ci est sans fichier pour garder la sortie brève:

1 > POST http://localhost:8080/webapp/resources/ingredient  
1 > Content-Type: multipart/form-data  
1 >   
--Boundary_5_1545082086_1303666703655  
Content-Type: text/plain  
Content-Disposition: form-data;name="name"  
Adam  
--Boundary_5_1545082086_1303666703655  
Content-Type: text/plain  
Content-Disposition: form-data;name="description"  
Test  
--Boundary_5_1545082086_1303666703655--  

Qu'est-ce que je fais mal chez le client pour que cela fonctionne correctement?

12
Ruggs

Si vous souhaitez ajouter des chaînes à la FormDataMultiPart, utilisez simplement la méthode .field("name", "value") de la même manière que pour la pièce jointe (queryParam ne fonctionne pas).

Vous trouverez ci-dessous un exemple de travail:

Tout d’abord, la partie serveur qui renvoie le contenu du fichier lu sous forme de chaîne: 

@Path("file")
public class FileResource {

    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response handleUpload(@FormDataParam("file") InputStream stream) throws Exception {
        return Response.ok(IOUtils.toString(stream)).build();
    }
}

Deuxièmement, la méthode client qui poste le fichier:

public void upload(String url, String fileName) {
    InputStream stream = getClass().getClassLoader().getResourceAsStream(fileName);
    FormDataMultiPart part = new FormDataMultiPart().field("file", stream, MediaType.TEXT_PLAIN_TYPE);

    WebResource resource = Client.create().resource(url);
    String response = resource.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, part);
    assertEquals("Hello, World", response);
}

Troisièmement, l'environnement de test:

Server server;

@Before
public void before() throws Exception {
    server = new Server(8080);
    server.addHandler(new WebAppContext(WEB_INF_DIRECTORY, "/"));
    server.start(); 
}

@After
public void after() throws Exception {
    server.stop();
}

@Test
public void upload() {
    upload("http://localhost:8080/file", "file.txt");
}

Enfin, les dépendances maven:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.Sun.jersey</groupId>
        <artifactId>jersey-server</artifactId>
        <version>1.6</version>
    </dependency>
    <dependency>
        <groupId>com.Sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.6</version>
    </dependency>
    <dependency>
        <groupId>com.Sun.jersey.contribs</groupId>
        <artifactId>jersey-multipart</artifactId>
        <version>1.6</version>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-embedded</artifactId>
        <version>6.1.26</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.0.1</version>
    </dependency>
</dependencies>

Le file.txt est à la racine du classpath et contient Hello, World.

30
yves amsellem

La solution Yves ne fonctionnait pas pour moi du côté client. J'ai regardé un peu autour de moi et trouvé:

ce qui ne fonctionnerait pas avec mon maillot actuel 1,18 (voir l'extrait de pom ci-dessous). La plupart des ennuis étaient du côté client. Je voudrais recevoir des messages d'erreur comme:

com.Sun.jersey.api.client.ClientHandlerException: javax.ws.rs.WebApplicationException: Java.lang.IllegalArgumentException: Missing body part entity of type 'text/plain'
at com.Sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.Java:155)
at com.Sun.jersey.api.client.Client.handle(Client.Java:652)
at com.Sun.jersey.api.client.WebResource.handle(WebResource.Java:682)

Le côté serveur a travaillé rapidement avec ce code (ce qui ne fait rien d’intéressant avec Encore le InputStream téléchargé - adapté à vos besoins)

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("text/plain")
public Response uploadFile(
        @FormDataParam("content") final InputStream uploadedInputStream,
        @FormDataParam("fileName") String fileName) throws IOException {
    String uploadContent=IOUtils.toString(uploadedInputStream);
    return Response.ok(uploadContent).build();
}   

le côté client fonctionnerait avec ce code:

import Java.io.File;
import Java.io.FileInputStream;
import Java.io.IOException;   
import javax.ws.rs.core.MediaType;

import com.Sun.jersey.api.client.Client;
import com.Sun.jersey.api.client.WebResource;
import com.Sun.jersey.multipart.FormDataBodyPart;
import com.Sun.jersey.multipart.FormDataMultiPart;
/**
 * upload the given file
 * 
 * inspired by
 * http://neopatel.blogspot.de/2011/04/jersey-posting-multipart-data.html
 * 
 * @param url
 * @param uploadFile
 * @return the result
 * @throws IOException
 */
public String upload(String url, File uploadFile) throws IOException {
    WebResource resource = Client.create().resource(url);
    FormDataMultiPart form = new FormDataMultiPart();
    form.field("fileName", uploadFile.getName());
    FormDataBodyPart fdp = new FormDataBodyPart("content",
            new FileInputStream(uploadFile),
            MediaType.APPLICATION_OCTET_STREAM_TYPE);
    form.bodyPart(fdp);
    String response = resource.type(MediaType.MULTIPART_FORM_DATA).post(String.class, form);
    return response;
}

extrait pom.xml:

<properties>
  <jersey.version>1.18</jersey.version>
</properties>
<dependency>
  <groupId>com.Sun.jersey</groupId>
  <artifactId>jersey-server</artifactId>
  <version>${jersey.version}</version>
</dependency>
<dependency>
  <groupId>com.Sun.jersey</groupId>
  <artifactId>jersey-client</artifactId>
  <version>${jersey.version}</version>
</dependency>
<!--  Multipart support -->
<dependency>
  <groupId>com.Sun.jersey.contribs</groupId>
  <artifactId>jersey-multipart</artifactId>
  <version>${jersey.version}</version>
</dependency>
2
Wolfgang Fahl

public DssResponse callPut(String url, Map<String, String> headers, FileDataBodyPart[] filePath, String boundary, String[] jsonString) throws IOException {
    Client client = ClientBuilder.newClient().register(MultiPartFeature.class);
    WebTarget webTarget = client.target(url);
    Builder builder = webTarget.request(MediaType.MULTIPART_FORM_DATA);
    FormDataMultiPart multiPart = new FormDataMultiPart();
    for (int i = 0; i < filePath.length; i++) {

        if (!filePath[i].getFileEntity().exists()) {
            throw new IOException("Invalid Input File - " + filePath[i].getFileEntity().getAbsolutePath());
        }

        multiPart.bodyPart(new FileDataBodyPart(filePath[i].getName(), filePath[i].getFileEntity()));
    }

    if (boundary != null)
        multiPart.type(Boundary.addBoundary(new MediaType("multipart", "form-data", Collections.singletonMap(Boundary.BOUNDARY_PARAMETER, boundary))));
    for (String jstr : jsonString) {
        multiPart.field("Content-Type", jstr, MediaType.APPLICATION_JSON_TYPE);
    }
    if (headers != null) {
        for (Entry<String, String> header : headers.entrySet()) {
            builder.header(header.getKey(), header.getValue());
            System.out.println(header.getKey() + "===============>>" + header.getValue());
        }
    }

    Response response = builder.accept(MediaType.APPLICATION_JSON).put(Entity.entity(multiPart, multiPart.getMediaType()));

    multiPart.close();

    // Assert.assertNotNull(response);
    if (response == null )
        throw new IOException ("Response is NULL");

    int status = response.getStatus();

    return dssResponse;
}
0
Vittal Manikonda