jasper version:6.0.0

    父pom

    1. <properties>
    2. <awssdk.version>2.17.64</awssdk.version>
    3. <jasperreports.version>6.0.0</jasperreports.version>
    4. <barbecue.version>1.5-beta1</barbecue.version>
    5. <barcode4j.version>2.1</barcode4j.version>
    6. <pdfbox.version>2.0.24</pdfbox.version>
    7. <itext.version>2.1.7</itext.version>
    8. <xmlapis.version>1.3.04</xmlapis.version>
    9. <zxing.version>3.4.1</zxing.version>
    10. </properties>
    11. <dependency>
    12. <groupId>software.amazon.awssdk</groupId>
    13. <artifactId>bom</artifactId>
    14. <version>${awssdk.version}</version>
    15. <type>pom</type>
    16. <scope>import</scope>
    17. </dependency>
    18. <dependency>
    19. <groupId>net.sf.jasperreports</groupId>
    20. <artifactId>jasperreports</artifactId>
    21. <version>${jasperreports.version}</version>
    22. <exclusions>
    23. <exclusion>
    24. <groupId>commons-logging</groupId>
    25. <artifactId>commons-logging</artifactId>
    26. </exclusion>
    27. <exclusion>
    28. <groupId>org.olap4j</groupId>
    29. <artifactId>olap4j</artifactId>
    30. </exclusion>
    31. <exclusion>
    32. <groupId>com.fasterxml.jackson.core</groupId>
    33. <artifactId>jackson-core</artifactId>
    34. </exclusion>
    35. <exclusion>
    36. <groupId>com.fasterxml.jackson.core</groupId>
    37. <artifactId>jackson-databind</artifactId>
    38. </exclusion>
    39. <exclusion>
    40. <groupId>com.fasterxml.jackson.core</groupId>
    41. <artifactId>jackson-annotations</artifactId>
    42. </exclusion>
    43. <exclusion>
    44. <groupId>org.eclipse.jdt.core.compiler</groupId>
    45. <artifactId>ecj</artifactId>
    46. </exclusion>
    47. <exclusion>
    48. <groupId>org.apache.lucene</groupId>
    49. <artifactId>lucene-core</artifactId>
    50. </exclusion>
    51. <exclusion>
    52. <groupId>org.apache.lucene</groupId>
    53. <artifactId>lucene-analyzers-common</artifactId>
    54. </exclusion>
    55. <exclusion>
    56. <groupId>org.apache.lucene</groupId>
    57. <artifactId>lucene-queryparser</artifactId>
    58. </exclusion>
    59. </exclusions>
    60. </dependency>
    61. <dependency>
    62. <groupId>com.lowagie</groupId>
    63. <artifactId>itext</artifactId>
    64. <version>${itext.version}</version>
    65. </dependency>
    66. <dependency>
    67. <groupId>xml-apis</groupId>
    68. <artifactId>xml-apis</artifactId>
    69. <version>${xmlapis.version}</version>
    70. </dependency>
    71. <dependency>
    72. <groupId>xml-apis</groupId>
    73. <artifactId>xml-apis-ext</artifactId>
    74. <version>${xmlapis.version}</version>
    75. </dependency>
    76. <dependency>
    77. <groupId>net.sourceforge.barbecue</groupId>
    78. <artifactId>barbecue</artifactId>
    79. <version>${barbecue.version}</version>
    80. </dependency>
    81. <dependency>
    82. <groupId>net.sf.barcode4j</groupId>
    83. <artifactId>barcode4j</artifactId>
    84. <version>${barcode4j.version}</version>
    85. </dependency>
    86. <dependency>
    87. <groupId>com.google.zxing</groupId>
    88. <artifactId>core</artifactId>
    89. <version>${zxing.version}</version>
    90. </dependency>
    91. <dependency>
    92. <groupId>org.apache.pdfbox</groupId>
    93. <artifactId>pdfbox</artifactId>
    94. <version>${pdfbox.version}</version>
    95. </dependency>

    子pom

    1. <dependency>
    2. <groupId>org.apache.pdfbox</groupId>
    3. <artifactId>pdfbox</artifactId>
    4. </dependency>
    5. <dependency>
    6. <groupId>net.sf.jasperreports</groupId>
    7. <artifactId>jasperreports</artifactId>
    8. </dependency>
    9. <dependency>
    10. <groupId>com.lowagie</groupId>
    11. <artifactId>itext</artifactId>
    12. </dependency>
    13. <dependency>
    14. <groupId>xml-apis</groupId>
    15. <artifactId>xml-apis-ext</artifactId>
    16. </dependency>
    17. <dependency>
    18. <groupId>net.sf.barcode4j</groupId>
    19. <artifactId>barcode4j</artifactId>
    20. </dependency>
    21. <dependency>
    22. <groupId>net.sourceforge.barbecue</groupId>
    23. <artifactId>barbecue</artifactId>
    24. </dependency>
    25. <dependency>
    26. <groupId>software.amazon.awssdk</groupId>
    27. <artifactId>s3</artifactId>
    28. </dependency>

    报表导出

    1. public class PdfExporter {
    2. private static final Logger log = LoggerFactory.getLogger(PdfExporter.class);
    3. private final AwsRepositoryService awsRepositoryService;
    4. public PdfExporter(AwsRepositoryService awsRepositoryService) {
    5. this.awsRepositoryService = awsRepositoryService;
    6. }
    7. public byte[] merge(Rectangle rectangle, List<byte[]> bytes) {
    8. return export(rectangle, bytes);
    9. }
    10. public byte[] export(Rectangle rectangle, byte[] bytes) {
    11. return export(rectangle, Collections.singletonList(bytes));
    12. }
    13. /**
    14. * 单个或合并导出
    15. *
    16. * @param bytes
    17. * @param rectangle
    18. * @return
    19. */
    20. public byte[] export(Rectangle rectangle, List<byte[]> bytes) {
    21. Document document = new Document();
    22. document.setPageSize(rectangle);
    23. try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
    24. PdfWriter writer = PdfWriter.getInstance(document, out);
    25. List<PdfReader> readers = new ArrayList<>(bytes.size());
    26. for (byte[] item : bytes) {
    27. PdfReader reader = new PdfReader(item);
    28. readers.add(reader);
    29. }
    30. document.open();
    31. PdfContentByte content = writer.getDirectContent();
    32. for (PdfReader reader : readers) {
    33. int currentPageNum = 1;
    34. int totalPages = reader.getNumberOfPages();
    35. while (currentPageNum <= totalPages) {
    36. document.newPage();
    37. PdfImportedPage page = writer.getImportedPage(reader, currentPageNum);
    38. content.addTemplate(page, 0,
    39. rectangle.getHeight() - reader.getPageSize(currentPageNum).getHeight());
    40. currentPageNum++;
    41. }
    42. }
    43. document.close();
    44. return out.toByteArray();
    45. } catch (Exception e) {
    46. log.error("Generate pdf exception. message : {}", e.getMessage());
    47. throw new RuntimeException("Exception when printing label", e);
    48. } finally {
    49. if (document.isOpen()) {
    50. document.close();
    51. }
    52. }
    53. }
    54. public void merge(List<InputStream> ins, OutputStream out, Rectangle pageSize, int row, int col) {
    55. if (CollectionUtils.isEmpty(ins)) {
    56. return;
    57. }
    58. Document document = new Document();
    59. document.setPageSize(pageSize);
    60. int count = row * col;
    61. try {
    62. List<PdfReader> readers = new ArrayList<>(ins.size());
    63. for (InputStream in : ins) {
    64. PdfReader pdfReader = new PdfReader(in);
    65. readers.add(pdfReader);
    66. }
    67. PdfWriter writer = PdfWriter.getInstance(document, out);
    68. document.open();
    69. PdfContentByte cb = writer.getDirectContent();
    70. int x = 0;
    71. int y = 0;
    72. int i = 0;
    73. while (i < readers.size()) {
    74. if (i % count == 0) {
    75. document.newPage();
    76. x = 0;
    77. y = 0;
    78. }
    79. while (x < row && i < readers.size()) {
    80. y = 0;
    81. while (y < col && i < readers.size()) {
    82. int pageNum = 1;
    83. PdfReader reader = readers.get(i);
    84. while (pageNum <= reader.getNumberOfPages()) {
    85. PdfImportedPage page = writer.getImportedPage(reader, pageNum);
    86. int rotation = reader.getPageRotation(pageNum);
    87. if ((rotation == 90 || rotation == 270) && (row > 1 || col > 1)) {
    88. cb.addTemplate(page, 0, -1, 1, 0, y * reader.getPageSizeWithRotation(pageNum).getWidth(),
    89. (x + 1) * reader.getPageSizeWithRotation(pageNum).getHeight());
    90. } else {
    91. // (row==1 && col==1) ||rotation == 0
    92. cb.addTemplate(page, y * reader.getPageSize(pageNum).getWidth(), x * reader.getPageSize(pageNum).getHeight());
    93. }
    94. pageNum++;
    95. }
    96. i++;
    97. y++;
    98. }
    99. x++;
    100. }
    101. }
    102. out.flush();
    103. document.close();
    104. } catch (Exception e) {
    105. log.error("Generate pdf exception. message : {}", e.getMessage());
    106. throw new RuntimeException("Exception when printing label", e);
    107. } finally {
    108. if (document.isOpen()) {
    109. document.close();
    110. }
    111. }
    112. }
    113. public byte[] autoMerge(Rectangle pageSize, List<byte[]> bytes) {
    114. Document document = new Document();
    115. document.setPageSize(pageSize);
    116. try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
    117. List<PdfReader> readers = new ArrayList<>(bytes.size());
    118. for (byte[] item : bytes) {
    119. PdfReader pdfReader = new PdfReader(item);
    120. readers.add(pdfReader);
    121. }
    122. PdfWriter writer = PdfWriter.getInstance(document, out);
    123. document.open();
    124. PdfContentByte cb = writer.getDirectContent();
    125. float pageHeight = pageSize.getHeight();
    126. float pageWidth = pageSize.getWidth();
    127. int i = 0;
    128. while (i < readers.size()) {
    129. float h = 0;
    130. float w = 0;
    131. float x = 0;
    132. float y = pageHeight;
    133. while (i < readers.size() && x < pageWidth) {
    134. int pageNum = 1;
    135. if (x >= pageWidth && y <= 0) {
    136. document.newPage();
    137. x = 0;
    138. y = pageHeight;
    139. }
    140. PdfReader reader = readers.get(i);
    141. float previousH = 0;
    142. while (i < readers.size() && pageNum <= reader.getNumberOfPages()) {
    143. PdfImportedPage page = writer.getImportedPage(reader, pageNum);
    144. previousH = h;
    145. h = reader.getPageSize(pageNum).getHeight();
    146. w = reader.getPageSize(pageNum).getWidth();
    147. if (x + w >= pageWidth && y <= 0) {
    148. document.newPage();
    149. x = 0;
    150. y = pageHeight;
    151. }
    152. if (x + w >= pageWidth) {
    153. x = 0;
    154. }
    155. if (x == 0) {
    156. y = y - h;
    157. } else {
    158. if (h > previousH) {
    159. y = y - (h - previousH);
    160. }
    161. }
    162. if (y < 0) {
    163. document.newPage();
    164. x = 0;
    165. y = pageHeight - h;
    166. if (y < 0) {
    167. y = 0;
    168. }
    169. }
    170. cb.addTemplate(page, x, y);
    171. x = x + w;
    172. pageNum++;
    173. }
    174. i++;
    175. }
    176. }
    177. document.close();
    178. return out.toByteArray();
    179. } catch (Exception e) {
    180. log.error("Generate pdf exception. message : {}", e.getMessage());
    181. throw new RuntimeException("Exception when printing label", e);
    182. } finally {
    183. if (document.isOpen()) {
    184. document.close();
    185. }
    186. }
    187. }
    188. public byte[] export(final String template, final Object[] objects) throws Exception {
    189. final Map<String, Object> params = new HashMap<>();
    190. JasperReport jasperReport = awsRepositoryService.loadReport(template);
    191. if (Objects.isNull(jasperReport)) {
    192. log.error("jasper template {} not found.", template);
    193. throw new RuntimeException("Exception when printing label");
    194. }
    195. JRDataSource dataSource = new JRBeanArrayDataSource(objects);
    196. SimpleJasperReportsContext jasperReportsContext = new SimpleJasperReportsContext();
    197. jasperReportsContext.setExtensions(RepositoryService.class,
    198. Collections.singletonList(awsRepositoryService));
    199. JasperPrint print = JasperFillManager.getInstance(jasperReportsContext)
    200. .fill(jasperReport, params, dataSource);
    201. JRPdfExporter exporter = new JRPdfExporter();
    202. exporter.setExporterInput(SimpleExporterInput.getInstance(Collections.singletonList(print)));
    203. try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
    204. exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
    205. exporter.exportReport();
    206. return out.toByteArray();
    207. } catch (Exception e) {
    208. log.error("Generate pdf exception. message : {}", e.getMessage());
    209. throw new RuntimeException("Exception when printing label", e);
    210. }
    211. }
    212. }

    自定义AWS资源加载实现接口

    1. @Component
    2. public class AwsRepositoryService implements RepositoryService {
    3. private static final Logger log = LoggerFactory.getLogger(AwsRepositoryService.class);
    4. private static final String JASPER_SUFFIX = ".jasper";
    5. @Autowired
    6. private RedisTemplate<String, Object> redisTemplate;
    7. @Override
    8. public Resource getResource(String uri) {
    9. return null;
    10. }
    11. @Override
    12. public void saveResource(String uri, Resource resource) {
    13. throw new UnsupportedOperationException();
    14. }
    15. @Override
    16. public <K extends Resource> K getResource(String uri, Class<K> resourceType) {
    17. // aws文件资源
    18. if (InputStreamResource.class.equals(resourceType)) {
    19. InputStream inputStream = AmazonS3Util.getObjectAsInputStream(uri);
    20. if (Objects.isNull(inputStream)) {
    21. return null;
    22. }
    23. InputStreamResource resource = new InputStreamResource();
    24. resource.setInputStream(inputStream);
    25. return resourceType.cast(resource);
    26. }
    27. // aws报表资源
    28. if (ReportResource.class.equals(resourceType)) {
    29. final ReportResource reportResource = new ReportResource();
    30. JasperReport report;
    31. try {
    32. report = loadReport(uri);
    33. } catch (Exception e) {
    34. throw new RuntimeException(String.format("load report '%s' error", uri), e);
    35. }
    36. if (Objects.isNull(report)) {
    37. return null;
    38. }
    39. reportResource.setReport(report);
    40. return resourceType.cast(reportResource);
    41. }
    42. return null;
    43. }
    44. public JasperReport loadReport(String uri) {
    45. if(uri.endsWith(JASPER_SUFFIX)){
    46. uri = uri.substring(0,uri.length() - 7);
    47. }
    48. // 一级缓存,从redis加载报表资源
    49. JasperReport report = getCacheJasperReport(uri);
    50. if (Objects.isNull(report)) {
    51. // 刷新缓存后再次获取
    52. report = refreshCacheJasperReport(uri);
    53. }
    54. return report;
    55. }
    56. private JasperReport getCacheJasperReport(final String template) {
    57. return (JasperReport) redisTemplate.opsForHash().get(CacheKey.ALL_LABEL_TEMPLATE, template);
    58. }
    59. private void putJasperReportCache(final String template, JasperReport jasperReport) {
    60. redisTemplate.opsForHash().putIfAbsent(CacheKey.ALL_LABEL_TEMPLATE, template, jasperReport);
    61. }
    62. /**
    63. * 刷新对应模板的缓存
    64. *
    65. * @param template 模板名称,
    66. */
    67. private JasperReport refreshCacheJasperReport(final String template) {
    68. // 先从aws获取报表资源,再缓存至redis
    69. String key = template + JASPER_SUFFIX;
    70. byte[] bytes = AmazonS3Util.getObjectAsBytes(key);
    71. if (Objects.isNull(bytes)) {
    72. return null;
    73. }
    74. JasperReport report = null;
    75. try {
    76. report = (JasperReport) JRLoader.loadObject(new ByteArrayInputStream(bytes));
    77. } catch (JRException e) {
    78. log.error("'{}' load error. message : {}", key, e.getMessage());
    79. }
    80. if (Objects.isNull(report)) {
    81. return null;
    82. }
    83. putJasperReportCache(template, report);
    84. return report;
    85. }
    86. }

    config

    1. @Configuration
    2. public class PdfExporterConfig {
    3. @Bean
    4. public PdfExporter pdfExporter(AwsRepositoryService repositoryService) {
    5. return new PdfExporter(repositoryService);
    6. }
    7. }