带有 Restlet 的 PDFbox
PDFbox with Restlet
我在从我们的 Restlet
API.
提供 PDF 文件时遇到问题
我正在使用 Apache PDFBox documentation 中的基本示例代码,它在 Restlet
上下文之外工作正常。
PDDocument document = new PDDocument();
System.err.println("before instantiating new PDPage");
// Create a new blank page and add it to the document
PDPage page = new PDPage(); // LINE FAILING IN RESTLET
System.err.println("after instantiating new PDPage");
document.addPage(page);
document.save("pdf.pdf");
document.close();
这是我在资源中使用 PDFBox 的尝试,最终我想 return 一个 OutputRepresentation
并将 PDDcoument
保存到流中。
以下代码在 PDPage page = new PDPage();
停止工作,我没有得到任何异常,Restlet
服务器没有 return 任何响应。永远不会打印文本 "after instantiating new PDPage"
。
编辑:我尽可能地简化了我的代码,但我仍然有问题
这是我的基本路由器:
public class ApiRestletApplication extends Application {
@Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/v1/myresource", MyResource.class);
return router;
}
}
这是我的资源
public class MyResource extends ServerResource {
protected static final Logger logger = LoggerFactory.getLogger(MyResource.class);
@Get
public Representation toPDF() {
PDDocument document = new PDDocument();
System.err.println("before instantiating new PDPage");
PDPage page = new PDPage();
System.err.println("after instantiating new PDPage"); //<= never printed
document.addPage(page);
return new PDFRepresentation(document);
}
}
这是我的web.xml
<!-- Restlet application -->
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>com.xxx.api.ApiRestletApplication</param-value>
</context-param>
<!-- Restlet adapter -->
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>
org.restlet.ext.servlet.ServerServlet
</servlet-class>
</servlet>
<!-- Catch all requests -->
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
如果我注释掉符合 PDPage 声明的行和 return 一些 StringRepresentation
,一切正常。我可以提供一些 Json、xml 和 excel。但是这个 PDF 快把我逼疯了。
这是我使用的版本:
[INFO] +- org.restlet.jee:org.restlet:jar:2.2.1:compile
[INFO] +- org.restlet.jee:org.restlet.ext.crypto:jar:2.2.1:compile
[INFO] +- org.restlet.jee:org.restlet.ext.servlet:jar:2.2.1:compile
[INFO] | +- org.apache.pdfbox:pdfbox:jar:1.8.10:compile
[INFO] | | +- org.apache.pdfbox:fontbox:jar:1.8.10:compile
[INFO] | | \- org.apache.pdfbox:jempbox:jar:1.8.10:compile
[INFO] | \- com.sun:tools:jar:jdk:system
这是 curl 请求:
curl "http://localhost:8889/v1/myresource" -H "Content-Type: application/pdf" -H "Accept: application/pdf"
这是 eclipse 中的日志:
2015-09-21 15:08:15.933:INFO::Started SelectChannelConnector@0.0.0.0:8889
2015-09-21 15:08:20.698:INFO:/:RestletServlet: [Restlet] Attaching application: com.xxx.api.ApiRestletApplication@2613622c to URI:
before instantiating new PDPage
//then nothing
感谢您的帮助。
编辑 2:以下代码有效,但我仍然不知道为什么我的代码无效:
public class RestletServerTest extends Application {
@Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/v1/myresource", MyResource.class);
return router;
}
public static void main(String[] args) throws Exception {
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
component.getDefaultHost().attach("", new RestletServerTest());
component.start();
}
}
编辑 3:问题似乎与 Restlet 无关,而与 PDFBox 和 servlet 相关:PDFBox: Unable to save pdf while running on tomcat
编辑 4:这是解决方案
事实上,您永远不会 return 在响应中包含您创建的 PDF 的内容。您的注释方法的 returned 表示对应于响应内容。
在你的情况下,它应该对应于二进制。您还可以利用内容配置 header 在浏览器中触发下载对话框。
您可以尝试将此内容放入一个字节数组中,然后使用专用表示(例如基于 OuputStream 的表示)通过 Restlet 发送它。
希望对您有所帮助。
蒂埃里
我试过你的示例代码,它对我有用。
我刚刚设置了一个 class 包装 PDDocument 的 PDDocumentRepresentation:
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.restlet.data.MediaType;
import org.restlet.representation.OutputRepresentation;
public class PDDocumentRepresentation extends OutputRepresentation {
private PDDocument document = new PDDocument();
public PDDocumentRepresentation(PDDocument document) {
super(MediaType.APPLICATION_PDF);
this.document = document;
}
@Override
public void write(OutputStream outputStream) throws IOException {
try {
document.save(outputStream);
document.close();
} catch (COSVisitorException e) {
throw new IOException(e);
}
}
}
资源代码如下:
public class MyResource extends ServerResource {
@Get
public Representation getPdf() {
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
return new PDDocumentRepresentation(document);
}
}
问题来自 PDFBox 版本。如果我使用 2.0.0-SNAPSHOT
(http://pdfbox.apache.org/2.0/getting-started.html) 版本,我可以通过 servlet 生成 PDF。感谢您的帮助。
我在从我们的 Restlet
API.
我正在使用 Apache PDFBox documentation 中的基本示例代码,它在 Restlet
上下文之外工作正常。
PDDocument document = new PDDocument();
System.err.println("before instantiating new PDPage");
// Create a new blank page and add it to the document
PDPage page = new PDPage(); // LINE FAILING IN RESTLET
System.err.println("after instantiating new PDPage");
document.addPage(page);
document.save("pdf.pdf");
document.close();
这是我在资源中使用 PDFBox 的尝试,最终我想 return 一个 OutputRepresentation
并将 PDDcoument
保存到流中。
以下代码在 PDPage page = new PDPage();
停止工作,我没有得到任何异常,Restlet
服务器没有 return 任何响应。永远不会打印文本 "after instantiating new PDPage"
。
编辑:我尽可能地简化了我的代码,但我仍然有问题
这是我的基本路由器:
public class ApiRestletApplication extends Application {
@Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/v1/myresource", MyResource.class);
return router;
}
}
这是我的资源
public class MyResource extends ServerResource {
protected static final Logger logger = LoggerFactory.getLogger(MyResource.class);
@Get
public Representation toPDF() {
PDDocument document = new PDDocument();
System.err.println("before instantiating new PDPage");
PDPage page = new PDPage();
System.err.println("after instantiating new PDPage"); //<= never printed
document.addPage(page);
return new PDFRepresentation(document);
}
}
这是我的web.xml
<!-- Restlet application -->
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>com.xxx.api.ApiRestletApplication</param-value>
</context-param>
<!-- Restlet adapter -->
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>
org.restlet.ext.servlet.ServerServlet
</servlet-class>
</servlet>
<!-- Catch all requests -->
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
如果我注释掉符合 PDPage 声明的行和 return 一些 StringRepresentation
,一切正常。我可以提供一些 Json、xml 和 excel。但是这个 PDF 快把我逼疯了。
这是我使用的版本:
[INFO] +- org.restlet.jee:org.restlet:jar:2.2.1:compile
[INFO] +- org.restlet.jee:org.restlet.ext.crypto:jar:2.2.1:compile
[INFO] +- org.restlet.jee:org.restlet.ext.servlet:jar:2.2.1:compile
[INFO] | +- org.apache.pdfbox:pdfbox:jar:1.8.10:compile
[INFO] | | +- org.apache.pdfbox:fontbox:jar:1.8.10:compile
[INFO] | | \- org.apache.pdfbox:jempbox:jar:1.8.10:compile
[INFO] | \- com.sun:tools:jar:jdk:system
这是 curl 请求:
curl "http://localhost:8889/v1/myresource" -H "Content-Type: application/pdf" -H "Accept: application/pdf"
这是 eclipse 中的日志:
2015-09-21 15:08:15.933:INFO::Started SelectChannelConnector@0.0.0.0:8889
2015-09-21 15:08:20.698:INFO:/:RestletServlet: [Restlet] Attaching application: com.xxx.api.ApiRestletApplication@2613622c to URI:
before instantiating new PDPage
//then nothing
感谢您的帮助。
编辑 2:以下代码有效,但我仍然不知道为什么我的代码无效:
public class RestletServerTest extends Application {
@Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/v1/myresource", MyResource.class);
return router;
}
public static void main(String[] args) throws Exception {
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
component.getDefaultHost().attach("", new RestletServerTest());
component.start();
}
}
编辑 3:问题似乎与 Restlet 无关,而与 PDFBox 和 servlet 相关:PDFBox: Unable to save pdf while running on tomcat
编辑 4:这是解决方案
事实上,您永远不会 return 在响应中包含您创建的 PDF 的内容。您的注释方法的 returned 表示对应于响应内容。
在你的情况下,它应该对应于二进制。您还可以利用内容配置 header 在浏览器中触发下载对话框。
您可以尝试将此内容放入一个字节数组中,然后使用专用表示(例如基于 OuputStream 的表示)通过 Restlet 发送它。
希望对您有所帮助。 蒂埃里
我试过你的示例代码,它对我有用。
我刚刚设置了一个 class 包装 PDDocument 的 PDDocumentRepresentation:
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.restlet.data.MediaType;
import org.restlet.representation.OutputRepresentation;
public class PDDocumentRepresentation extends OutputRepresentation {
private PDDocument document = new PDDocument();
public PDDocumentRepresentation(PDDocument document) {
super(MediaType.APPLICATION_PDF);
this.document = document;
}
@Override
public void write(OutputStream outputStream) throws IOException {
try {
document.save(outputStream);
document.close();
} catch (COSVisitorException e) {
throw new IOException(e);
}
}
}
资源代码如下:
public class MyResource extends ServerResource {
@Get
public Representation getPdf() {
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
return new PDDocumentRepresentation(document);
}
}
问题来自 PDFBox 版本。如果我使用 2.0.0-SNAPSHOT
(http://pdfbox.apache.org/2.0/getting-started.html) 版本,我可以通过 servlet 生成 PDF。感谢您的帮助。