electron 如何在Node.js应用程序中使用SAP Crystal Reports

pxq42qpu  于 2023-03-16  发布在  Electron
关注(0)|答案(1)|浏览(165)

我正在尝试在电子应用程序(桌面Node.js应用程序)中使用SAP Crystal Reports。我有几个*.rpt文件,应该从SQLite数据库中读取数据,然后打印一些报表。
但似乎没有JavaScript库可以让我做到这一点。我唯一找到的是SAP Crystal Reports JavaScript API,它只是SAP Business Intelligence Platform的一个客户端库,我不使用它。我只需要打印一些报表,而不需要依赖任何外部服务器。
有人设法在Node.js应用程序中使用Crystal Reports进行打印吗?

5hcedyr0

5hcedyr01#

似乎无法直接从Node.js应用程序与Crystal Reports交互。因此,我决定编写一个简单的命令行Java程序,该程序使用Crystal Reports Java SDK。我从Node.js应用程序运行此Java程序。

水晶报表CLI(Java)

我的项目中只有一个cr-cli/CrystalReport.java文件:

import com.crystaldecisions.sdk.occa.report.application.*;
import com.crystaldecisions.sdk.occa.report.data.*;
import com.crystaldecisions.sdk.occa.report.document.*;
import com.crystaldecisions.sdk.occa.report.lib.*;
import com.crystaldecisions.sdk.occa.report.exportoptions.*;
import java.io.*;
import java.nio.file.*;
import org.apache.commons.cli.*;

public class CrystalReport {

  public static void main(String args[]) {
    Options options = new Options();

    Option databaseOption = new Option("d", "database", true, "database file path");
    databaseOption.setRequired(true);
    options.addOption(databaseOption);

    Option exportOption = new Option("e", "export", true, "output PDF file path");
    options.addOption(exportOption);

    Option reportOption = new Option("r", "report", true, "report file path");
    reportOption.setRequired(true);
    options.addOption(reportOption);

    Option selectionOption = new Option("s", "selection", true, "record selection formula");
    selectionOption.setRequired(true);
    options.addOption(selectionOption);

    CommandLine cmd = null;

    try {
      CommandLineParser parser = new DefaultParser();
      cmd = parser.parse(options, args);
    } catch (ParseException e) {
      System.out.println(e.getMessage());

      HelpFormatter formatter = new HelpFormatter();
      formatter.printHelp("cr-cli", options);

      System.exit(1);
    }

    String databasePath = cmd.getOptionValue("database");
    String exportPath = cmd.getOptionValue("export");
    String reportPath = cmd.getOptionValue("report");
    String selectionFormula = cmd.getOptionValue("selection");

    try {
      CrystalReport report = new CrystalReport(reportPath, databasePath, selectionFormula);

      if (exportPath != null) {
        Files.createDirectories(Paths.get(exportPath).getParent());
        report.export(exportPath);
      } else {
        report.print();
      }
    } catch (Exception ex) {
      ex.printStackTrace();
      System.exit(1);
    }
  }

  private ReportClientDocument report;

  public CrystalReport(String reportPath, String databasePath, String selectionFormula) throws ReportSDKException {
    this.report = new ReportClientDocument();
    this.report.open(reportPath, 0);

    this.report.setRecordSelectionFormula(selectionFormula);

    CrystalReport.replaceDatabaseConnection(this.report, databasePath);
    SubreportController subreportController = report.getSubreportController();
    for (String subreportName : subreportController.getSubreportNames()) {
      ISubreportClientDocument subreport = subreportController.getSubreport(subreportName);
      CrystalReport.replaceDatabaseConnection(subreport, databasePath);
    }
  }

