PDFbox с Restlet
У меня возникла проблема с обслуживанием PDF-файла из нашего Restlet
API.
Я использую базовый пример кода издокументации Apache PDFBox , он прекрасно работает вне контекста 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 в ресурсе, в конечном итоге я хочу вернуть OutputRepresentation
и сохранить PDDcoument
в поток.
Следующий код перестает работать на PDPage page = new PDPage();
, я не получаю никаких исключений, сервер Restlet
не возвращает никакого ответа. Текст "after instantiating new PDPage"
никогда не печатается.
EDIT: я упростил свой код, насколько это возможно, но у меня все еще есть проблема
Вот мой основной маршрутизатор:
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);
}
}
Вот моя паутина.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 и верну некоторые 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 "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 и сервлетами: PDFBox: не удается сохранить pdf во время работы на tomcat
Правка 4: вот решение https://stackoverflow.com/a/32706385/1039265
3 ответа:
Я попробовал ваш пример кода, и он сработал для меня.
Я только что настроил класс PDDocumentRepresentation, который обертывает PDDocument:
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); } }
Фактически вы никогда не возвращаете содержимое вашего созданного PDF-файла в ответ. Возвращаемое представление аннотированного метода соответствует содержимому ответа.
В вашем случае он должен соответствовать двоичному. Вы также можете использовать заголовок Content disposition для запуска диалогового окна загрузки в браузере.
Вы можете попытаться поместить это содержимое в массив байтов, а затем отправить его через Restlet с выделенным представлением (например, на основе OuputStream).
Надеюсь, это вам поможет. Тьерри
Проблема исходит из версии PDFBox. Если я использую версию
2.0.0-SNAPSHOT
(http://pdfbox.apache.org/2.0/getting-started.html ), я могу генерировать PDF через сервлет. Спасибо за вашу помощь.