找回密码
 立即注册

QQ登录

只需一步,快速开始

lucas.Yan
超级版主   /  发表于:2024-12-11 14:42  /   查看:71  /  回复:0
本帖最后由 lucas.Yan 于 2024-12-20 13:40 编辑

应用场景:客户在创建前后端分离的应用时,前端只用于做一些基本的数据展示,如果涉及大量的数据或报表生成,建议放在服务器端展示,本文主要分享如何在服务器端使用ActiveReportsJS 实现报表导出PDF功能
Demo下载

运行Demo
1 下载对应浏览器版本的WebDriver:Microsoft Edge WebDriver | Microsoft Edge Developer(本Demo使用的Edge浏览器)
2 配置Java项目
3 运行maven
4 修改代码中的WebDriver地址
5 运行程序,访问index接口
环境准备:Maven3、Tomcat9.0.88、Java17、Edge浏览器和对应版本的WebDriver。

主要代码:
利用selenium的无头浏览器调用报表的导出方法,将返回的PDF数据流保存为文件形式。然后通过调用服务器的打印程序进行打印。
  1. package Servlet;

  2. import org.apache.pdfbox.pdmodel.PDDocument;
  3. import org.apache.pdfbox.printing.PDFPageable;
  4. import org.openqa.selenium.JavascriptExecutor;
  5. import org.openqa.selenium.WebDriver;
  6. import org.openqa.selenium.edge.EdgeDriver;
  7. import org.openqa.selenium.edge.EdgeOptions;

  8. import javax.servlet.ServletException;
  9. import javax.servlet.annotation.WebServlet;
  10. import javax.servlet.http.HttpServlet;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.awt.*;
  14. import java.awt.print.PrinterException;
  15. import java.awt.print.PrinterJob;
  16. import java.io.File;
  17. import java.io.FileOutputStream;
  18. import java.io.IOException;
  19. import java.util.Base64;

  20. @WebServlet(name = "index", value = "/index")
  21. public class index extends HttpServlet {


  22.     @Override
  23.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
  24.         EdgeOptions edgeOptions = new EdgeOptions();

  25.         edgeOptions.addArguments("--headless");
  26.         edgeOptions.addArguments("--disable-gpu");
  27.         edgeOptions.addArguments("--no-sandbox");
  28.         //resources文件夹下有一份,替换使用。
  29.         System.setProperty("webdriver.edge.driver", "C:\\Users\\LucasYan\\Desktop\\客户资源\\后端导出arjs-java\\src\\main\\resources\\msedgedriver.exe");
  30.         String resultString = getPDFString(edgeOptions);

  31.         resp.setContentType("text/plain");
  32.         resp.setCharacterEncoding("UTF-8");

  33.         resp.getWriter().write(resultString);

  34.         //去掉前缀,转换为PDF文件并保存。
  35.         String pdfstring = resultString.replace("data:application/pdf;base64,", "");
  36.         byte[] pdfBytes = Base64.getDecoder().decode(pdfstring);
  37.         File file = new File("output.pdf");
  38.         try (FileOutputStream fos = new FileOutputStream(file)) {
  39.             fos.write(pdfBytes);
  40.             // 打开PDF文档
  41.             PDDocument document = PDDocument.load(file);
  42.             // 创建一个PrinterJob
  43.             PrinterJob job = PrinterJob.getPrinterJob();
  44.             // 设置页面格式
  45.             job.setPageable(new PDFPageable(document));
  46.             // 尝试打印文档
  47. //            job.print();
  48.             // 关闭文档
  49.             document.close();
  50.             System.out.println("PDF 文件已成功生成:output.pdf");
  51.         } catch (IOException e) {
  52.             e.printStackTrace();
  53.         }
  54. //        catch (PrinterException e){
  55. //            e.printStackTrace();
  56. //        }
  57.     }

  58.     private static String getPDFString(EdgeOptions edgeOptions) {
  59.         WebDriver driver = new EdgeDriver(edgeOptions);
  60.         String targetUrl = "http://localhost:8080/static/arjs.html"; // Replace with actual URL
  61.         driver.get(targetUrl);
  62.         // 执行页面上的脚本呢
  63.         JavascriptExecutor jsExecutor = (JavascriptExecutor) driver;
  64.         Object result = jsExecutor.executeScript(
  65.                 "var callback = arguments[arguments.length - 1];" +
  66.                         "return generatePDF().then(callback);"); // Replace with actual function name
  67.         return result != null ? result.toString() : "";
  68.     }
  69. }
