你不能有两个Content-Type
(从技术上讲,这就是我们下面要做的,但它们与多部分的每个部分分开,但主要类型是多部分)。这基本上就是您对方法的期望。你正在期待多重andjson 一起作为主要媒体类型。这Employee
数据需要是多部分的一部分。所以你可以添加一个@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();
}
我刚刚创建了一个简单的Employee
类与id
and name
场进行测试。这工作得很好。它显示图像,打印内容配置,并打印Employee
object.
我对 Postman 不太熟悉,所以我把测试留到最后:-)
它似乎也工作正常,正如您可以看到的响应"Cool Tools"
。但如果我们看一下印刷的Employee
数据,我们会看到它是空的。这很奇怪,因为使用客户端 API 时它工作得很好。
如果我们查看预览窗口,我们就会看到问题
没有Content-Type
标题为emp
身体的一部分。你可以在客户端API中看到我明确设置了它
MultiPart multipartEntity = new FormDataMultiPart()
.field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
.bodyPart(filePart);
所以我想这真的只是part的完整答案。就像我说的,我对 Postman 不熟悉所以我不知道如何设置Content-Type
s 用于各个身体部位。这image/png
因为图像是自动为我设置的图像部分(我猜它只是由文件扩展名确定)。如果你能弄清楚这一点,那么问题就应该解决了。如果您知道如何执行此操作,请将其作为答案发布。
请参阅下面的更新以获取解决方案
只是为了完整性......
-
请参阅此处,了解有关带有 Jersey 的 MultiPart 的更多信息 https://jersey.github.io/documentation/latest/media.html#multipart.
基本配置:
依赖关系:
<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);
如果您遇到服务器配置问题,以下帖子之一可能会有所帮助
- Jersey 2 中的 ResourceConfig 类到底是什么? https://stackoverflow.com/q/45625925/2587435
- 152 MULTIPART_FORM_DATA:未找到公共 javax.ws.rs.core.Response 类型参数的注入源 https://stackoverflow.com/a/30656345/2587435
UPDATE
因此,正如您从 Postman 客户端中看到的,某些客户端无法设置各个部分的 Content-Type,这包括浏览器,因为它在使用时的默认功能FormData
(js).
我们不能指望客户端能够解决这个问题,所以我们能做的就是在接收数据时,在反序列化之前显式设置 Content-Type。例如
@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 参数并使用任何用于将 String 反序列化为 POJO 的 JSON 库(如 Jackson ObjectMapper)。使用前一个选项,我们只是让 Jersey 处理反序列化,它将使用与所有其他 JSON 端点(可能是首选)相同的 JSON 库。
Asides
- 有一段对话在这些评论 https://stackoverflow.com/a/42020869/2587435如果您使用与默认 HttpUrlConnection 不同的连接器,您可能会对此感兴趣。