wake-up-neo.com

Versuch, eine Datei auf einen JAX-RS-Server (Jersey) hochzuladen

Ich versuche, eine Datei und andere Formulardaten mit einem Multipart/Formulardaten-Client mit Jersey hochzuladen. Ich lade in einen REST-Webservice hoch, der auch Jersey verwendet. Hier ist der Servercode:

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

Ich habe den Servercode mit einem einfachen HTML-Formular auf meinem Desktop getestet und funktioniert einwandfrei. Das Problem scheint im Client zu liegen. Hier ist der entsprechende Kundencode.

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

Ich erhalte eine 400-Antwort vom Server "Die vom Client gesendete Anforderung war syntaktisch falsch"

Hier ist die Nachricht, die aus dem Logger ausgespuckt wird. Diese enthält keine Datei, um die Ausgabe kurz zu halten:

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--  

Was mache ich falsch im Client, damit das korrekt funktioniert?

12
Ruggs

Wenn Sie Strings zur FormDataMultiPart hinzufügen möchten, verwenden Sie einfach die .field("name", "value")-Methode auf dieselbe Weise, wie sie für den Dateianhang verwendet wird (queryParam funktioniert nicht).

Unten ist eine Arbeitsprobe:

Zuerst der Serverteil, der den Inhalt der gelesenen Datei als String zurückgibt: 

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

Zweitens, die Client-Methode, die die Datei bereitstellt:

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

Drittens die Testumgebung:

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

Zum Schluss noch die Maven-Abhängigkeiten:

<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>

Der file.txt befindet sich im Stammverzeichnis des Klassenpfads und enthält Hello, World.

30
yves amsellem

Die Lösung von Yves hat auf der Clientseite für mich nicht funktioniert. Ich sah mich ein wenig um und fand Folgendes:

keines davon würde mit meinem aktuellen Trikot 1.18 funktionieren (siehe Pom-Auszug unten). Das meiste Ärger war auf der Kundenseite. Ich würde Fehlermeldungen erhalten wie:

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)

Die Serverseite hat schnell mit diesem Code gearbeitet (was mit Dem hochgeladenen InputStream noch nichts interessantes macht - passend zu Ihren Anforderungen)

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

die Client-Seite würde mit diesem Code funktionieren:

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

pom.xml extract:

<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