2011-04-24 17 views
12

Estoy tratando de cargar un archivo y otros datos de formulario usando el cliente multipart/form-data con Jersey. Estoy cargando a un servicio web REST también usando Jersey. Aquí está el código del servidor:Intentando cargar un archivo en un servidor JAX-RS (jersey)

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

He probado el código del servidor mediante un formulario HTML básico en mi escritorio y funciona bien. El problema parece estar en el cliente. Aquí está el código de cliente relevante.

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

que estoy recibiendo una respuesta desde el servidor 400 "La solicitud enviada por el cliente era sintácticamente incorrecto"

Aquí es el mensaje que se escupió del registrador, éste es sin un archivo para mantener la salida breve:

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é estoy haciendo mal en el cliente para que esto funcione correctamente?

+0

muestra: http://puspendu.wordpress.com/2012/08/23/restful-webservice-file-upload-with-jersey/ –

+0

la opción que hizo configurado para mostrar el cuerpo de la solicitud, he habilitado 'ServerProperties.TRACING = ALL' y' ServerProperties.TRACING_THRESHOLD = VERBOSE'. Pero no muestra el cuerpo de solicitud –

Respuesta

30

Si desea agregar cadenas al FormDataMultiPart simplemente utilice el método .field("name", "value") de la misma manera que se utiliza para el archivo adjunto (queryParam no funciona).

A continuación se muestra un ejemplo de trabajo:

En primer lugar, la parte del servidor que devuelve el contenido del archivo de lectura como una cadena:

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

En segundo lugar, el método de cliente publicar el archivo:

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

En tercer lugar, el entorno de prueba:

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

Por último, las dependencias de 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> 

El file.txt es en la raíz de la ruta de clase y contiene Hello, World.

+0

Los parámetros de consulta realmente se usan para obtener operaciones que no forman opts. El problema terminó siendo un error en Netbeans 6.9.1. No incluyen un frasco requerido. La única solución es actualizar Netbeans 7. – Ruggs

+0

No veo cómo Netbeans puede ser parte del problema. Ver mi respuesta actualizada –

+0

No estaba usando maven para administrar las bibliotecas y netbeans cuando agregaba las bibliotecas jax-rs. Faltaba mimepull.jar. Puede encontrar varios números de ticket relacionados con este problema en Netbeans bugzilla. – Ruggs

-2

o simplemente escribir un nuevo archivo y subirlo:

Writer output = null; 
    File file = null; 
    try { 
     String text = "Rajesh Kumar"; 
     file = new File("write.txt"); 
     output = new BufferedWriter(new FileWriter(file)); 
     output.write(text); 
     output.close(); 
    } catch (IOException e) { 
     System.out.println("IOException e"); 
     e.printStackTrace(); 
    } 

    InputStream is = null; 

    try { 
     is = new FileInputStream(file); 
    } catch (FileNotFoundException e) { 
     System.out.println("FileNotFoundException e"); 
     e.printStackTrace(); 
    } catch (IOException e) { 
     System.out.println("IOException e"); 
     e.printStackTrace(); 
    } 

    FormDataMultiPart part = new FormDataMultiPart().field("file", is, MediaType.TEXT_PLAIN_TYPE); 
    res = service.path("rest").path("tenant").path(tenant1.getTenantId()).path("file").type(MediaType.MULTIPART_FORM_DATA_TYPE).post(ClientResponse.class, part); 
2

solución Yves no funcionó para mí en el lado del cliente. miré un poco y encontró:

de los cuales no trabajaría con mi camiseta actual 1,18 (véase el extracto de pom abajo). La mayoría de los problemas se produjeron en el lado del cliente.Me gustaría obtener mensajes de error como:

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) 

El lado del servidor trabajó rápidamente con este código (que no hace nada interesante con InputStream subida todavía - ajuste a sus necesidades)

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

la lado del cliente trabajaría con este código:

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

extracto de 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> 
0

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

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) realmente ayuda a mejorar la calidad de su enviar. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. – NathanOliver

Cuestiones relacionadas