文件与泽西岛宁静的 Web 服务中的其他对象一起上传

我想通过上传图像和员工数据在系统中创建员工信息。我能够使用球衣用不同的休息电话来做到这一点。但我想在一次休息中实现。我在结构下面提供。请帮助我在这方面如何做。

@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

}

每当我试图这样做时,我都会在Chrome postman中遇到错误。下面给出了我的员工json的简单结构。

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

但是,我可以通过进行两个不同的调用来执行此操作,但是我想在一次休息调用中实现,以便我可以接收文件以及员工的实际数据。

请您在这方面提供帮助。


答案 1

你不能有两个(从技术上讲,这就是我们下面要做的,但它们与多部分的每个部分分开,但主要类型是多部分)。这基本上就是你对方法的期望。您期望将多个部分和 json 一起作为主要媒体类型。数据需要成为多部分的一部分。因此,您可以为 .Content-TypeEmployee@FormDataParam("emp")Employee

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

这是我用于测试的类

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

首先,我刚刚使用客户端API进行了测试,以确保其正常工作

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

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

我刚刚创建了一个简单的类,其中包含一个用于测试的和字段。这完全可以正常工作。它显示图像,打印内容处置,并打印对象。EmployeeidnameEmployee

我不太熟悉Postman,所以我保存了最后的测试:-)

enter image description here

它似乎也可以正常工作,如您所见 响应 。但是,如果我们查看打印的数据,我们将看到它为空。这很奇怪,因为使用客户端API可以正常工作。"Cool Tools"Employee

如果我们查看“预览”窗口,我们将看到问题

enter image description here

正文部分没有标题。你可以看到在客户端API中我显式设置了它Content-Typeemp

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

所以我想这真的只是完整答案的一部分。就像我说的,我不熟悉邮递员,所以我不知道如何为个别身体部位设置s。图像的自动为我设置了图像部分(我猜它只是由文件扩展名决定的)。如果你能弄清楚这一点,那么问题应该得到解决。请,如果您发现如何执行此操作,请将其作为答案发布。Content-Typeimage/png

请参阅下面的更新以获取解决方案


只是为了完整性...

基本配置:

屬地:

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

客户端配置:

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

服务器配置:

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

如果您在服务器配置方面遇到问题,以下帖子之一可能会有所帮助


更新

因此,从Postman客户端可以看出,某些客户端无法设置单个部分的Content-Type,这包括浏览器,关于使用(js)时的默认功能。FormData

我们不能指望客户端找到绕过这一点,所以我们能做的就是在接收数据时,在反序列化之前显式设置内容类型。例如

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

获得POJO需要一些额外的工作,但与强迫客户尝试找到自己的解决方案相比,这是一个更好的解决方案。

另一种选择是使用 String 参数,并使用您使用的任何 JSON 库将 String 反序列化为 POJO(如 Jackson ObjectMapper)。使用上一个选项,我们只让 Jersey 处理反序列化,它将使用与所有其他 JSON 终结点相同的 JSON 库(可能是首选)。


旁白

  • 这些注释中有一个对话,如果您使用的连接器与默认的 HttpUrlConnection 不同,您可能会对此感兴趣。

答案 2

您可以使用以下代码访问图像文件和表单中的数据,使用多部分表单数据。

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