You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot集成Crystal Reports连接PostgreSQL的问题排查

问题:Crystal Reports for Eclipse与Spring Boot集成时ODBC数据源连接失败

环境与前置问题

  • 使用64位Crystal Reports 2025,已安装PostgreSQL ODBC驱动
  • 创建.rpt文件时,JDBC连接能看到数据库表但无法展开字段(点击表名旁的‘+’无反应),ODBC连接则可正常列出字段

核心需求

将Crystal Reports for Eclipse SP31与Spring Boot(Gradle、Java 21)集成,实现从远程.rpt文件导出PDF的功能

当前实现代码

public byte[] generateReport() throws IOException, ReportSDKException {

    // 1) Download .rpt
    byte[] rptBytes = myStorageService.getFile(
            "https://url/to/the/file.rpt"
    );

    // 2) Write to a temp .rpt file
    Path tempRpt = Files.createTempFile("temp-", ".rpt");
    Files.write(tempRpt, rptBytes);
    tempRpt.toFile().deleteOnExit();

    // 3) Open in Crystal/JRC (read-only)
    ReportClientDocument report = new ReportClientDocument();
    try {
        report.open(
                tempRpt.toString(),
                com.crystaldecisions.sdk.occa.report.application.OpenReportOptions._openAsReadOnly
        );

        // 4) Grab DatabaseController & IDatabase
        DatabaseController dbController = report.getDatabaseController();
        IDatabase database = dbController.getDatabase();
        Connections connections = database.getConnections();

        // 5) Rebind each table
        for (int i = 0; i < connections.size(); i++) {
            IConnection conn = connections.get(i);
            IConnectionInfo connInfo = conn.getConnectionInfo();

            // a) Clear any old, designer-saved properties
            PropertyBag bag = connInfo.getAttributes();
            bag.clear();

            bag.put("DSN",              "PostgreSQL30");
            bag.put("User ID",          "my_user");
            bag.put("Password",         "my_password");
            bag.put("UseDSNProperties", "false");

            connInfo.setAttributes(bag);
            connInfo.setKind(ConnectionInfoKind.SQL);
            conn.setConnectionInfo(connInfo);
        }
        dbController.logonEx("PostgreSQL30", "", "my_user", "my_password");

        // 7) Export to PDF
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ExportOptions opts = new ExportOptions();
        PDFExportFormatOptions pdfOpts = new PDFExportFormatOptions();
        opts.setExportFormatType(ReportExportFormat.PDF);
        opts.setFormatOptions(pdfOpts);

        report.getPrintOutputController().export(opts, baos);
        baos.flush();
        return baos.toByteArray();
    } finally {
        try { report.close(); } catch (Exception ignored) {}
        Files.deleteIfExists(tempRpt);
    }
}

报错信息

2025-06-02T20:09:12.331-05:00 ERROR 40348 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: com.crystaldecisions.sdk.occa.report.lib.ReportSDKException: Error finding JNDI name (PostgreSQL30)---- Error code:-2147467259 Error code name:failed] with root cause

