简体   繁体   English

Jersey REST服务将响应作为带有下载窗口的图像返回

[英]Jersey REST service to return response as an image with download window

I have a D3 graph generated on client side. 我在客户端生成了一个D3图。 I send the SVG data to Jersey REST service convert the SVG data to image ( OutputStream ) using Transcoding . 我将SVG数据发送到Jersey REST服务,使用TranscodingSVG数据转换为图像( OutputStream )。 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: 调用此服务后,我在服务器控制台上获得以下Exception

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. 不,我不这么认为......我认为根本问题是你不能直接操作响应OutputStream并从你的downloadSVG方法返回一个Response。

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 . 查看MessageBodyWriter It gives you access to the request OutputStream and allows you to manipulate the response headers. 它使您可以访问请求OutputStream,并允许您操作响应头。

Here's what I would do: 这就是我要做的事情:

1) Create a new class (MyPNG). 1)创建一个新类(MyPNG)。 Modify your REST method to return MyPNG rather than Response and mark it with a @Produces tag. 修改REST方法以返回MyPNG而不是Response,并使用@Produces标记对其进行标记。

@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 2)在REST方法中,读取InputStream并创建并返回MyPNG的新实例

3) Implement MessageBodyWriter and do something like this in the writeTo method: 3)实现MessageBodyWriter并在writeTo方法中执行类似的操作:

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. 4)按照适用于您的Jersey版本的说明将MessageBodyWriter注册为提供者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM