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 == 0cb.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资源加载实现接口
@Componentpublic class AwsRepositoryService implements RepositoryService {private static final Logger log = LoggerFactory.getLogger(AwsRepositoryService.class);private static final String JASPER_SUFFIX = ".jasper";@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Overridepublic Resource getResource(String uri) {return null;}@Overridepublic void saveResource(String uri, Resource resource) {throw new UnsupportedOperationException();}@Overridepublic <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获取报表资源,再缓存至redisString 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
@Configurationpublic class PdfExporterConfig {@Beanpublic PdfExporter pdfExporter(AwsRepositoryService repositoryService) {return new PdfExporter(repositoryService);}}
