Java 文件与 Jersey 宁静网络服务中的其他对象一起上传
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27609569/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
File upload along with other object in Jersey restful web service
提问by Sambit
I want to create an employee information in the system by uploading an image along with employee data. I am able to do it with different rest calls using jersey. But I want to achieve in one rest call. I provide below the structure. Please help me how to do in this regard.
我想通过上传图像和员工数据在系统中创建员工信息。我可以使用球衣通过不同的休息电话来做到这一点。但我想在一次休息电话中实现。我提供下面的结构。请帮我这方面怎么做。
@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
}
Whenever I am trying to do, I get error in Chrome postman. The simple structure of my Employee json is given below.
每当我尝试这样做时,Chrome 邮递员都会出错。下面给出了我的 Employee json 的简单结构。
{
"Name": "John",
"Age": 23,
"Email": "[email protected]",
"Adrs": {
"DoorNo": "12-A",
"Street": "Street-11",
"City": "Bangalore",
"Country": "Karnataka"
}
}
However I can do it by making two different call, but I want to achieve in one rest call so that I can receive the file as well as the actual data of the employee.
但是,我可以通过拨打两个不同的电话来实现,但我想在一个休息电话中实现,以便我可以接收文件以及员工的实际数据。
Request you to help in this regard.
请求您在这方面提供帮助。
回答by Paul Samsotha
You can't have two Content-Type
s (well technically that's what we're doing below, but they are separated with each part of the multipart, but the main type is multipart). That's basically what you are expecting with your method. You are expecting mutlipart andjson together as the main media type. The Employee
data needs to be part of the multipart. So you can add a @FormDataParam("emp")
for the Employee
.
你不能有两个Content-Type
s(技术上这就是我们在下面所做的,但它们与 multipart 的每个部分分开,但主要类型是 multipart)。这基本上就是您对方法的期望。您期望 mutlipart和json 一起作为主要媒体类型。该Employee
数据需要多部分的一部分。所以你可以@FormDataParam("emp")
为Employee
.
@FormDataParam("emp") Employee emp) { ...
Here's the class I used for testing
这是我用于测试的类
@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();
}
}
First I just tested with the client API to make sure it works
首先,我只是用客户端 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();
}
I just created a simple Employee
class with an id
and name
field for testing. This works perfectly fine. It shows the image, prints the content disposition, and prints the Employee
object.
我刚刚创建了一个Employee
带有id
andname
字段的简单类用于测试。这工作得很好。它显示图像,打印内容配置,并打印Employee
对象。
I'm not too familiar with Postman, so I saved that testing for last :-)
我对 Postman 不太熟悉,所以我把那个测试留到最后 :-)
It appears to work fine also, as you can see the response "Cool Tools"
. But if we look at the printed Employee
data, we'll see that it's null. Which is weird because with the client API it worked fine.
正如您所看到的响应,它似乎也能正常工作"Cool Tools"
。但是如果我们查看打印的Employee
数据,我们会发现它是空的。这很奇怪,因为使用客户端 API 时它运行良好。
If we look at the Preview window, we'll see the problem
如果我们查看预览窗口,就会看到问题
There's no Content-Type
header for the emp
body part. You can see in the client API I explicitly set it
正文部分没有Content-Type
标题emp
。您可以在客户端 API 中看到我明确设置了它
MultiPart multipartEntity = new FormDataMultiPart()
.field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
.bodyPart(filePart);
So I guess this is really only partof a full answer. Like I said, I am not familiar with Postman So I don't know how to set Content-Type
s for individual body parts. The image/png
for the image was automatically set for me for the image part (I guess it was just determined by the file extension). If you can figure this out, then the problem should be solved. Please, if you find out how to do this, post it as an answer.
所以我想这实际上只是完整答案的一部分。就像我说的,我不熟悉 Postman 所以我不知道如何Content-Type
为各个身体部位设置s。在image/png
对图像进行自动为我设置的图像部分(我猜它只是由文件扩展名确定)。如果你能弄清楚这一点,那么问题就应该解决了。请,如果您知道如何执行此操作,请将其发布为答案。
And just for completeness...
只是为了完整性......
Basic configurations:
基本配置:
Dependency:
依赖:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey2.version}</version>
</dependency>
Client config:
客户端配置:
final Client client = ClientBuilder.newBuilder()
.register(MultiPartFeature.class)
.build();
Server config:
服务器配置:
// Create JAX-RS application.
final Application application = new ResourceConfig()
.packages("org.glassfish.jersey.examples.multipart")
.register(MultiPartFeature.class);
UPDATE
更新
So as you can see from the Postman client, some clients are unable to set individual parts' Content-Type, this includes the browser, in regards to it's default capabilities when using FormData
(js).
所以正如你从 Postman 客户端看到的,一些客户端无法设置单个部分的 Content-Type,这包括浏览器,关于它在使用FormData
(js)时的默认功能。
We can't expect the client to find away around this, so what we can do, is when receiving the data, explicitly set the Content-Type before deserializing. For example
我们不能指望客户端解决这个问题,所以我们可以做的是,在接收数据时,在反序列化之前显式设置 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);
}
It's a little extra work to get the POJO, but it is a better solution than forcing the client to try and find it's own solution.
获得 POJO 需要一些额外的工作,但它比强迫客户端尝试找到自己的解决方案更好。
Asides
旁白
- There is a conversation in these commentsthat you may be interested in if you are using a different Connector than the default HttpUrlConnection.
- 如果您使用的连接器与默认的 HttpUrlConnection 不同,那么您可能会对这些评论中的某个对话感兴趣。
回答by zameer
You can access the Image File and data from a form using MULTIPART FORM DATA By using the below code.
您可以使用 MULTIPART FORM DATA 从表单访问图像文件和数据,使用以下代码。
@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) {}
}
}
}
回答by pitaside
Your ApplicationConfig should register the MultiPartFeature.class from the glassfish.jersey.media.. so as to enable file upload
您的 ApplicationConfig 应该从 glassfish.jersey.media.. 注册 MultiPartFeature.class 以启用文件上传
@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 Hymanson feature and provider is used for object serialization
//between client and server objects in to a json
register(HymansonFeature.class);
register(HymansonProvider.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);
}
回答by Raman B
I used file upload example from,
我使用了文件上传示例,
http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/
http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/
in my resource class i have below method
在我的资源类中,我有以下方法
@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);
}
in my attachService.java i have below method
在我的 attachService.java 中,我有以下方法
public void saveAttachment(String flename, byte[] is) {
// TODO Auto-generated method stub
attachmentDao.saveAttachment(flename,is);
}
in Dao i have
在道我有
attach.setData(is);
attach.setFileName(flename);
in my HBM mapping is like
在我的 HBM 映射中
<property name="data" type="binary" >
<column name="data" />
</property>
This working for all type of files like .PDF,.TXT, .PNG etc.,
这适用于所有类型的文件,如 .PDF、.TXT、.PNG 等,
回答by mkag
I want add a comment on peeskillet but don't have 50 reputation points, hence adding as an answer:
我想在 peeskillet 上添加评论,但没有 50 声望点,因此添加为答案:
When I tried @peeskillet solution with Jersey client 2.21.1, there was 400 error. It worked when I added following in my client code:
当我使用 Jersey 客户端 2.21.1 尝试 @peeskillet 解决方案时,出现 400 错误。当我在客户端代码中添加以下内容时它起作用了:
MediaType contentType = MediaType.MULTIPART_FORM_DATA_TYPE;
contentType = Boundary.addBoundary(contentType);
Response response = t.request().post(
Entity.entity(multipartEntity, contentType));
instead of hardcoded MediaType.MULTIPART_FORM_DATA in post request call.
而不是在 post 请求调用中硬编码 MediaType.MULTIPART_FORM_DATA。