Browser Invoice for Thymeleaf
HTML invoice report package rendered by the Report-Boot Thymeleaf provider. Browser-ready, watermarked, UUID-protected.
Package metadata
Template file
classpath:/reports/templates/invoice-thymeleaf.html
File-name pattern
invoice-${invoiceNumber}.html
Provider module
report-boot-thymeleaf
Template type
.html
What's inside the package
- InvoiceThymeleafReportDto.java
- InvoiceItemDto.java
- invoice-thymeleaf.html
Annotations used
Every annotation declared on the DTO, with a paste-ready example.
| Annotation | Description |
|---|---|
| @ReportTemplate | Template identity and HTML output. @ReportTemplate(code = "invoice-thymeleaf", templateFile = "classpath:/reports/templates/invoice-thymeleaf.html", output = ReportOutput.HTML) |
| @ReportEngineType | Selects the Thymeleaf renderer. @ReportEngineType(ReportEngine.THYMELEAF) |
| @ReportSecured | Watermark + 30 minute download expiry. @ReportSecured(watermark = true, expiryMinutes = 30) |
| @ReportAccess | Required role for generate / download. @ReportAccess(role = "ROLE_REPORT_ADMIN") |
| @ReportField | Exposes a value to the Thymeleaf context. @ReportField("customerName") |
| @ReportTable | Iterable source for the items <tr> loop. @ReportTable("items") |
Field contract
Template keys ↔ DTO fields. Use this when designing or editing the underlying template file.
| Template key | Source | Type | Required |
|---|---|---|---|
| invoiceNumber | @ReportField | String | Yes |
| customerName | @ReportField | String | Yes |
| invoiceDate | @ReportField | LocalDate | No |
| totalAmount | @ReportField | BigDecimal | No |
| items | @ReportTable | List<InvoiceItemDto> | No |
| items.itemName | row @ReportField | String | No |
| items.quantity | row @ReportField | Integer | No |
| items.unitPrice | row @ReportField | BigDecimal | No |
| items.total | row @ReportField | BigDecimal | No |
Ready-to-use DTO
@ReportTemplate(
code = "invoice-thymeleaf",
title = "Invoice (Thymeleaf HTML)",
templateFile = "classpath:/reports/templates/invoice-thymeleaf.html",
output = ReportOutput.HTML
)
@ReportEngineType(ReportEngine.THYMELEAF)
@ReportSecured(watermark = true, expiryMinutes = 30)
@ReportFileName("invoice-${invoiceNumber}.html")
@ReportAccess(role = "ROLE_REPORT_ADMIN")
@ReportTitle("Thymeleaf Invoice Report")
@ReportDescription("Demo invoice report rendered by the Report-Boot Thymeleaf provider.")
@ReportVersion("1.0.0")
@ReportCategory("Billing")
public class InvoiceThymeleafReportDto {
@ReportField("invoiceNumber") @ReportRequired
private String invoiceNumber;
@ReportField("customerName") @ReportRequired
private String customerName;
@ReportField("invoiceDate") @ReportDateFormat("yyyy-MM-dd")
private LocalDate invoiceDate;
@ReportField("totalAmount")
@ReportFormat(pattern = "#,##0.00") @ReportCurrency("USD") @ReportLocale("en_US")
private BigDecimal totalAmount;
@ReportTable("items")
private List<InvoiceItemDto> items;
}
public class InvoiceItemDto {
@ReportField("itemName") private String itemName;
@ReportField("quantity") private Integer quantity;
@ReportField("unitPrice") private BigDecimal unitPrice;
@ReportField("total") private BigDecimal total;
// getters / setters
}Controller example
Standard generate + download flow. Returns a JSON body with the report-order UUID and a download URL.
@RestController
@RequestMapping("/api/reports/thymeleaf/invoice")
public class ThymeleafInvoiceReportController {
private final ReportService reportService;
public ThymeleafInvoiceReportController(ReportService reportService) {
this.reportService = reportService;
}
@PostMapping
public ResponseEntity<Map<String, Object>> generate(@RequestBody InvoiceThymeleafReportDto dto) {
GeneratedReport report = reportService.generate(dto);
String url = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/api/reports/thymeleaf/invoice/")
.path(report.getReportOrderUuid().toString())
.path("/download")
.toUriString();
return ResponseEntity.status(HttpStatus.CREATED)
.body(Map.of(
"reportOrderUuid", report.getReportOrderUuid(),
"fileName", report.getFileName(),
"contentType", report.getContentType(),
"generatedAt", report.getGeneratedAt(),
"downloadUrl", url
));
}
@GetMapping("/{uuid}/download")
public ResponseEntity<byte[]> download(@PathVariable UUID uuid) {
GeneratedReport report = reportService.download(uuid);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + report.getFileName() + "\"")
.contentType(MediaType.parseMediaType(report.getContentType()))
.body(report.getContent());
}
}
// File extension for this provider: .htmlSample request
{
"invoiceNumber": "INV-1001",
"customerName": "ACME Corp",
"invoiceDate": "2026-05-31",
"totalAmount": 1200.50,
"items": [
{ "itemName": "Implementation package", "quantity": 1, "unitPrice": 950.00, "total": 950.00 },
{ "itemName": "Support hours", "quantity": 5, "unitPrice": 50.10, "total": 250.50 }
]
}Security notes
- Downloads are served by report-order UUID, never by file path.
- Expiry is enforced after 30 minutes (@ReportSecured).
- Access requires role
ROLE_REPORT_ADMIN(@ReportAccess). - Watermark metadata is applied at render time (@ReportSecured(watermark = true)).
AI installer prompt
Paste this prompt into Cursor, Copilot Chat or any IDE assistant. It will add dependencies, copy the DTO + template, register the controller and respect the security policy declared on the DTO. Each marketplace package ships its own curated prompt.
You are a Report-Boot assistant embedded in the developer's IDE.
Goal: integrate the "InvoiceThymeleafReportDto" template into the user's Spring Boot project.
Steps:
1. Confirm Java 17+ and Spring Boot 3.x are present.
2. Add Maven dependencies:
- com.reportboot:report-boot-spring-boot-starter:0.1.0-MVP
- com.reportboot:report-boot-thymeleaf:0.1.0-MVP
- the matching third-party engine dependency (the user is responsible for its license).
3. Copy invoice-thymeleaf.html into src/main/resources/reports/templates/.
4. Copy InvoiceThymeleafReportDto.java and InvoiceItemDto.java into the user's DTO package and adjust the package declaration.
5. Inject ReportService and call reportService.generate(dto) then expose a download endpoint by UUID.
6. Surface the secured download URL and respect the expiry / role declared by the @ReportSecured and @ReportAccess annotations.
7. Verify with a smoke test POST using the provided sample JSON.
Output a concise change-list and the exact files to create or modify. Do not invent annotations; only use the ones declared on the DTO.