OSWorkflow 2.7.0 範例應用在 MySQL + Tomcat 環境下的完整配置步驟,包含 server.xml DataSource、osworkflow.xml 持久化映射、propertyset.xml 屬性集、web.xml 資源參照、JAR 放置位置,並詳細分析啟動時 web.xml ParseError: NullPointerException 的根因與修正方案。
mysql-connector-java-3.1.x 或 org.gjt.mm.mysql.Driver)<Context path="/osworkflow_example" docBase="osworkflow-2.7.0-example"
debug="99" reloadable="true" crossContext="true">
<Resource name="jdbc/DefaultDS"
auth="Container"
type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/DefaultDS">
<parameter><name>factory</name><value>org.apache.commons.dbcp.BasicDataSourceFactory</value></parameter>
<parameter><name>maxActive</name><value>100</value></parameter>
<parameter><name>maxIdle</name><value>30</value></parameter>
<parameter><name>maxWait</name><value>10000</value></parameter>
<parameter><name>username</name><value>root</value></parameter>
<parameter><name>password</name><value></value></parameter>
<parameter><name>driverClassName</name><value>com.mysql.jdbc.Driver</value></parameter>
<parameter><name>url</name><value>jdbc:mysql://localhost:3306/osworkflow?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8</value></parameter>
</ResourceParams>
</Context>
關鍵修正:驅動類別名稱改為 com.mysql.jdbc.Driver(官方驅動),URL 加入編碼參數。
<osworkflow>
<persistence class="com.opensymphony.workflow.spi.jdbc.MySQLWorkflowStore">
<property key="datasource" value="jdbc/DefaultDS"/>
<property key="entry.sequence" value="SELECT COALESCE(MAX(ID),0)+1 FROM OS_WFENTRY"/>
<property key="entry.table" value="OS_WFENTRY"/>
<property key="entry.id" value="ID"/>
<property key="entry.name" value="NAME"/>
<property key="entry.state" value="STATE"/>
<property key="step.sequence" value="SELECT COALESCE(MAX(ID),0)+1 FROM (SELECT ID FROM OS_CURRENTSTEP UNION SELECT ID FROM OS_HISTORYSTEP) AS T"/>
<property key="step.sequence.increment" value="INSERT INTO OS_STEPIDS (ID) VALUES (NULL)"/>
<property key="step.sequence.retrieve" value="SELECT MAX(ID) FROM OS_STEPIDS"/>
<property key="history.table" value="OS_HISTORYSTEP"/>
<property key="current.table" value="OS_CURRENTSTEP"/>
<property key="historyPrev.table" value="OS_HISTORYSTEP_PREV"/>
<property key="currentPrev.table" value="OS_CURRENTSTEP_PREV"/>
<!-- 其餘欄位映射省略 -->>
</persistence>
</osworkflow>
序列查詢改用 MAX(ID)+1 相容 MySQL,避免原版 count(*) 在高併發下產生重複鍵。
<propertysets>
<propertyset name="jdbc" class="com.opensymphony.module.propertyset.database.JDBCPropertySet">
<arg name="datasource" value="jdbc/DefaultDS"/>
<arg name="table.name" value="OS_PROPERTYENTRY"/>
<arg name="col.globalKey" value="GLOBAL_KEY"/>
<arg name="col.itemKey" value="ITEM_KEY"/>
<arg name="col.itemType" value="ITEM_TYPE"/>
<arg name="col.string" value="STRING_VALUE"/>
<arg name="col.date" value="DATE_VALUE"/>
<arg name="col.data" value="DATA_VALUE"/>
<arg name="col.float" value="FLOAT_VALUE"/>
<arg name="col.number" value="NUMBER_VALUE"/>
</propertyset>
</propertysets>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"https://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>OSWorkflow Example App</display-name>
<welcome-file-list><welcome-file>default.jsp</welcome-file></welcome-file-list>
<resource-ref>
<description>OSWorkflow Example App</description>
<res-ref-name>jdbc/DefaultDS</res-ref-name>
<res-ref-type>javax.sql.DataSource</res-ref-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
錯誤根因:原始 web.xml 宣告 encoding="ISO-8859-1" 但內含中文註解/內容,且 DTD 宣告行尾多出分號 ;>,導致 Digester 解析拋 NullPointerException。修正:編碼改 UTF-8、移除多餘分號、確保檔案實際儲存為 UTF-8。
| JAR | 位置 |
|---|---|
| mysql-connector-java-*.jar | $CATALINA_HOME/common/lib/ |
| commons-dbcp.jar, commons-pool.jar, commons-collections.jar | $CATALINA_HOME/common/lib/ |
| jboss-j2ee.jar | $CATALINA_HOME/common/endorsed/ (提供 JTA API) |
| osworkflow.jar, propertyset.jar | WEB-INF/lib/ |
CREATE DATABASE osworkflow DEFAULT CHARACTER SET utf8;
USE osworkflow;
CREATE TABLE OS_WFENTRY (ID BIGINT PRIMARY KEY, NAME VARCHAR(255), STATE INT);
CREATE TABLE OS_CURRENTSTEP (ID BIGINT PRIMARY KEY, ENTRY_ID BIGINT, STEP_ID INT, OWNER VARCHAR(255), START_DATE DATETIME, FINISH_DATE DATETIME, STATUS CHAR(1));
CREATE TABLE OS_HISTORYSTEP (ID BIGINT PRIMARY KEY, ENTRY_ID BIGINT, STEP_ID INT, OWNER VARCHAR(255), START_DATE DATETIME, FINISH_DATE DATETIME, STATUS CHAR(1));
CREATE TABLE OS_CURRENTSTEP_PREV (ID BIGINT, PREVIOUS_ID BIGINT);
CREATE TABLE OS_HISTORYSTEP_PREV (ID BIGINT, PREVIOUS_ID BIGINT);
CREATE TABLE OS_STEPIDS (ID BIGINT AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE OS_PROPERTYENTRY (GLOBAL_KEY VARCHAR(250), ITEM_KEY VARCHAR(250), ITEM_TYPE INT, STRING_VALUE VARCHAR(255), DATE_VALUE DATETIME, DATA_VALUE BLOB, FLOAT_VALUE DOUBLE, NUMBER_VALUE BIGINT, PRIMARY KEY (GLOBAL_KEY, ITEM_KEY));
ParseError、NullPointerException。BasicDataSourceFactory 成功建立 Pool。https://localhost:8080/osworkflow_example/ 進入範例首頁。OS_WFENTRY 確認寫入成功。