I need to consume a request whose content-type is multipart/related. Request will consist of image, json payload and binary content. I tried to find some example on how to handle such request in a Spring boot application, I found some references on how to handle multipart/form-data request but nothing related to multipart/related mime type.
Request is something like this:
POST /upload
Content-Type: multipart/related; boundary="123asdf234"
--123asdf234
Content-Type: application/json; charset=UTF-8
Content-Disposition: form-data
{
"json": "payload"
}
—-123asdf234
Content-Type: application/zip
Content-Disposition: file-data; filename="some.zip"; size=123456;
<binary-attachment-content>
—-123asdf234
Content-Type: image/png
Content-Disposition: file-data; filename="image1.png"; size=123456;
<binary-attachment-content>
—-123asdf234-—
Can someone tell on how to handle this request in Spring boot application. I'm using JaxRS.
To solve this I first referred to http://cxf.apache.org/docs/jax-rs-multiparts.html to properly understand multipart/related in relation to JAX-RS. Next I referred to the Spring documentation on JAX-RS and chose to use the Jersey dependency to solve it. Then referring to the Jersey documentation I build the following test project: https://github.com/ShawnTuatara/stackoverflow-38838926. The main example is:
package ca.tuatara.stackoverflow;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.media.multipart.BodyPart;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;
@SpringBootApplication
public class Stackoverflow38838926Application {
public static void main(String[] args) {
SpringApplication.run(Stackoverflow38838926Application.class, args);
}
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(MultiPartFeature.class);
register(MultipartHandler.class);
register(MultipartPartsHandler.class);
}
}
@Component
@Path("/upload")
@Consumes("multipart/*")
@Produces("text/text")
public class MultipartHandler {
@POST
public String upload(MultiPart request) {
StringBuffer response = new StringBuffer();
for (BodyPart part : request.getBodyParts()) {
if (MediaType.APPLICATION_JSON_TYPE.isCompatible(part.getMediaType())) {
response.append(part.getEntityAs(JsonModel.class));
} else if (MediaType.APPLICATION_XML_TYPE.isCompatible(part.getMediaType())) {
response.append(part.getEntityAs(XmlModel.class));
}
response.append(System.lineSeparator());
}
return response.toString();
}
}
@Component
@Path("/uploadParts")
@Consumes("multipart/*")
@Produces("text/text")
public class MultipartPartsHandler {
@POST
public String upload(@FormDataParam("json") JsonModel json, @FormDataParam("xml") XmlModel xml) {
return json + System.lineSeparator() + xml;
}
}
}
The test shows how to send the multipart requests. I have kept in some DEBUG logging so you can see exactly what is going over the wire when the test runs.
There was a couple issues with your original POST payload that won't allow it to be parsed properly. The content has to have a newline between the headers and the content. If you don't provide a "name" property for the Content-Disposition then you can only use the first example ("/upload"). If you do name the form-data then you can use the second example ("/uploadParts"). I didn't do the example with the image or file upload but if you read the Jersey multipart page you can see it is straightforward to add that parameter input on the request method.