jasper version:6.0.0
父pom
<properties>
<awssdk.version>2.17.64</awssdk.version>
<jasperreports.version>6.0.0</jasperreports.version>
<barbecue.version>1.5-beta1</barbecue.version>
<barcode4j.version>2.1</barcode4j.version>
<pdfbox.version>2.0.24</pdfbox.version>
<itext.version>2.1.7</itext.version>
<xmlapis.version>1.3.04</xmlapis.version>
<zxing.version>3.4.1</zxing.version>
</properties>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>${awssdk.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>${jasperreports.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.olap4j</groupId>
<artifactId>olap4j</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>${xmlapis.version}</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis-ext</artifactId>
<version>${xmlapis.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.barbecue</groupId>
<artifactId>barbecue</artifactId>
<version>${barbecue.version}</version>
</dependency>
<dependency>
<groupId>net.sf.barcode4j</groupId>
<artifactId>barcode4j</artifactId>
<version>${barcode4j.version}</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>${zxing.version}</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version>
</dependency>
子pom
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis-ext</artifactId>
</dependency>
<dependency>
<groupId>net.sf.barcode4j</groupId>
<artifactId>barcode4j</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.barbecue</groupId>
<artifactId>barbecue</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
</dependency>
报表导出
public class PdfExporter {
private static final Logger log = LoggerFactory.getLogger(PdfExporter.class);
private final AwsRepositoryService awsRepositoryService;
public PdfExporter(AwsRepositoryService awsRepositoryService) {
this.awsRepositoryService = awsRepositoryService;
}
public byte[] merge(Rectangle rectangle, List<byte[]> bytes) {
return export(rectangle, bytes);
}
public byte[] export(Rectangle rectangle, byte[] bytes) {
return export(rectangle, Collections.singletonList(bytes));
}
/**
* 单个或合并导出
*
* @param bytes
* @param rectangle
* @return
*/
public byte[] export(Rectangle rectangle, List<byte[]> bytes) {
Document document = new Document();
document.setPageSize(rectangle);
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
PdfWriter writer = PdfWriter.getInstance(document, out);
List<PdfReader> readers = new ArrayList<>(bytes.size());
for (byte[] item : bytes) {
PdfReader reader = new PdfReader(item);
readers.add(reader);
}
document.open();
PdfContentByte content = writer.getDirectContent();
for (PdfReader reader : readers) {
int currentPageNum = 1;
int totalPages = reader.getNumberOfPages();
while (currentPageNum <= totalPages) {
document.newPage();
PdfImportedPage page = writer.getImportedPage(reader, currentPageNum);
content.addTemplate(page, 0,
rectangle.getHeight() - reader.getPageSize(currentPageNum).getHeight());
currentPageNum++;
}
}
document.close();
return out.toByteArray();
} catch (Exception e) {
log.error("Generate pdf exception. message : {}", e.getMessage());
throw new RuntimeException("Exception when printing label", e);
} finally {
if (document.isOpen()) {
document.close();
}
}
}
public void merge(List<InputStream> ins, OutputStream out, Rectangle pageSize, int row, int col) {
if (CollectionUtils.isEmpty(ins)) {
return;
}
Document document = new Document();
document.setPageSize(pageSize);
int count = row * col;
try {
List<PdfReader> readers = new ArrayList<>(ins.size());
for (InputStream in : ins) {
PdfReader pdfReader = new PdfReader(in);
readers.add(pdfReader);
}
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
PdfContentByte cb = writer.getDirectContent();
int x = 0;
int y = 0;
int i = 0;
while (i < readers.size()) {
if (i % count == 0) {
document.newPage();
x = 0;
y = 0;
}
while (x < row && i < readers.size()) {
y = 0;
while (y < col && i < readers.size()) {
int pageNum = 1;
PdfReader reader = readers.get(i);
while (pageNum <= reader.getNumberOfPages()) {
PdfImportedPage page = writer.getImportedPage(reader, pageNum);
int rotation = reader.getPageRotation(pageNum);
if ((rotation == 90 || rotation == 270) && (row > 1 || col > 1)) {
cb.addTemplate(page, 0, -1, 1, 0, y * reader.getPageSizeWithRotation(pageNum).getWidth(),
(x + 1) * reader.getPageSizeWithRotation(pageNum).getHeight());
} else {
// (row==1 && col==1) ||rotation == 0
cb.addTemplate(page, y * reader.getPageSize(pageNum).getWidth(), x * reader.getPageSize(pageNum).getHeight());
}
pageNum++;
}
i++;
y++;
}
x++;
}
}
out.flush();
document.close();
} catch (Exception e) {
log.error("Generate pdf exception. message : {}", e.getMessage());
throw new RuntimeException("Exception when printing label", e);
} finally {
if (document.isOpen()) {
document.close();
}
}
}
public byte[] autoMerge(Rectangle pageSize, List<byte[]> bytes) {
Document document = new Document();
document.setPageSize(pageSize);
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
List<PdfReader> readers = new ArrayList<>(bytes.size());
for (byte[] item : bytes) {
PdfReader pdfReader = new PdfReader(item);
readers.add(pdfReader);
}
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
PdfContentByte cb = writer.getDirectContent();
float pageHeight = pageSize.getHeight();
float pageWidth = pageSize.getWidth();
int i = 0;
while (i < readers.size()) {
float h = 0;
float w = 0;
float x = 0;
float y = pageHeight;
while (i < readers.size() && x < pageWidth) {
int pageNum = 1;
if (x >= pageWidth && y <= 0) {
document.newPage();
x = 0;
y = pageHeight;
}
PdfReader reader = readers.get(i);
float previousH = 0;
while (i < readers.size() && pageNum <= reader.getNumberOfPages()) {
PdfImportedPage page = writer.getImportedPage(reader, pageNum);
previousH = h;
h = reader.getPageSize(pageNum).getHeight();
w = reader.getPageSize(pageNum).getWidth();
if (x + w >= pageWidth && y <= 0) {
document.newPage();
x = 0;
y = pageHeight;
}
if (x + w >= pageWidth) {
x = 0;
}
if (x == 0) {
y = y - h;
} else {
if (h > previousH) {
y = y - (h - previousH);
}
}
if (y < 0) {
document.newPage();
x = 0;
y = pageHeight - h;
if (y < 0) {
y = 0;
}
}
cb.addTemplate(page, x, y);
x = x + w;
pageNum++;
}
i++;
}
}
document.close();
return out.toByteArray();
} catch (Exception e) {
log.error("Generate pdf exception. message : {}", e.getMessage());
throw new RuntimeException("Exception when printing label", e);
} finally {
if (document.isOpen()) {
document.close();
}
}
}
public byte[] export(final String template, final Object[] objects) throws Exception {
final Map<String, Object> params = new HashMap<>();
JasperReport jasperReport = awsRepositoryService.loadReport(template);
if (Objects.isNull(jasperReport)) {
log.error("jasper template {} not found.", template);
throw new RuntimeException("Exception when printing label");
}
JRDataSource dataSource = new JRBeanArrayDataSource(objects);
SimpleJasperReportsContext jasperReportsContext = new SimpleJasperReportsContext();
jasperReportsContext.setExtensions(RepositoryService.class,
Collections.singletonList(awsRepositoryService));
JasperPrint print = JasperFillManager.getInstance(jasperReportsContext)
.fill(jasperReport, params, dataSource);
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(SimpleExporterInput.getInstance(Collections.singletonList(print)));
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
exporter.exportReport();
return out.toByteArray();
} catch (Exception e) {
log.error("Generate pdf exception. message : {}", e.getMessage());
throw new RuntimeException("Exception when printing label", e);
}
}
}
自定义AWS资源加载实现接口
@Component
public class AwsRepositoryService implements RepositoryService {
private static final Logger log = LoggerFactory.getLogger(AwsRepositoryService.class);
private static final String JASPER_SUFFIX = ".jasper";
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Resource getResource(String uri) {
return null;
}
@Override
public void saveResource(String uri, Resource resource) {
throw new UnsupportedOperationException();
}
@Override
public <K extends Resource> K getResource(String uri, Class<K> resourceType) {
// aws文件资源
if (InputStreamResource.class.equals(resourceType)) {
InputStream inputStream = AmazonS3Util.getObjectAsInputStream(uri);
if (Objects.isNull(inputStream)) {
return null;
}
InputStreamResource resource = new InputStreamResource();
resource.setInputStream(inputStream);
return resourceType.cast(resource);
}
// aws报表资源
if (ReportResource.class.equals(resourceType)) {
final ReportResource reportResource = new ReportResource();
JasperReport report;
try {
report = loadReport(uri);
} catch (Exception e) {
throw new RuntimeException(String.format("load report '%s' error", uri), e);
}
if (Objects.isNull(report)) {
return null;
}
reportResource.setReport(report);
return resourceType.cast(reportResource);
}
return null;
}
public JasperReport loadReport(String uri) {
if(uri.endsWith(JASPER_SUFFIX)){
uri = uri.substring(0,uri.length() - 7);
}
// 一级缓存,从redis加载报表资源
JasperReport report = getCacheJasperReport(uri);
if (Objects.isNull(report)) {
// 刷新缓存后再次获取
report = refreshCacheJasperReport(uri);
}
return report;
}
private JasperReport getCacheJasperReport(final String template) {
return (JasperReport) redisTemplate.opsForHash().get(CacheKey.ALL_LABEL_TEMPLATE, template);
}
private void putJasperReportCache(final String template, JasperReport jasperReport) {
redisTemplate.opsForHash().putIfAbsent(CacheKey.ALL_LABEL_TEMPLATE, template, jasperReport);
}
/**
* 刷新对应模板的缓存
*
* @param template 模板名称,
*/
private JasperReport refreshCacheJasperReport(final String template) {
// 先从aws获取报表资源,再缓存至redis
String key = template + JASPER_SUFFIX;
byte[] bytes = AmazonS3Util.getObjectAsBytes(key);
if (Objects.isNull(bytes)) {
return null;
}
JasperReport report = null;
try {
report = (JasperReport) JRLoader.loadObject(new ByteArrayInputStream(bytes));
} catch (JRException e) {
log.error("'{}' load error. message : {}", key, e.getMessage());
}
if (Objects.isNull(report)) {
return null;
}
putJasperReportCache(template, report);
return report;
}
}
config
@Configuration
public class PdfExporterConfig {
@Bean
public PdfExporter pdfExporter(AwsRepositoryService repositoryService) {
return new PdfExporter(repositoryService);
}
}