I have a D3
graph generated on client side. I send the SVG
data to Jersey
REST service convert the SVG
data to image ( OutputStream
) using Transcoding
. When I return the response from service I could see the data returned as binary stream in console.
What I want is a browser download window to popup as soon as the service returns the response.
Following is the code snippet:
@POST
@Path("downloadSVG")
@Produces("image/png")
public javax.ws.rs.core.Response downloadSVG(@Context HttpServletRequest request, @Context HttpServletResponse httpServletResponse,String values){
LOGGER.info("Inside downloadSVG service.");
javax.ws.rs.core.Response graphImage = null;
JSONObject data = new JSONObject(values);
String svgXML = data.get("svgURL").toString();
try {
OutputStream os = httpServletResponse.getOutputStream();
JPEGTranscoder t = new JPEGTranscoder();
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(.8));
InputStream is = new ByteArrayInputStream(svgXML.getBytes());
TranscoderInput input = new TranscoderInput(is);
TranscoderOutput output = new TranscoderOutput(os);
t.transcode(input, output);
LOGGER.info("Graph image generated. Trying to return it to client.");
graphImage = javax.ws.rs.core.Response.ok(os).header("Content-Disposition", "attachment;
filename=graph.png").type("image/png").build();
os.flush();
os.close();
} catch (IOException e1) {
e1.printStackTrace();
} catch (TranscoderException e) {
e.printStackTrace();
}
return graphImage;
}
Once this service is called I get following Exception
on server console:
SLF4J: This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version
Jan 03, 2014 3:21:32 PM com.sun.jersey.spi.container.ContainerResponse write
SEVERE: A message body writer for Java class org.apache.catalina.connector.CoyoteOutputStream, and Java type class org.apache.catalina.connector.CoyoteOutputStream, and MIME media type image/png was not found
Jan 03, 2014 3:21:32 PM com.sun.jersey.spi.container.ContainerResponse write
SEVERE: The registered message body writers compatible with the MIME media type are:
image/* ->
com.sun.jersey.core.impl.provider.entity.RenderedImageProvider
*/* ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.MimeMultipartProvider
com.sun.jersey.core.impl.provider.entity.StringProvider
.
.
Jan 03, 2014 3:21:32 PM com.sun.jersey.spi.container.ContainerResponse logException
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException: com.sun.jersey.api.MessageException: A message body writer for Java class org.apache.catalina.connector.CoyoteOutputStream, and Java type class org.apache.catalina.connector.CoyoteOutputStream, and MIME media type
image/png was not found
at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:285)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1448)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1360)
.
.
.
Caused by: com.sun.jersey.api.MessageException: A message body writer for Java class org.apache.catalina.connector.CoyoteOutputStream, and Java type class org.apache.catalina.connector.CoyoteOutputStream, and MIME media type image/png was not found
... 56 more
I think I am missing some Jersey dependency.
Any pointers are highly appreciated. Thanks in advance.
I think I am missing some Jersey dependency.
No I don't think so... I believe the fundamental issue is that you can't directly manipulate the response OutputStream and return a Response from your downloadSVG method.
Any pointers are highly appreciated.
A cleaner approach would be to separate the logic that constructs the image from the logic that renders the image to the client. Check out MessageBodyWriter . It gives you access to the request OutputStream and allows you to manipulate the response headers.
Here's what I would do:
1) Create a new class (MyPNG). Modify your REST method to return MyPNG rather than Response and mark it with a @Produces tag.
@Produces("image/png")
public MyPNG downloadSVG(@Context HttpServletRequest request, @Context HttpServletResponse httpServletResponse,String values){
2) In your REST method, read the InputStream and create and return a new instance of MyPNG
3) Implement MessageBodyWriter and do something like this in the writeTo method:
public PNGMessageBodyWriter implements MessageBodyWriter<MyPNG> {
....
boolean isWriteable(java.lang.Class<?> type,
java.lang.reflect.Type genericType,
java.lang.annotation.Annotation[] annotations,
MediaType mediaType)
{
return mediaType.toString.equals("image/png");
}
....
void writeTo(MyJPEG instance, java.lang.Class<?> type, java.lang.reflect.Type genericType, java.lang.annotation.Annotation[] annotations,
MediaType mediaType, MultivaluedMap<java.lang.String,java.lang.Object> httpHeaders, java.io.OutputStream entityStream) throws java.io.IOException,
WebApplicationException
{
JPEGTranscoder t = new JPEGTranscoder();
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(.8));
InputStream is = new ByteArrayInputStream(instance.getBytes());
TranscoderInput input = new TranscoderInput(is);
TranscoderOutput output = new TranscoderOutput(entityStream);
t.transcode(input, output);
httpHeaders.put("Content-Disposition", ""attachment;filename=" + instance.getFilename());
// and so on....
httpHeaders.put("whatever else", "some other value");
}
4) Follow the instructions appropriate for your version of Jersey to register your MessageBodyWriter as a Provider.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.