画像を従業員データとともにアップロードして、システムに従業員情報を作成したい。私はジャージを使用して、さまざまな休憩通話でそれを行うことができます。しかし、私は1回の休憩で達成したいです。構造の下に提供します。この点で行う方法を教えてください。
@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郵便配達員でエラーが発生します。私の従業員jsonの単純な構造を以下に示します。
{
"Name": "John",
"Age": 23,
"Email": "[email protected]",
"Adrs": {
"DoorNo": "12-A",
"Street": "Street-11",
"City": "Bangalore",
"Country": "Karnataka"
}
}
ただし、2つの異なる呼び出しを行うことでそれを行うことができますが、ファイルと従業員の実際のデータを受信できるように、1つの残りの呼び出しで達成したいです。
この点であなたに助けを求める。
2つのContent-Type
を使用することはできません(技術的には以下で行っていますが、それらはマルチパートの各部分で分離されていますが、メインタイプはマルチパートです)。それは基本的にあなたのメソッドで期待していることです。メインメディアタイプとして、マルチパートandjsonを一緒に期待しています。 Employee
データは、マルチパートの一部である必要があります。したがって、Employee
に@FormDataParam("emp")
を追加できます。
@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
フィールドを持つ単純なname
クラスを作成しました。これは完璧に機能します。画像を表示し、コンテンツの性質を印刷し、Employee
オブジェクトを印刷します。
私はPostmanにあまり詳しくないので、最後にテストを保存しました:-)
応答"Cool Tools"
を確認できるように、正常に動作しているように見えます。しかし、印刷されたEmployee
データを見ると、nullであることがわかります。これは、クライアントAPIでうまく機能したため、奇妙です。
プレビューウィンドウを見ると、問題がわかります
emp
本文部分にContent-Type
ヘッダーはありません。クライアントAPIで明示的に設定したことがわかります。
MultiPart multipartEntity = new FormDataMultiPart()
.field("emp", empPartJson, MediaType.APPLICATION_JSON_TYPE)
.bodyPart(filePart);
だから、これは本当に完全な答えの一部partだけだと思います。私が言ったように、私はPostmanに精通していないので、個々の身体部分にContent-Type
sを設定する方法がわかりません。画像のimage/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クライアントからわかるように、一部のクライアントは、FormData
(js)を使用する場合のデフォルト機能に関して、個々のパーツのContent-Typeを設定できません。これにはブラウザーも含まれます。
クライアントがこれを回避することを期待することはできません。したがって、できることは、データを受信するときに、デシリアライズする前に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を入手するのは少し余分な作業ですが、クライアントに独自のソリューションを見つけさせようとするよりも優れたソリューションです。
以下のコードを使用して、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) {}
}
}
}
Peeskilletにコメントを追加したいのですが、50レピュテーションポイントを持っていないので、答えとして追加します。
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));
リクエスト後の呼び出しでハードコードされたMediaType.MULTIPART_FORM_DATAの代わりに。
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 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);
}