JSP中渲染Crystal Report时从web.xml修改数据库连接的方法
解决Crystal Report在JSP渲染时动态修改数据库连接的问题
针对你的需求,这里提供两种实用的实现方案,适配你现有项目结构,帮你在报表渲染阶段从web.xml读取连接信息并替换设计时的固定连接:
方案一:通过web.xml上下文参数存储连接字符串
首先在你的web.xml中添加数据库连接相关的上下文参数,方便统一管理:
<!-- 新增数据库连接参数 --> <context-param> <param-name>dbJdbcUrl</param-name> <param-value>jdbc:sqlserver://your-db-server:1433;databaseName=IntranetDBW</param-value> </context-param> <context-param> <param-name>dbUsername</param-name> <param-value>your-db-username</param-value> </context-param> <context-param> <param-name>dbPassword</param-name> <param-value>your-db-password</param-value> </context-param> <context-param> <param-name>dbDriverClass</param-name> <param-value>com.microsoft.sqlserver.jdbc.SQLServerDriver</param-value> </context-param>
然后修改JSP代码,在打开报表后动态替换数据库连接:
<%@ page import= "com.crystaldecisions.report.web.viewer.*,com.crystaldecisions.sdk.occa.report.data.*" %> <%@ page import="com.crystaldecisions.sdk.occa.report.lib.*"%> <%@ page import="com.crystaldecisions.sdk.occa.report.*"%> <%@page import="com.crystaldecisions.reports.sdk.*" %> <%@page import="com.crystaldecisions.sdk.occa.report.exportoptions.*" %> <%@page import="javax.servlet.ServletContext" %> <% // 从web.xml读取预配置的连接参数 ServletContext appContext = getServletConfig().getServletContext(); String jdbcUrl = appContext.getInitParameter("dbJdbcUrl"); String dbUser = appContext.getInitParameter("dbUsername"); String dbPwd = appContext.getInitParameter("dbPassword"); String driverClass = appContext.getInitParameter("dbDriverClass"); // 打开报表文件 String REPORT_NAME = "test_table.rpt"; ReportClientDocument reportClientDoc = new ReportClientDocument(); reportClientDoc.open(REPORT_NAME, 0); // 获取报表的数据库控制器,用于修改连接 DatabaseController dbController = reportClientDoc.getDatabaseController(); IConnectionInfo originalConnInfo = dbController.getConnectionInfos(null).getConnectionInfo(0); // 构建新的连接属性集合 PropertyBag newConnProps = new PropertyBag(); newConnProps.put("JDBC Connection String", jdbcUrl); newConnProps.put("JDBC Driver Class Name", driverClass); newConnProps.put("User ID", dbUser); newConnProps.put("Password", dbPwd); // 根据数据库类型补充其他必要属性,比如SQL Server需要的Server Name、Database Name newConnProps.put("Server Name", jdbcUrl.split("://")[1].split(";")[0]); newConnProps.put("Database Name", jdbcUrl.split("databaseName=")[1]); // 更新连接信息 originalConnInfo.setAttributes(newConnProps); originalConnInfo.setUserName(dbUser); originalConnInfo.setPassword(dbPwd); // 应用新连接到报表 dbController.setConnection(originalConnInfo, originalConnInfo, null, 0); // 初始化报表查看器并渲染 CrystalReportViewer viewer = new CrystalReportViewer(); viewer.setOwnPage(true); viewer.setOwnForm(true); viewer.setPrintMode(CrPrintMode.ACTIVEX); viewer.setReportSource(reportClientDoc.getReportSource()); viewer.processHttpRequest(request, response, appContext, null); %>
方案二:利用已配置的容器数据源(推荐)
你已经在web.xml中配置了jdbc/IntranetDBW的资源引用,这种方式更安全(容器管理密码)且支持连接池,是生产环境的首选方案:
修改JSP代码如下:
<%@ page import= "com.crystaldecisions.report.web.viewer.*,com.crystaldecisions.sdk.occa.report.data.*" %> <%@ page import="com.crystaldecisions.sdk.occa.report.lib.*"%> <%@ page import="com.crystaldecisions.sdk.occa.report.*"%> <%@page import="com.crystaldecisions.reports.sdk.*" %> <%@page import="com.crystaldecisions.sdk.occa.report.exportoptions.*" %> <%@page import="javax.naming.InitialContext" %> <%@page import="javax.sql.DataSource" %> <%@page import="java.sql.Connection" %> <% // 从容器中获取预配置的数据源 InitialContext ctx = new InitialContext(); DataSource dbSource = (DataSource) ctx.lookup("java:comp/env/jdbc/IntranetDBW"); Connection dbConn = dbSource.getConnection(); // 打开报表文件 String REPORT_NAME = "test_table.rpt"; ReportClientDocument reportClientDoc = new ReportClientDocument(); reportClientDoc.open(REPORT_NAME, 0); // 修改报表连接 DatabaseController dbController = reportClientDoc.getDatabaseController(); IConnectionInfo originalConnInfo = dbController.getConnectionInfos(null).getConnectionInfo(0); PropertyBag newConnProps = new PropertyBag(); newConnProps.put("Database DLL", "crdb_jdbc.dll"); // 对应JDBC驱动的DLL文件 newConnProps.put("JDBC Connection String", dbConn.getMetaData().getURL()); newConnProps.put("User ID", dbConn.getMetaData().getUserName()); originalConnInfo.setAttributes(newConnProps); originalConnInfo.setUserName(dbConn.getMetaData().getUserName()); // 应用更新 dbController.setConnection(originalConnInfo, originalConnInfo, null, 0); // 归还连接到连接池 dbConn.close(); // 渲染报表 CrystalReportViewer viewer = new CrystalReportViewer(); viewer.setOwnPage(true); viewer.setOwnForm(true); viewer.setPrintMode(CrPrintMode.ACTIVEX); viewer.setReportSource(reportClientDoc.getReportSource()); viewer.processHttpRequest(request, response, getServletConfig().getServletContext(), null); %>
关键注意事项
- 连接类型匹配:确保动态设置的连接类型和报表设计时的类型一致(比如都是JDBC),否则会出现兼容性错误。
- 属性适配:不同数据库的
PropertyBag属性略有差异,比如Oracle和SQL Server的参数名称不同,需要根据你的数据库类型调整。 - 资源释放:使用容器数据源时,务必关闭
Connection对象,让连接归还到连接池,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Masum billah
相关产品推荐
相关产品推荐

