扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
Spring 框架已经作为逻辑层被广泛的用于轻量级的J2EE开发中。Spring 框架可以很好的和Struts, WebWork, Hibernate等其他开源项目集成在一起。尤其在重构现有应用的使用,Spring 框架可以提供很多帮助。存储过程可以用来封装业务逻辑,控制用户权限,以及做日常的增删改查(CRUD)。在重构已有系统的时候,一般存储过程中的业务逻辑并不需要改变,只是调用存储过程的方式需要进行调整。Spring 框架提供了完整的存储过程封装,数据源管理的功能,使用Spring 框架,开发人员可以很容易的构建轻量级J2EE应用。本文将给出一个使用Spring 框架和Struts来调用存储过程的完整例子,包括如何传入参数,如何获得传出参数,如何获得结果集以及如何获得多个结果集。
读者定位为具有DB2和Web开发经验的开发和设计人员。
读者可以学习到如何使用Spring框架来调用存储过程,可以通过文中的代码快速构建一个使用Spring框架的Web应用。本文的例子将包括使用Apache Struts进行网页表单的提交和验证,使用Spring框架来调用具有输入输出参数和返回结果集的存储过程,结果集将通过DisplayTag来进行显示。
Spring是一个广泛应用于逻辑层的开源框架,它使构建J2EE应用程序的Java开发人员可以直达实质问题的核心,而不是在提供服务的细节上花费大量时间。您可以通过developerWorks的文章"Spring 系列: Spring 框架简介"来了解Spring框架。Spring框架中一个重要的模块就是Spring DAO,它允许开发者在不同数据访问技术间切换,而且Spring提供了统一的异常处理机制,在切换的同时不用考虑异常处理。
当前很多应用程序使用存储过程来封装业务逻辑,在重构已有应用的时候,只是更改调用存储过程的方式。在调用存储过程方面现在大多直接采用JDBC的操作处理,这种方法需要创建数据库连接、创建statement语句、关闭ResultSet、关闭statement、关闭数据库连接、处理异常等等,一方面这些代码与业务逻辑不相关,另一方面也可能会给应用引入bug。因此很多人更青睐于使用数据持久化框架。在数据持久化框架中Hibernate 倍受人们关注,它主要提供Java对象与关系数据库的映射(O/R Mapping),这样只需关心操作java对象而不必关心底层数据。在Hibernate 3.0中也提供了对存储过程查询的支持,但是要求存储过程必须返回一个结果集,并且关键的是应用要遵循O/R Mapping的设计要求来架构应用系统。Spring DAO为JDBC提供了抽象层,使得开发者更高效的使用JDBC,它提供了对存储过程的支持,通过抽象类org.springframework.jdbc.object.StoredProcedure我们可以方便的调用存储过程,支持输入参数、输出参数和多个结果集。下面将通过一个实例详细的介绍使用Spring框架来调用存储过程的方法。
实例将实现在页面表单输入客户代码custNum,然后通过存储过程查询数据库中客户信息,得到所有客户信息和所查客户信息,并将其返回结果在页面上显示。您可以下载实例代码,代码可以在Eclipse环境中运行,对照代码看这篇文章更直观。
我们首先来看DB2的存储过程。存储过程一般被用来返回数据库中表的数据或者对表的数据进行更改。在这里我们使用存储过程从表中获得结果集。
首先我们需要建立DB2环境:
1) 把远程DB2服务器编制到本地。在这里我们远程的DB2主机地址是zxl01.cn.ibm.com,端口是50001
db2 CATALOG TCPIP NODE node01 REMOTE zxl01.cn.ibm.com SERVER 50001 |
2) 在本地建立远程DB2的别名。在这里我们使用testDB作为别名。
db2 CATALOG DB testDB AT NODE node01 |
3) 创建customer数据表
DROP TABLE DSW.CUSTOMER @ CREATE TABLE DSW.CUSTOMER ( CUST_NUM VARCHAR(10) NOT NULL, CUST_NAME VARCHAR(35) NOT NULL, ADDRESS VARCHAR(35) NOT NULL, CITY VARCHAR(35) NOT NULL, COUNTRY VARCHAR(3) NOT NULL, ADD_DATE TIMESTAMP NOT NULL ) @ ALTER TABLE DSW.CUSTOMER ADD CONSTRAINT CUSTOMER_PK PRIMARY KEY (CUST_NUM) @ |
4) 创建存储过程
DROP PROCEDURE DSW.S_CUSTOMER @ CREATE PROCEDURE DSW.S_CUSTOMER ( OUT poStatus INTEGER, IN piCust_num VARCHAR(10) ) LANGUAGE SQL SPECIFIC DSW.S_CUSTOMER RESULT SETS 2 P1: BEGIN NOT ATOMIC ------------------------------------------------------------- -- CONDITION declaration ------------------------------------------------------------- DECLARE sqlReset CONDITION for sqlstate '80100'; -- Generic Variables DECLARE SQLCODE INTEGER DEFAULT 0; DECLARE SQLSTATE CHAR(5) DEFAULT '00000'; -- Generic handler variables DECLARE hSqlcode INTEGER DEFAULT 0; DECLARE hSqlstate CHAR(5) DEFAULT '00000'; DECLARE v_Cnt INT; -- Cursor for returning RS to the client DECLARE cursor1 CURSOR WITH RETURN TO CLIENT FOR ( SELECT CUST_NUM, CUST_NAME FROM DSW.CUSTOMER ); DECLARE cursor2 CURSOR WITH RETURN TO CLIENT FOR ( SELECT * FROM DSW.CUSTOMER WHERE CUST_NUM = piCust_num ); OPEN cursor1; OPEN cursor2; SET poStatus = 2; RETURN poStatus; END P1 @ |
5) 插入测试数据
INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY) VALUES('1','Steven','shang di','BeiJing','CHN') @ INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY) VALUES('2','David','shang di','BeiJing','CHN') @ INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY) VALUES('3','Tony','shang di','BeiJing','CHN') @ INSERT INTO DSW.CUSTOMER (CUST_NUM,CUST_NAME,ADDRESS,CITY,COUNTRY) VALUES('4','Maggie','shang di','BeiJing','CHN') @ |
将Spring框架集成到现有的Web应用中十分容易,在web.xml中的Listener部分增加一个Spring的ContextLoaderListener同时设置contextConfigLocation参数,指向Spring的配置文件位置。如清单6所示。在web.xml中还有对于Struts的支持,读者可以参考developerworks上的Struts专题来了解如何使用Struts。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app id="WebApp"> <display-name>SpringSproc</display-name> <!-- Standard Action Servlet Configuration --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext-service.xml </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app> |
将Spring和Struts进行整合的方法有很多,developerworks上的文章"使用 Spring 更好地处理 Struts 动作"中介绍了几种方法,可以参照。
在Spring的配置文件applicationContext-service.xml中我们对使用到的Java类和数据源进行了配置。通过指定driverClassName、url、username、password等属性就可以创建数据源。在清单7中我们使用直接连接数据库的方式,我们也可以使用在应用服务器中配置的DataSource来连接数据库,只需要更改为不同的Reference就可以改变对数据库的连接方式。在这方面,Spring框架显示出了很强的灵活性。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="dataSourceJDBC" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>COM.ibm.db2.jdbc.app.DB2Driver</value> </property> <property name="url"> <value>jdbc:db2:testDB</value> </property> <property name="username"> <value>dsw</value> </property> <property name="password"> <value>pass4spring</value> </property> </bean> <bean id="SearchImpl" class="com.springsproc.dao.jdbc.SearchDAOImpl"> <property name="dataSource"> <ref local="dataSourceJDBC" /> </property> <property name="sprocName"> <value>DSW.S_CUSTOMER</value> </property> </bean> </beans> |
在Java代码SearchAction.java中将连接实例化。这也是Spring中的核心思想之一:控制反转(Inversion of Control)。清单8中(1)是把一个在applicationContext-service.xml中配置的bean实例化成对象,(2)调用getBean方法得到基于接口SearchDAO(具体见清单9) 的实例SearchImpl bean,然后再通过(3)调用具体的方法去执行存储过程。
private static ApplicationContext ctx = null; public Object getBean(String name) { |(1) if (ctx == null) { ctx = WebApplicationContextUtils .getRequiredWebApplicationContext (servlet.getServletContext()); } return ctx.getBean(name); } SearchDAO mgr = (SearchDAO) getBean("SearchImpl"); |(2) Map map = mgr.execute(custNum); |(3) |
package com.springsproc.dao; import java.util.List; public interface SearchDAO { public Map execute(String custNum); } |
4. 使用Spring framework为存储过程传入参数
用户在web页面上填入custNum,提交后经Struts的validation验证传入action的FormBean中,然后再从FormBean中得到custNum,并由清单8中(3)传入Spring framework。
5. 使用Spring framework获得存储过程的传出参数和结果集
Spring framework提供了调用存储过程的方法,下面对几个相关的类和接口做简单介绍,你也可以通过Spring API获得更多详细信息。
了解了Spring为我们提供的这些关于存储过程的方法和接口后,来看看具体的实现方法。如清单10所示。SearchDAOImpl.java中有三个内部类,其中SearchCustomersProcedure来负责声明数据库连接和存储过程名(2)、输入参数(6)、输出参数(5)以及输出结果集(3)(4),DemoRowMapper和DemoRowMapper2来负责取得结果集中的数据。其中(3)创建一个名为"resultSet"的结果集,通过DemoRowMapper(7)来取得结果集中的数据,当有多个结果集的时候需要重复这个过程,如(6)(8)。最后由execute方法(1)填入输入参数并执行存储过程调用。
public Map execute(String custNum) { SearchCustomersProcedure sp = new SearchCustomersProcedure(dataSource); Map map = new HashMap(1); map.put("piCust_num", custNum); Map results = sp.execute(map); |(1) return results; } private class SearchCustomersProcedure extends StoredProcedure { SearchCustomersProcedure(DataSource dataSource) { super(dataSource, sprocName); |(2) declareParameter(new SqlReturnResultSet("resultSet", new DemoRowMapper())); |(3) declareParameter(new SqlReturnResultSet("resultSet2", new DemoRowMapper2())); |(4) declareParameter(new SqlOutParameter("poGenStatus", Types.INTEGER)); |(5) declareParameter(new SqlParameter("piCust_num", Types.VARCHAR)); |(6) } } private class DemoRowMapper implements RowMapper { |(7) public Object mapRow(ResultSet rs, int rowNum) throws SQLException { Customer customer = new Customer(); customer.setCustNum(rs.getString(1)); customer.setCustName(rs.getString(2)); return customer; } } private class DemoRowMapper2 implements RowMapper { |(8) public Object mapRow(ResultSet rs, int rowNum) throws SQLException { Customer customer = new Customer(); customer.setCustName(rs.getString(1)); customer.setCustNum(rs.getString(2)); customer.setCustAddress(rs.getString(3)); customer.setCustCity(rs.getString(4)); customer.setCustCountry(rs.getString(5)); return customer; } } |
6. 在Web页面上显示结果集 (使用DisplayTag)
在SearchAction从SearchDAOImpl取得数据以后,将数据以attribute方式存入request中,如清单11中(1)(2)所示。在页面中使用DisplayTag将request中的数据以表格形式显示出来。可以指定列名或者按某些列排序,如清单12中(1);也可以不做任何处理,只是将数据显示出来,如清单12中(2)。可以在DisplayTag Homepage得到更多关于DisplayTag的详细信息。
List list = (List)map.get("resultSet"); List list2 = (List)map.get("resultSet2"); String poGenStatus = map.get("poGenStatus").toString(); log.info("poGenStatus is:" + poGenStatus); request.setAttribute("customerList",list); |(1) request.setAttribute("MyCustomers",list2); |(2) return mapping.findForward("list"); |
|(1) <display:table name="customerList" cellspacing="2" cellpadding="2" requestURI="" defaultsort="1" id="customers"> <%-- Table columns --%> <display:column property="custNum" sort="true" headerClass="sortable" title="Customer number" headerStyleClass="header"/> <display:column property="custName" sort="true" headerClass="sortable" title="Customer name" headerStyleClass="header"/> </display:table> |(2) <display:table name="myCustomer" cellspacing="2" cellpadding="2" requestURI="" defaultsort="1" id="myCustomer"> </display:table> |
这样使用Spring framework调用存储过程的实例就完成了,运行该实例,如下图所示:
Spring框架提供了一些接口和类,封装了对数据库的处理,极大地简化了对数据库的操作。开发人员可以把更多的精力放在业务逻辑上。数据库连接等信息写在配置文件中,在运行期装入bean中进行连接操作实例化的方法使系统更加灵活,可以在部署应用的时候很方便的更改,不仅提高了团队开发的效率,也提高了系统的可维护性。
本文以一个实例介绍了使用Spring框架调用存储过程的方法,通过本文您已经可以使用Spring框架结合不同类型的存储过程来对DB2中的数据进行操作。并且参照这个实例您可以创建基于Struts + Spring框架的web应用系统。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者