使用 Apache Wink 通过 Java REST 服务返回 Excel 文档

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39091126/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 04:05:31  来源:igfitidea点击:

Returning an excel document via a Java REST service with Apache Wink

javaexcelrestwebsphere-8apache-wink

提问by risingTide

I need to return a Microsoft Excel file from a Java REST service. I'm using WebSphere 8.5 which inherently uses Apache Wink as it's JAX-RS implementation; that's a requirement which I can not change. I am also using Java 7 JDK. Here is the error I'm receiving:

我需要从 Java REST 服务返回 Microsoft Excel 文件。我正在使用 WebSphere 8.5,它本质上使用 Apache Wink,因为它是 JAX-RS 实现;这是我无法改变的要求。我也在使用 Java 7 JDK。这是我收到的错误:

org.apache.wink.server.internal.handlers.FlushResultHandler handleResponse The system could not find a javax.ws.rs.ext.MessageBodyWriter or a DataSourceProvider class for the com.somewhere.else.message.core.BaseResponseMessage type and application/vnd.ms-excel mediaType. Ensure that a javax.ws.rs.ext.MessageBodyWriter exists in the JAX-RS application for the type and media type specified.

org.apache.wink.server.internal.handlers.FlushResultHandler handleResponse 系统找不到 com.somewhere.else.message.core.BaseResponseMessage 类型和应用程序的 javax.ws.rs.ext.MessageBodyWriter 或 DataSourceProvider 类/ vnd.ms-excel 媒体类型。确保在 JAX-RS 应用程序中存在指定类型和媒体类型的 javax.ws.rs.ext.MessageBodyWriter。

Here is my Java Resource class method:

这是我的 Java Resource 类方法:

@GET
@Path("/report")
@Produces("application/vnd.ms-excel")
public Response getReport() { 

    int fileSize = 0;

    byte[] reportByteArray = null;

    ResponseBuilder responseBuilder = null;
    InputStream report = null;

    BaseResponseMessage<InputStream> baseResponseMessage = new  
    BaseResponseMessage<InputStream>();

    Path reportPath = null;

    String localPath = "C:/Users/me/Report.xls";

    responseBuilder = Response.ok(baseResponseMessage); 

    responseBuilder.header("Content-Description", "File Transfer");
    responseBuilder.header("Content-Disposition", "attachment; 
         filename=Report.xls");
    responseBuilder.header("Content-Transfer-Encoding", "binary");
    responseBuilder.header("Connection", "Keep-Alive");

    reportPath = Paths.get(localPath);

    if (Files.exists(reportPath)) {

        if (Files.isReadable(reportPath)) {

            reportByteArray = Files.readAllBytes(reportPath);

            report = new ByteArrayInputStream(reportByteArray);
        }
    }

    fileSize = report.available();

    responseBuilder.header("Content-Length", fileSize);

    baseResponseMessage.setPayload(report);

    return responseBuilder.build();
}

I do know from looking at the debugger that the path and the excel file are found correctly, and the fileSize is populated correctly as well.

我确实通过查看调试器知道正确找到了路径和 excel 文件,并且 fileSize 也正确填充。

I will gladly provide any more information that is needed. Thank you for your time!

我很乐意提供更多需要的信息。感谢您的时间!

采纳答案by risingTide

The problem was the existence of the BaseResponseMessage. Apparently because I was actually returning the BaseResponseMessage in the Responseobject instead of the actual InputStreamJAX-RS didn't know how to process it since (as the error states) there isn't a MessageBodyWriter or DataSourceProvider specifically associated with that combination. Funny how the error message actually revealed the actual problem had I read it more closely! :p

问题在于 BaseResponseMessage 的存在。显然,因为我实际上是在Response对象中返回 BaseResponseMessage而不是实际的InputStreamJAX-RS 不知道如何处理它,因为(作为错误状态)没有专门与该组合关联的 MessageBodyWriter 或 DataSourceProvider。有趣的是,如果我更仔细地阅读错误消息,它实际上揭示了实际问题!:p

When the code above is modified to remove the BaseResponseMessage and do something like this:

当修改上面的代码以删除 BaseResponseMessage 并执行以下操作时:

responseBuilder = Response.ok(report);

responseBuilder = Response.ok(report);

then it will work just fine.

那么它会工作得很好。

[As an aside, returning an InputStreamis not really a good idea anyway; the code has since been modified to return a StreamingOutputobject.]

[顺便说一句,无论如何,返回InputStream并不是一个好主意;此代码已被修改为返回StreamingOutput对象。]

回答by Arun B Chandrasekaran

I think the problem is on the @Produces annotation. JAX-RS may not know how to handle "application/vnd.ms-excel" by default. You can try using

我认为问题出在@Produces 注释上。默认情况下,JAX-RS 可能不知道如何处理“application/vnd.ms-excel”。您可以尝试使用

@Produces( MediaType.APPLICATION_OCTET_STREAM)

Here is the sample code,

这是示例代码,

  1. Create a JEE 6 web project
  2. Created an Application Class

    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;

    @ApplicationPath("/services/*")
    public class MyApplication extends Application {

    }

  3. Created a REST Resource class,

    import java.io.File;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.core.Response.ResponseBuilder;

    @Path("/hello")
    public class HelloResource {

    @GET  
    @Path("excel")  
    @Produces(MediaType.APPLICATION_OCTET_STREAM)  
    public Response test2() {  
        File file = new File("C:/users/arun/rest-test.xlsx");  
        ResponseBuilder rb = Response.ok(file);  
        rb.header("content-disposition", "attachment; filename=rest-test.xlsx");  
        return rb.build();  
    }  
    

    }

  1. 创建 JEE 6 Web 项目
  2. 创建了一个应用程序类

    导入 javax.ws.rs.ApplicationPath;
    导入 javax.ws.rs.core.Application;

    @ApplicationPath("/services/*")
    public class MyApplication extends Application {

    }

  3. 创建了一个 REST 资源类,

    导入 java.io.File;
    导入 javax.ws.rs.GET;
    导入 javax.ws.rs.Path;
    导入 javax.ws.rs.Produces;
    导入 javax.ws.rs.core.MediaType;
    导入 javax.ws.rs.core.Response;
    导入 javax.ws.rs.core.Response.ResponseBuilder;

    @Path("/hello")
    公共类 HelloResource {

    @GET  
    @Path("excel")  
    @Produces(MediaType.APPLICATION_OCTET_STREAM)  
    public Response test2() {  
        File file = new File("C:/users/arun/rest-test.xlsx");  
        ResponseBuilder rb = Response.ok(file);  
        rb.header("content-disposition", "attachment; filename=rest-test.xlsx");  
        return rb.build();  
    }  
    

    }