使用 Apache Wink 通过 Java REST 服务返回 excel 文档
Returning an excel document via a Java REST service with Apache Wink
我需要 return 来自 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.
这是我的 Java 资源 class 方法:
@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();
}
通过查看调试器,我确实知道路径和 excel 文件已正确找到,并且文件大小也已正确填充。
我很乐意提供更多需要的信息。感谢您的宝贵时间!
我认为问题出在 @Produces
注释上。默认情况下,JAX-RS 可能不知道如何处理 "application/vnd.ms-excel"
。您可以尝试使用
@Produces( MediaType.APPLICATION_OCTET_STREAM)
这里是示例代码,
创建 JEE 6 网络项目
创建了一个应用程序Class
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/services/*")
public class MyApplication extends Application {
}
创建了 REST 资源 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();
}
}
问题是 BaseResponseMessage 的存在。显然是因为我实际上是在 Response object instead of the actual InputStream 中返回 BaseResponseMessage JAX-RS 不知道如何处理它,因为(如错误状态)没有与该组合专门关联的 MessageBodyWriter 或 DataSourceProvider。有趣的是,如果我更仔细地阅读错误消息,它实际上揭示了实际问题! :p
当修改上面的代码以删除 BaseResponseMessage 并执行如下操作时:
responseBuilder = Response.ok(report);
那就可以正常工作了。
[顺便说一句,返回一个 InputStream is not really a good idea anyway; the code has since been modified to return a StreamingOutput 对象。]
我需要 return 来自 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.
这是我的 Java 资源 class 方法:
@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();
}
通过查看调试器,我确实知道路径和 excel 文件已正确找到,并且文件大小也已正确填充。
我很乐意提供更多需要的信息。感谢您的宝贵时间!
我认为问题出在 @Produces
注释上。默认情况下,JAX-RS 可能不知道如何处理 "application/vnd.ms-excel"
。您可以尝试使用
@Produces( MediaType.APPLICATION_OCTET_STREAM)
这里是示例代码,
创建 JEE 6 网络项目
创建了一个应用程序Class
import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("/services/*") public class MyApplication extends Application { }
创建了 REST 资源 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(); } }
问题是 BaseResponseMessage 的存在。显然是因为我实际上是在 Response object instead of the actual InputStream 中返回 BaseResponseMessage JAX-RS 不知道如何处理它,因为(如错误状态)没有与该组合专门关联的 MessageBodyWriter 或 DataSourceProvider。有趣的是,如果我更仔细地阅读错误消息,它实际上揭示了实际问题! :p
当修改上面的代码以删除 BaseResponseMessage 并执行如下操作时:
responseBuilder = Response.ok(report);
那就可以正常工作了。
[顺便说一句,返回一个 InputStream is not really a good idea anyway; the code has since been modified to return a StreamingOutput 对象。]