复制代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.   <head>
  4.     <meta charset="UTF-8" />
  5.     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.     <title>Proposal Generation</title>
  8.       <link
  9.               rel="stylesheet"
  10.               href="https://cdn.grapecity.com/activereportsjs/5.0.0/styles/ar-js-ui.css"
  11.               type="text/css"
  12.       />
  13. <!--      <link-->
  14. <!--              rel="stylesheet"-->
  15. <!--              href="https://cdn.grapecity.com/activereportsjs/5.0.0/styles/ar-js-designer.css"-->
  16. <!--              type="text/css"-->
  17. <!--      />-->
  18.       <link
  19.               rel="stylesheet"
  20.               href="https://cdn.grapecity.com/activereportsjs/5.0.0/styles/ar-js-viewer.css"
  21.               type="text/css"
  22.       />
  23.       <script src="https://cdn.grapecity.com/activereportsjs/5.0.0/dist/ar-js-core.js"></script>
  24. <!--      <script src="https://cdn.grapecity.com/activereportsjs/5.0.0/dist/ar-js-designer.js"></script>-->
  25.       <script src="https://cdn.grapecity.com/activereportsjs/5.0.0/dist/ar-js-pdf.js"></script>
  26.       <script src="https://cdn.grapecity.com/activereportsjs/5.0.0/dist/ar-js-tabular-data.js"></script>
  27.       <script src="https://cdn.grapecity.com/activereportsjs/5.0.0/dist/ar-js-html.js"></script>
  28.       <script type="text/javascript" src="./datasource.js"></script>

  29.   </head>
  30.   <body>
  31.     <embed id="pdf" type="application/pdf"  width="100%" height="800px" />
  32.   </body>
  33.   <script type="text/javascript">
  34.       const ARJS = MESCIUS.ActiveReportsJS.Core;
  35.       const fonts = [
  36.           {
  37.               name: '微软雅黑',
  38.               locals: ['Microsoft YaHei', 'SimSun Regular'],
  39.               source: './fonts/Chinese.ttf',
  40.           },
  41.           {
  42.               name: 'Sinhala',
  43.               locals: ['Microsoft YaHei', 'SimSun Regular'],
  44.               source: './fonts/Chinese.ttf',
  45.           },
  46.           {
  47.               name: 'Arial',
  48.               weight: 'bold',
  49.               style: 'italic',
  50.               source: './fonts/arialbi.ttf',
  51.           },
  52.           {
  53.               name: 'Arial',
  54.               style: 'italic',
  55.               source: './fonts/ariali.ttf',
  56.           },
  57.           {
  58.               name: 'Arial',
  59.               weight: 'bold',
  60.               source: './fonts/arialbd.ttf',
  61.           },
  62.           {
  63.               name: 'Arial',
  64.               source: './fonts/arial.ttf',
  65.           },
  66.       ];
  67.       ARJS.FontStore.registerFonts(fonts);
  68.       const settings = {
  69.           info: {
  70.               title: 'Invoice List',
  71.               subject: 'This is the Invoice List',
  72.               author: 'John K',
  73.               keywords: 'PDF; import; export',
  74.           },
  75.           fonts: fonts,
  76.       };
  77.       const lang = 'HK';
  78.       function blob2base64(blob) {
  79.           return new Promise((resolve, reject) => {
  80.               var reader = new FileReader();
  81.               reader.onloadend = () => {
  82.                   resolve(reader.result);
  83.               };
  84.               reader.onerror = () => {
  85.                   reject(reader.err);
  86.               };
  87.               reader.readAsDataURL(blob);
  88.           });
  89.       }

  90.       async function generateProposal(mainReport) {
  91.           const start = new Date();
  92.           console.log(`start generate proposal inner puppeteer HTML ${start}`);
  93.           const PDF = MESCIUS.ActiveReportsJS.PdfExport;
  94.           const pageReport = new ARJS.PageReport();
  95.           try {
  96.               await pageReport.load(mainReport);
  97.               if ('LicenseError' === pageReport.name) {
  98.                   throw new Error('License Error');
  99.               }
  100.               const pageDocument = await pageReport.run();
  101.               console.log('page report randered completed, start export the PDF');
  102.               const result = await PDF.exportDocument(pageDocument, settings, pageNum => {
  103.                   console.log(`exporting PDF version at page ${pageNum}`);
  104.               });
  105.               console.log(`pdf document exported completed, cost ${Date.now() - start}ms`);
  106.               return blob2base64(result.data);
  107.           } catch (e) {
  108.               console.error(`error occured while generate the proposal, ${e}`);
  109.               throw e;
  110.           }
  111.       }
  112.   </script>
  113.   <script>
  114.       async function generatePDF() {
  115.           return await generateProposal('templates/123.rdlx-json');
  116.       }
  117.   </script>
  118. </html>
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部