  private static void replaceDatabaseConnection(IReportClientDocument report, String databasePath) throws ReportSDKException {
    DatabaseController databaseController = report.getDatabaseController();
    IConnectionInfo oldConnectionInfo = databaseController.getConnectionInfos(null).getConnectionInfo(0);

    PropertyBag attributes = new PropertyBag(oldConnectionInfo.getAttributes());
    attributes.put("Connection URL", "jdbc:sqlite:" + databasePath);

    IConnectionInfo newConnectionInfo = new ConnectionInfo(oldConnectionInfo);
    newConnectionInfo.setAttributes(attributes);

    int replaceParams = DBOptions._ignoreCurrentTableQualifiers + DBOptions._doNotVerifyDB;
    databaseController.replaceConnection(oldConnectionInfo, newConnectionInfo, null, replaceParams);
  }

  public void export(String exportPath) throws IOException, FileNotFoundException, ReportSDKException {
    ByteArrayInputStream byteArrayInputStream = (ByteArrayInputStream) this.report.getPrintOutputController().export(ReportExportFormat.PDF);
    byte byteArray[] = new byte[byteArrayInputStream.available()];

    File file = new File(exportPath);
    FileOutputStream fileOutputStream = new FileOutputStream(file);

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(byteArrayInputStream.available());
    int x = byteArrayInputStream.read(byteArray, 0, byteArrayInputStream.available());
    byteArrayOutputStream.write(byteArray, 0, x);
    byteArrayOutputStream.writeTo(fileOutputStream);
  }

  public void print() throws ReportSDKException {
    this.report.getPrintOutputController().printReport(new PrintReportOptions());
  }
}

这些文件位于cr-cli/lib文件夹中:

com.azalea.ufl.barcode.1.0.jar
commons-configuration-1.2.jar
CrystalCommon2.jar
DatabaseConnectors.jar
JDBInterface.jar
log4j-api.jar
pfjgraphics.jar
sqlite-jdbc-3.41.0.0.jar
XMLConnector.jar
commons-cli-1.5.0.jar
commons-lang-2.1.jar
CrystalReportsRuntime.jar
icu4j.jar
jrcerom.jar
log4j-core.jar
QueryBuilder.jar
webreporting.jar
xpp3.jar
commons-collections-3.2.2.jar
commons-logging.jar
cvom.jar
jai_imageio.jar
keycodeDecoder.jar
logging.jar
sap.com~tc~sec~csi.jar
webreporting-jsf.jar

我使用以下命令编译它:

javac -classpath './cr-cli/lib/*' -source 8 -target 8 ./cr-cli/CrystalReport.java

然后我从我的Electron(Node.js)应用程序运行它,方法如下:

import {exec} from 'child_process';
import {app} from 'electron';
import path from 'path';

interface CrystalReportsCliOptions {
  databasePath: string;
  exportPath?: string;
  reportPath: string;
  selectionFormula: string;
}

const cliPath = path.join(app.isPackaged ? process.resourcesPath : process.cwd(), 'cr-cli');

export async function runCrystalReportsCli(options: CrystalReportsCliOptions) {
  const javaVersion = await detectJavaVersion();
  if (javaVersion < 8) {
    return;
  }

  const command = ['java'];
  if (javaVersion >= 9) {
    command.push('--add-exports', 'java.base/sun.security.action=ALL-UNNAMED');
  }
  command.push('-classpath', `"${cliPath + path.delimiter + path.join(cliPath, 'lib/*')}"`);

  command.push('CrystalReport');
  command.push('--database', options.databasePath);
  command.push('--report', options.reportPath);
  command.push('--selection', `"${options.selectionFormula}"`);
  if (options.exportPath) {
    command.push('--export', options.exportPath);
  }

  return new Promise((resolve, reject) => {
    exec(command.join(' '), (error, stdout) => (error ? reject(error) : resolve(stdout)));
  });
}

function detectJavaVersion(): Promise<number> {
  return new Promise(resolve => {
    exec('java -version', (error, _, stderr) => {
      if (error) {
        resolve(0);
      } else {
        const [versionLine] = stderr.split('\n');
        const version = versionLine.split('"')[1];
        const majorVersion = Number(version.split('.')[version.startsWith('1.') ? 1 : 0]);

        resolve(majorVersion);
      }
    });
  });
}

相关问题