Spring Framework 廣泛用於輕量級 J2EE 開發邏輯層,與 Struts、WebWork、Hibernate 等開源專案整合良好,重構既有系統時尤顯威力。預存程序可封裝業務邏輯、控制權限、處理 CRUD。重構時業務邏輯不變,僅需調整呼叫方式。Spring 提供完整預存程序封裝與資料源管理,讓開發者輕鬆建構輕量級 J2EE 應用。
本文提供 Spring + Struts 呼叫 DB2 預存程序完整範例:輸入/輸出參數、單一/多結果集處理、DisplayTag 顯示結果。適用對象:具 DB2 與 Web 開發經驗的開發/設計人員。
org.springframework.jdbc.object.StoredProcedure 抽象類支援輸入/輸出參數與多結果集編目遠端 DB2 伺服器(主機 zxl01.cn.ibm.com,埠 50001):
db2 CATALOG TCPIP NODE node01 REMOTE zxl01.cn.ibm.com SERVER 50001
db2 CATALOG DB testDB AT NODE node01
建立客戶資料表:
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)@
建立預存程序 DSW.S_CUSTOMER(輸出狀態碼、輸入客戶編號、返回 2 個結果集):
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
DECLARE sqlReset CONDITION FOR SQLSTATE '80100';
DECLARE SQLCODE INTEGER DEFAULT 0;
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE hSqlcode INTEGER DEFAULT 0;
DECLARE hSqlstate CHAR(5) DEFAULT '00000';
DECLARE v_Cnt INT;
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@
插入測試資料:
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')@
web.xml 整合 Spring ContextLoaderListener**:
<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>
applicationContext-service.xml**:
<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>
彈性優勢:資料庫連線資訊寫在配置檔,部署時輕鬆切換 DataSource 實作(如應用伺服器配置的 JNDI DataSource),提升團隊開發效率與系統可維護性。
SearchAction.java**(控制反轉 IoC 核心體現):
private static ApplicationContext ctx = null;
public Object getBean(String name) {
if (ctx == null) {
ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servlet.getServletContext());
}
return ctx.getBean(name);
}
// 在 execute 方法中:
SearchDAO mgr = (SearchDAO) getBean("SearchImpl"); // (1) 實例化 Bean (2) 取得介面實現
Map map = mgr.execute(custNum); // (3) 呼叫具體方法執行預存程序
package com.springsproc.dao;
import java.util.List;
public interface SearchDAO {
public Map execute(String custNum);
}
SearchDAOImpl.java**:
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); // 執行預存程序
return results;
}
private class SearchCustomersProcedure extends StoredProcedure {
SearchCustomersProcedure(DataSource dataSource) {
super(dataSource, sprocName); // 設定資料源與預存程序名
// 宣告第一個結果集
declareParameter(new SqlReturnResultSet("resultSet", new DemoRowMapper()));
// 宣告第二個結果集
declareParameter(new SqlReturnResultSet("resultSet2", new DemoRowMapper2()));
// 宣告輸出參數
declareParameter(new SqlOutParameter("poGenStatus", Types.INTEGER));
// 宣告輸入參數
declareParameter(new SqlParameter("piCust_num", Types.VARCHAR));
}
}
// RowMapper 實作:將 ResultSet 映射為領域物件
private class DemoRowMapper implements RowMapper {
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 {
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;
}
}
| 類別/介面 | 用途 |
|---|---|
StoredProcedure | 抽象類,declareParameter() 宣告參數,execute() 執行呼叫 |
SqlParameter | 代表預存程序參數 |
ResultSetSupportingSqlParameter | SqlOutParameter、SqlReturnResultSet 共同基類 |
SqlOutParameter | 代表輸出參數 |
SqlReturnResultSet | 代表輸出結果集 |
RowMapper | 介面,mapRow() 將 ResultSet 映射為物件 |
SearchAction.java 續**:
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); // 所有客戶清單
request.setAttribute("MyCustomers", list2); // 查詢客戶明細
return mapping.findForward("list");
SearchByCustNumber.jsp 使用 DisplayTag**:
<!-- 可排序、指定欄位顯示 -->
<display:table name="customerList" cellspacing="2" cellpadding="2" requestURI="" defaultsort="1" id="customers">
<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>
<!-- 直接顯示所有欄位 -->
<display:table name="myCustomer" cellspacing="2" cellpadding="2" requestURI="" defaultsort="1" id="myCustomer">
</display:table>
執行結果截圖:

本文以完整實例展示 Spring Framework 呼叫 DB2 預存程序的方法,涵蓋參數傳遞、多結果集處理、DisplayTag 前端顯示。參考此範例,您可結合不同類型預存程序操作 DB2 資料,並快速建構基於 Struts + Spring 的 Web 應用系統。