visit
curl http://[email protected]/docs \
--fail --silent --show-error \
--header "Content-Type:application/json" \
--data '{"test": true,
"document_url": "//www.docraptor.com/examples/invoice.html",
"type": "pdf" }' > docraptor.pdf
Page #1
The first page will contain the following elements:Page #2
In order to demonstrate the power and flexibility with DocRaptor, the second page will contain::<!DOCTYPE html>
<html>
<head>
<title>Your New Project for Our Best Client</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style type="text/css">
/*resets from YUI*/
table {border-collapse:collapse; border-spacing:0;}
/* setup the page */
@page { margin: 30px; background: #ffffff; }
/* setup the footer */
@page { @bottom { content: flow(foot); } }
#footer { flow: static(foot); }
/* useful utility */
.clear { clear:both; }
/* layout */
#container { font-family: Omnes Light, Trebuchet MS, Calibri, Futura, Geneva, Tahoma; font-size: 14pt; color: #a7a7a7; position: relative; }
/* footer shenanigans! */
#footer { text-align: center; display: block; }
/* colors */
.black { color: black }
/* stylin */
#quote_name { margin-top: 3.5em; text-align: right; font-weight: bold; font-size: 1.5em }
#client { font-size: 0.75em; margin-top: 3em; margin-left: 0.5em;}
#client_header { font-size: 0.5em; }
#phase_details {
margin-top: 2em;
font-size: 0.6em;
border-width: 1px;
border-spacing: 0px;
border-style: solid;
border-color: gray;
width: 100%;
}
#phase_details th { font-size: 0.8em; padding: 10px !important; border-style: solid !important; }
#phase_details th, td {
border-width: 1px;
padding: 3px 5px;
border-top-style: none;
border-bottom-style: none;
border-left-style: solid;
border-right-style: solid;
border-color: gray;
background-color: white;
}
#phase_details tr.first td { padding-top: 10px; padding-bottom: 10px; }
#phase_details td.price { text-align: left; }
#phase_details .price_container { float: left; min-width: 30%; }
#phase_details thead .title { width: 20%; }
#phase_details thead .description { width: 60%; }
#phase_details thead .price { width: 20%; }
#phase_details tr.last { border-bottom: 1px solid gray; }
#footer #contain { text-align: right; font-size: 0.8em; }
#total_price { text-align: right; margin-right: 6.75em; margin-top: 0.5em; }
#total_price h2 { color: black; font-size: 0.6em; font-weight: bold; }
#total_price .price { margin-left: 0.75em; }
</style>
</head>
<body>
<div id="container">
<div id="logo">Your Logo</div>
<div id="main">
<div id="header">
<div id="header_info black">1234 Made Up LN <span class="black">|</span> (555)-555-5555 <span class="black">|</span> example.com</div>
</div>
<h1 class="black" id="quote_name">Your New Project</h1>
<div id="client">
<div id="client_header">client:</div>
<p class="address black">
Our Best Cient
</p>
</div>
<table id="phase_details">
<thead>
<tr>
<th class="title">phase title</th>
<th class="description">phase description & features</th>
<th class="price">price</th>
</tr>
</thead>
<tr class="first black">
<td>When We Do Stuff</td>
<td>From 10/10/2010 to 11/11/2011</td>
<td class="price"><div class="price_container">$300</div></td>
</tr>
<tr>
<td></td>
<td>Doing Stuff</td>
<td class="price"><div class="price_container">$200</div></td>
</tr>
...
</table>
</div>
<div id="total_price">
<h2>TOTAL: <span class="price black">$1100</span></h2>
</div>
</div>
</body>
</html>
<dependency>
<groupId>com.docraptor</groupId>
<artifactId>docraptor</artifactId>
<version>2.0.0</version>
</dependency>
@Data
@Entity
@Table(name = "artists")
public class Artist {
@Id
private String name;
private String yearFormed;
private boolean active;
private String imageUrl;
}
[
...
{
"name": "Yes",
"yearFormed": "1968",
"active": true,
"imageUrl": "//somehost/Yes_concert.jpg"
}
]
Configuring DocRaptor Inside Spring Boot
The following attributes are required to interact with the DocRaptor service:About doc-raptor.test-mode
By enabling test mode via the ${DOCRAPTOR_TEST_MODE_ENABLED} variable, which maps to [doc-raptor.test-mode], no charges will be incurred against the DocRaptor account. However, enabling test mode replaces any custom watermarks with a generic DocRaptor watermark.Keep in mind, it is possible to use a [doc-raptor.api-key] equal to YOUR_API_KEY_HERE. However, in doing so [doc-raptor.test-mode] will always be set to true within the DocRaptor service.Starting Spring Boot With DocRaptor
With the DocRaptor configuration in place, starting the Spring Boot server with the sample project should yield a start-up screen similar to below:2020-10-30 10:42:05.100 INFO 95816 --- [ main] DeferredRepositoryInitializationListener : Spring Data repositories initialized!
2020-10-30 10:42:05.108 INFO 95816 --- [ main] c.g.j.d.DocraptorServiceApplication : Started DocraptorServiceApplication in 2.615 seconds (JVM running for 3.042)
2020-10-30 10:42:15.634 INFO 95816 --- [nio-8017-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-10-30 10:42:15.634 INFO 95816 --- [nio-8017-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-10-30 10:42:15.639 INFO 95816 --- [nio-8017-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
<dependency>
<groupId>com.j2html</groupId>
<artifactId>j2html</artifactId>
<version>1.4.0</version>
</dependency>
public final class HtmlBuilder {
private HtmlBuilder() { }
public static String createHtml(List<Artist> artists, String title) {
ContainerTag containerTag = html(
head(
title(title),
style(createStyleObjects()).attr("type", "text/css")
),
body(
div(
div("DRAFT").attr("id", "watermark"),
h1(title),
createBasicTable(artists.stream())
).withClass("named_page_one"),
div(
h1(title),
createBasicTable(artists.stream())
).withClass("named_page_two page_break")
)
);
return containerTag.render();
}
private static ContainerTag createBasicTable(Stream<Artist> artists) {
return table(
thead(
tr(
th(text("Photo")),
th(text("Name")),
th(text("Founded")),
th(text("Active"))
)
),
tbody(
artists.map(artist ->
tr(
td("").attr("width", "5%").attr("background", artist.getImageUrl()).withStyle("background-size: contain; background-repeat: no-repeat;"),
td(text(artist.getName())),
td(text(artist.getYearFormed())),
td(text(artist.isActive() ? "Yes" : "No"))
)).toArray(ContainerTag[]::new)
)
);
}
private static String createStyleObjects() {
return "table, th, td {" +
"border: 1px solid black; " +
"padding: 7px; " +
"} " +
"table {" +
" border-collapse: collapse;" +
" width: 100%;" +
"} " +
"#watermark {" +
"flow: static(watermarkflow);" +
"font-size: 120px;" +
"opacity: 0.5;" +
"transform: rotate(-30deg);" +
"text-align: center;" +
"} " +
"@page namedPage1 {" +
"size: letter portrait;" +
"@bottom {" +
"content: counter(page, lower-roman);" +
"} " +
"@prince-overlay {" +
"content: flow(watermarkflow)" +
"} " +
"} " +
"@page namedPage2 {" +
"size: letter landscape;" +
"margin-top: 70px; " +
"@top {" +
"content: counter(page, decimal-leading-zero);" +
"} " +
"} " +
".named_page_one {" +
"page: namedPage1;" +
"} " +
".named_page_two {" +
"page: namedPage2;" +
"} " +
".page_break {" +
"page-break-before: always;" +
"} ";
}
}
public byte[] process(DocRaptorRequest docRaptorRequest) throws Exception {
log.info("process(docRaptorRequest={}, testMode={})", docRaptorRequest, docRaptorProperties.isTestMode());
DocApi docApi = new DocApi();
ApiClient apiClient = docApi.getApiClient();
apiClient.setUsername(docRaptorProperties.getApiKey());
validateRequest(docRaptorRequest);
return docApi.createDoc(buildDocFromRequest(docRaptorRequest));
}
private Doc buildDocFromRequest(DocRaptorRequest docRaptorRequest) {
Doc doc = new Doc();
doc.setTest(docRaptorProperties.isTestMode());
doc.setJavascript(docRaptorProperties.isUseJavascript());
if (docRaptorRequest.getContentType().equals(DocRaptorContentType.STRING)) {
doc.setDocumentContent(docRaptorRequest.getDocumentContent());
} else {
doc.setDocumentUrl(docRaptorRequest.getDocumentUrl());
}
doc.setDocumentType(docRaptorRequest.getDocumentType());
doc.setName(docRaptorRequest.getName());
if (docRaptorRequest.usePrinceXml()) {
PrinceOptions princeOptions = new PrinceOptions();
princeOptions.setBaseurl(docRaptorRequest.getBaseUrl());
doc.setPrinceOptions(princeOptions);
}
log.debug("doc={}", doc.toString());
return doc;
}
public byte[] createPdf(String name) throws Exception {
DocRaptorRequest docRaptorRequest = new DocRaptorRequest();
docRaptorRequest.setDocumentType(Doc.DocumentTypeEnum.PDF);
docRaptorRequest.setContentType(DocRaptorContentType.STRING);
docRaptorRequest.setDocumentContent(HtmlBuilder.createHtml(getArtists(), "Classic Rock Artists"));
docRaptorRequest.setName(name);
return docRaptorService.process(docRaptorRequest);
}
@GetMapping(value = "/artists/pdf", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<byte[]> getArtistsPdf(@RequestParam(required = false) String filename) {
try {
if (StringUtils.isEmpty(filename)) {
filename = "Artists.pdf";
}
HttpHeaders headers = new HttpHeaders();
headers.setCacheControl(CacheControl.noCache().getHeaderValue());
headers.add("content-disposition", "inline;filename=" + filename);
return new ResponseEntity<>(artistService.createPdf(filename), headers, HttpStatus.OK);
} catch (Exception e) {
log.error(e.getMessage(), e);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
@GetMapping(value = "/artists/pdf", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<byte[]> getArtistsPdf(@RequestParam(required = false) String filename) {
try {
if (StringUtils.isEmpty(filename)) {
filename = "Artists.pdf";
}
HttpHeaders headers = new HttpHeaders();
headers.setCacheControl(CacheControl.noCache().getHeaderValue());
headers.add("content-disposition", "inline;filename=" + filename);
return new ResponseEntity<>(artistService.createPdf(filename), headers, HttpStatus.OK);
} catch (Exception e) {
log.error(e.getMessage(), e);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
curl --location --request GET '//localhost:8080/artists/pdf'
This view is a simple list of data from the in-memory H2 database of the Spring Boot service. The Create PDF located in the top right-hand corner of the application calls DocRaptor and the artists/pdf URI.
In order for DocRaptor to make the PDF file, the Create PDF button is wired to the following method:
createPdf() {
this.artistsService.createPdf().subscribe((response)=> {
let file = new Blob([response], {type: 'application/pdf'});
let fileURL = URL.createObjectURL(file);
window.open(fileURL);
});
}
createPdf() {
const httpOptions = {
'responseType' : 'arraybuffer' as 'json'
};
return this.http.get<any>(this.baseUrl + '/pdf', httpOptions);
}
Also published at