Upload de arquivo junto com outro object no serviço web sossegado de Jersey

Eu quero criar uma informação de funcionário no sistema fazendo o upload de uma imagem junto com os dados do funcionário. Eu posso fazer isso com diferentes chamadas de descanso usando jersey. Mas eu quero conseguir em uma chamada de descanso. Eu forneço abaixo da estrutura. Por favor me ajude como fazer a esse respeito.

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

Sempre que eu estou tentando fazer, recebo erro no carteiro do Chrome. A estrutura simples do meu Employer json é dada abaixo.

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

No entanto, posso fazê-lo fazendo duas chamadas diferentes, mas quero alcançar em uma chamada de descanso para que eu possa receber o arquivo, bem como os dados reais do funcionário.

Peça-lhe para ajudar nesse sentido.

Você não pode ter dois Content-Type (tecnicamente, é o que estamos fazendo abaixo, mas eles são separados em cada parte do multipart, mas o tipo principal é multipart). Isso é basicamente o que você está esperando com o seu método. Você está esperando mutlipart e json juntos como o principal tipo de mídia. Os dados do Employee precisam fazer parte do multipart. Então você pode adicionar um @FormDataParam("emp") para o Employee .

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

Aqui está a aula que usei para testar

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

Primeiro testei com a API do cliente para ter certeza de que funciona

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

Acabei de criar uma class Employee simples com um campo id e name para teste. Isso funciona perfeitamente bem. Mostra a imagem, imprime a disposição do conteúdo e imprime o object Employee .

Eu não estou muito familiarizado com o Postman, então eu salvei o teste para o final 🙂

insira a descrição da imagem aqui

Parece funcionar bem também, como você pode ver a resposta "Cool Tools" . Mas se olharmos para os dados impressos dos Employee , veremos que é nulo. O que é estranho porque com a API do cliente funcionou bem.

Se olharmos para a janela de visualização, veremos o problema

insira a descrição da imagem aqui

Não há header Content-Type para a parte do corpo emp . Você pode ver na API do cliente que eu defini explicitamente

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

Então eu acho que isso é apenas parte de uma resposta completa. Como eu disse, eu não estou familiarizado com o Postman. Então eu não sei como definir o Content-Type para partes individuais do corpo. A image/png da imagem foi explicitamente definida para mim para a parte da imagem. Se você puder descobrir isso, o problema deve ser resolvido. Por favor, se você descobrir como fazer isso, poste como uma resposta.


E só por completude …

  • Veja aqui mais sobre o MultiPart com Jersey .

Configurações básicas:

Dependência:

  org.glassfish.jersey.media jersey-media-multipart ${jersey2.version}  

Configuração do cliente:

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

Configuração do servidor:

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

ATUALIZAR

Assim, como você pode ver no cliente Postman, alguns clientes não podem definir partes individuais do tipo de conteúdo, isso inclui o navegador, no que diz respeito às suas capacidades padrão ao usar FormData (js).

Não podemos esperar que o cliente descubra isso, então o que podemos fazer é, ao receber os dados, definir explicitamente o Tipo de Conteúdo antes de desserializar. Por exemplo

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

É um pouco de trabalho extra para obter o POJO, mas é uma solução melhor do que forçar o cliente a tentar encontrar sua própria solução.

Você pode acessar o arquivo de imagem e os dados de um formulário usando o MULTIPART FORM DATA usando o código abaixo.

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

Seu ApplicationConfig deve registrar o MultiPartFeature.class a partir do glassfish.jersey.media .. para permitir o upload de arquivos

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

Eu usei o exemplo de upload de arquivo de

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

na minha class de resources eu tenho abaixo método

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

no meu attachService.java eu ​​tenho abaixo método

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

no Dao eu tenho

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

no meu mapeamento HBM é como

    

Isso funciona para todos os tipos de arquivos como .PDF, .TXT, .PNG etc.,

Eu quero adicionar um comentário sobre peeskillet mas não tem 50 pontos de reputação, portanto, adicionando como uma resposta:

Quando tentei a solução @peeskillet com o cliente Jersey 2.21.1, houve 400 erros. Funcionou quando adicionei o seguinte no meu código de cliente:

  MediaType contentType = MediaType.MULTIPART_FORM_DATA_TYPE; contentType = Boundary.addBoundary(contentType); Response response = t.request().post( Entity.entity(multipartEntity, contentType)); 

em vez de MediaType codificado.MULTIPART_FORM_DATA na chamada pós-solicitação.

Definir o “Content-Type: multipart / form-data” no lado do cliente e que deve fazer o trabalho