com.businessobjects.reports.jdbinterface.common.DBException: Error finding JNDI name (PostgreSQL30)
    at com.crystaldecisions.reports.queryengine.driverImpl.jdbc.JDBCConnection.Open(Unknown Source) ~[DatabaseConnectors.jar:12.2.232.5499]
    at com.crystaldecisions.reports.queryengine.JDBConnectionWrapper.Open(SourceFile:123) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.reports.queryengine.Connection.bs(SourceFile:1788) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.reports.queryengine.Connection.bv(SourceFile:507) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.reports.queryengine.Connection.uk(SourceFile:3035) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.reports.dataengine.dfadapter.DFAdapter.a(SourceFile:697) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.reports.dataengine.dfadapter.DFAdapter.for(SourceFile:707) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.reports.reportdefinition.ReportHelper.a(SourceFile:198) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.requesthandler.ReportViewingRequestHandler.long(SourceFile:962) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.requesthandler.ReportViewingRequestHandler.a(SourceFile:640) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.requesthandler.ReportViewingRequestHandler.int(SourceFile:666) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter.do(SourceFile:1944) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter.if(SourceFile:661) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter.a(SourceFile:167) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter$2.a(SourceFile:529) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter$2.call(SourceFile:526) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.reports.common.ThreadGuard.syncExecute(SourceFile:102) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter.for(SourceFile:525) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter.int(SourceFile:424) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.reports.sdk.JRCCommunicationAdapter.request(SourceFile:352) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.sdk.erom.jrc.a.a(SourceFile:54) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.businessobjects.sdk.erom.jrc.a.execute(SourceFile:67) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.proxy.remoteagent.RemoteAgent$a.execute(SourceFile:716) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.proxy.remoteagent.CommunicationChannel.a(SourceFile:125) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.proxy.remoteagent.RemoteAgent.a(SourceFile:537) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.sdk.occa.report.application.dt.a(SourceFile:186) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.sdk.occa.report.application.ReportSource.a(SourceFile:1558) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.sdk.occa.report.application.ReportSource.a(SourceFile:337) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.sdk.occa.report.application.PrintOutputController.if(SourceFile:224) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.sdk.occa.report.application.PrintOutputController.export(SourceFile:206) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.crystaldecisions.sdk.occa.report.application.PrintOutputController.export(SourceFile:184) ~[CrystalReportsRuntime.jar:12.2.232.5499]
    at com.myproject.services.AppReportService.generateReport(AppReportService.java:283) ~[main/:na]

已排查情况

  • 已在64位和32位ODBC数据源管理器中配置PostgreSQL30,Crystal Reports客户端可正常使用该数据源
  • 问题仅出现在Spring Boot集成后的报表导出环节

解决建议

  • 修正连接类型配置:当前代码中connInfo.setKind(ConnectionInfoKind.SQL)会让JRC尝试用JDBC/JNDI连接,改为ConnectionInfoKind.ODBC明确指定使用ODBC驱动
  • 调整ODBC属性参数:修改PropertyBag配置,添加驱动名称等关键参数,确保JRC能识别ODBC驱动:
    bag.put("DSN",              "PostgreSQL30");
    bag.put("User ID",          "my_user");
    bag.put("Password",         "my_password");
    bag.put("UseDSNProperties", "true"); // 依赖DSN配置时设为true
    bag.put("Driver",           "{PostgreSQL Unicode(x64)}"); // 对应安装的64位驱动名称
    
  • 替换logonEx方法:dbController.logonEx("PostgreSQL30", "", "my_user", "my_password")中的第一个参数被解析为JNDI名称,改用dbController.logon("my_user", "my_password"),让JRC使用已配置的ODBC连接信息
  • 确认进程位数匹配:Spring Boot是64位Java进程,必须确保系统中64位PostgreSQL ODBC驱动已正确安装,且ODBC数据源是64位版本(32位数据源无法被64位进程识别)
  • 改用直连配置(推荐):在Spring Boot环境中,DSN可能因权限或环境变量问题无法被JRC读取,直接配置数据库地址、端口、库名等参数替代DSN:
    bag.clear();
    bag.put("Driver", "{PostgreSQL Unicode(x64)}");
    bag.put("Server", "your_db_host");
    bag.put("Port", "5432");
    bag.put("Database", "your_db_name");
    bag.put("User ID", "my_user");
    bag.put("Password", "my_password");
    bag.put("UseDSNProperties", "false");
    
  • 验证依赖兼容性:确保Crystal Reports for Eclipse的JAR包支持Java 21,若版本不兼容需升级到对应支持版本
  • 检查数据库权限:确认my_user拥有报表涉及表的SELECT权限,且服务器端口开放、网络连接正常

内容的提问来源于stack exchange,提问作者José

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:17:33