BPM是jboss旗下遵守LGPL许可的java开源工作流,功能比较完善,从4.0开始引入了pvm的概念,支持jPDL、BPEL等流程定义语言。由于相关资料还比较少,开发自己的一个demo还不是太容易,本文详细讲解如何做一个简单的demo程序。
    我们从http://www.jboss.org/jbossjbpm/jbpm_downloads/下载jBPM,实际使用时发现4.0.CR1和4.1版本各有一些问题,此处把这两个版本都下载下来。开发使用4.1版本,Eclipse插件GPD(图形化设计流程)使用4.0.CR1版本的,tomcat使用6.0.18版本的,jdk要求5.0及以上,Eclipse使用eclipse-jee-galileo-win32版本的。
    下载包里面有自带的一个example,根据jBMP的文档可以部署,但这个example把工作流部分封装为RESTful Web Service,学习起来有一定难度,看了会让人一头雾水,此处就不讲了。以下讲述如何把jBPM嵌入到应用系统中去。
    1、在Eclipse中安装GPD。
    把%jbpm-4.0.CR1_HOME%/gpd下的jbpm-gpd-site.zip安装到Eclipse中,熟悉Eclipse的知道安装方法,在jBPM的文档中也有介绍。
    2、在Eclipse中建立一个动态网站的项目jBPMDemo,复制必要的jar文件到WEB-INF/lib下面。
    把%jbpm-4.1_HOME%/lib下的所有jar文件、%jbpm-4.1_HOME%/jbpm.jar复制过去。
    但juel.jar中javax/el中的类与tomcat中的有冲突,把juel.jar中的javax/el删除。
    3、配置mysql数据库。
    在mysql数据库中建立一个名为jbpmdb的数据库,在里面执行%jbpm-4.1_HOME%/install/src/db/jbpm.mysql.create.sql建立jbpm所需的数据库表。
    另外建立一个表存放业务数据:
create table ask_for_leave ( 
id MEDIUMINT NOT NULL AUTO_INCREMENT primary key, 
apply_user varchar(50), -- 申请人 
apply_time timestamp default now(), -- 申请时间 
begin_leave_time timestamp, -- 假期开始时间 
end_leave_time timestamp, -- 假期结束时间 
leave_reason varchar(500), -- 请假理由 
approve_user varchar(50), -- 审批人 
approve_time timestamp, -- 审批时间 
is_passed smallint, -- 是否同意,1 同意,2 驳回 
approve_remark varchar(500), -- 审批备注,如驳回的原因 
back_time timestamp -- 销假时间 
);
    4、配置JOTM事务支持。
    把carol.properties、jta.jar、commons-logging.jar、carol.jar、connector-1_5.jar、jotm.jar、jotm_jrmp_stubs.jar、jts1_0.jar、mysql-connector-java-3.1.11-bin.jar、objectweb-datasource.jar、xapool.jar放到%tomcat_home%/lib下面。
    把howl.jar、jotm.jar、objectweb-datasource.jar、ow_carol.jar、xapool.jar放到WEB-INF/lib下面。
    在jBPLDemo的context配置数据源,代码如下:
<?xml version='1.0' encoding='utf-8'?> 
<Context displayName="jBPMDemo" 
         docBase="${catalina.base}/webapps/jBPMDemo"  
         path="/jBPMDemo"  
         workDir="work/Catalina/localhost/jBPMDemo" reloadable="true"> 
          
   <Resource name="UserTransaction" 
      auth="Container" 
      type="javax.transaction.UserTransaction" 
      factory="org.objectweb.jotm.UserTransactionFactory" 
      jotm.timeout="180" />

<Resource name="JbpmDS" type="javax.sql.DataSource" 
      factory="org.objectweb.jndi.DataSourceFactory" 
      maxWait="5000" 
      maxActive="300" 
      maxIdle="2" 
      username="root" 
      password="" 
      driverClassName="com.mysql.jdbc.Driver" 
      url="jdbc:mysql://127.0.0.1:3306/jbpmdb" 
   />      
        
</Context>

    在应用的WEB-INF/classes下建立文件jbpm.cfg.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>

<jbpm-configuration>

<import resource="jbpm.default.cfg.xml" /> 
  <import resource="jbpm.tx.hibernate.cfg.xml" /> 
  <import resource="jbpm.jpdl.cfg.xml" /> 
  <import resource="jbpm.identity.cfg.xml" /> 
  <import resource="jbpm.businesscalendar.cfg.xml" /> 
  <import resource="jbpm.jobexecutor.cfg.xml" />

</jbpm-configuration>

    在应用的WEB-INF/classes下建立文件jbpm.hibernate.cfg.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-configuration PUBLIC 
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration> 
<session-factory>

<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> 
<property name="hibernate.connection.datasource">java:comp/env/JbpmDS</property> 
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property> 
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JOTMTransactionManagerLookup</property>
<property name="jta.UserTransaction">java:comp/env/UserTransaction</property>

<mapping resource="jbpm.repository.hbm.xml" /> 
<mapping resource="jbpm.execution.hbm.xml" /> 
<mapping resource="jbpm.history.hbm.xml" /> 
<mapping resource="jbpm.task.hbm.xml" /> 
<mapping resource="jbpm.identity.hbm.xml" />

</session-factory> 
</hibernate-configuration>

    5、在Eclipse中GPD定义流程。
    GPD对中文的支持还有问题,要用图形界面与直接编写代码相结合的方式,最后效果如下图:
流程图
    产生的代码askForLeave.jpdl.xml放到应用的WEN-INF/classes/jpdl下面,代码如下:
<?xml version="1.0" encoding="UTF-8"?>

<process key="askForLeave" name="请假流程" version="1" xmlns="http://jbpm.org/4.0/jpdl"> 
   <swimlane candidate-groups="manager" name="manager"/> 
   <start g="188,10,48,48" name="start1"> 
      <transition g="-30,-10" name="开始" to="填写请假申请"/> 
   </start> 
   <task assignee="#{owner}" g="167,86,92,52" name="填写请假申请"> 
      <transition g="-50,-11" name="提交审批" to="审批"/> 
   </task> 
   <task g="169,159,92,52" name="审批" swimlane="manager"> 
      <transition g="-76,-8" name="判断审批结果" to="exclusive1"/> 
   </task> 
   <task assignee="#{owner}" g="91,298,92,52" name="销假"> 
      <transition g="-50,-11" name="休假结束" to="end1"/> 
   </task> 
   <task assignee="#{owner}" g="252,295,92,52" name="查看原因"> 
      <transition g="-34,-10" name="请假结束" to="end2"/> 
   </task> 
   <end g="116,377,48,48" name="end1"/> 
   <end g="275,372,48,48" name="end2"/> 
   <decision g="190,227,48,48" name="exclusive1"> 
      <transition g="0,-15" name="拒绝" to="查看原因"> 
        <condition expr="#{is_passed==false}"/> 
      </transition> 
      <transition g="-31,-16" name="通过" to="销假"/> 
   </decision> 
</process>

    产生的图片askForLeave.png放到应用的askForLeave文件夹下面。
    6、建立几个java类。
demo.jbpm.DBUtil:
package demo.jbpm;

import java.sql.Connection;

import javax.naming.InitialContext; 
import javax.sql.DataSource;

import javax.transaction.UserTransaction;

public class DBUtil { 
    private static DataSource ds; 
    /** 
     * 获取数据源 
     * @return 
     * @throws Exception 
     */ 
    public static DataSource getDS() throws Exception { 
        if (ds == null) ds = (DataSource) new InitialContext().lookup("java:comp/env/JbpmDS"); 
        return ds; 
    } 
     
    /** 
     * 获取数据库连接 
     * @return 
     * @throws Exception 
     */ 
    public static Connection getConn() throws Exception { 
        return getDS().getConnection(); 
    } 
     
    /** 
     * 获取事务UserTransaction 
     * @return 
     * @throws Exception 
     */ 
    public static UserTransaction getUserTransaction() throws Exception { 
        UserTransaction ut = (UserTransaction) new InitialContext().lookup("java:comp/env/UserTransaction"); 
        return ut; 
    } 
}

    demo.jbpm.JBPMUtil.java:
package demo.jbpm;

import org.jbpm.api.Configuration; 
import org.jbpm.api.ExecutionService; 
import org.jbpm.api.IdentityService; 
import org.jbpm.api.ProcessEngine; 
import org.jbpm.api.RepositoryService; 
import org.jbpm.api.TaskService;

public class JBPMUtil { 
    private static ProcessEngine pe; 
    private static RepositoryService repositoryService; 
    private static ExecutionService executionService; 
    private static IdentityService identityService; 
    private static TaskService taskService; 
     
    public static void deploy(String jdplPath) { 
        String deployId = getRepositoryService().createDeployment().addResourceFromClasspath(jdplPath).deploy(); 
        System.out.println("----------deploy id:" + deployId); 
    } 
     
    public static ProcessEngine getProcessEngine() { 
        if (pe == null) { 
            Configuration config = new Configuration(); 
            pe = config.buildProcessEngine(); 
        } 
        return pe; 
    } 
     
    public static RepositoryService getRepositoryService() { 
        if (repositoryService == null) repositoryService = getProcessEngine().getRepositoryService(); 
        return repositoryService; 
    } 
     
    public static ExecutionService getExecutionService() { 
        if (executionService == null) executionService = getProcessEngine().getExecutionService(); 
        return executionService; 
    } 
     
    public static IdentityService getIdentityService() { 
        if (identityService == null) identityService = getProcessEngine().getIdentityService(); 
        return identityService; 
    } 
     
    public static TaskService getTaskService() { 
        if (taskService == null) taskService = getProcessEngine().getTaskService(); 
        return taskService; 
    } 
}

    demo.jbpm.AskForLeave.java:
package demo.jbpm;

import java.sql.Connection; 
import java.sql.ResultSet; 
import java.sql.Statement; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Set;

import javax.servlet.http.HttpServletRequest; 
import javax.transaction.Status; 
import javax.transaction.UserTransaction;

import org.jbpm.api.ProcessDefinition; 
import org.jbpm.api.ProcessInstance; 
import org.jbpm.api.model.ActivityCoordinates; 
import org.jbpm.api.task.Task;

public class AskForLeave { 
    private final static String employeeName = "王三"; 
    private final static String managerName = "李五"; 
     
    public static void deploy() { 
        JBPMUtil.deploy("jpdl/askForLeave.jpdl.xml"); 
        JBPMUtil.getIdentityService().createUser(employeeName, "王", "三"); 
        JBPMUtil.getIdentityService().createUser(managerName, "李", "五"); 
        JBPMUtil.getIdentityService().createGroup("manager"); 
        JBPMUtil.getIdentityService().createMembership(managerName, "manager"); 
    } 
     
    /** 
     * 请假申请 
     * @param request 
     * @throws Exception 
     */ 
    public static void apply(HttpServletRequest request) throws Exception { 
        UserTransaction ut =DBUtil.getUserTransaction(); 
        Connection conn = DBUtil.getConn(); 
        boolean rollback = false; 
        try { 
            ut.begin(); 
            //*********业务部分 
            //请假申请存入数据库 
            Statement stmt = conn.createStatement(); 
            String sql = "insert into ask_for_leave(apply_user," + 
                  "begin_leave_time,end_leave_time,leave_reason) values(" + 
                  "'" + request.getParameter("apply_user") + "'," + 
                  "'" + request.getParameter("begin_leave_time") + "'," + 
                  "'" + request.getParameter("end_leave_time") + "'," + 
                  "'" + request.getParameter("leave_reason") + "')"; 
            System.out.println("insert:" + sql); 
            stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); 
            ResultSet rs = stmt.getGeneratedKeys(); 
            int id = 0; 
            if (rs.next()) id = rs.getInt(1); 
            System.out.println("--------------id:" + id); 
             
             
            //*********工作流部分 
            //新建工作流实例 
            Map var = new HashMap(); 
            var.put("owner", employeeName); 
            var.put("biz_id", id); 
            ProcessInstance processInstance = JBPMUtil.getExecutionService().startProcessInstanceByKey("askForLeave", var);
             
            //执行动作 
            List<Task> tasks = JBPMUtil.getTaskService().findPersonalTasks(employeeName); 
            for (Task t : tasks) { 
                if (processInstance.getId().equals(JBPMUtil.getExecutionService().findExecutionById(t.getExecutionId()).getProcessInstance().getId())
                        && t.getActivityName().equals("填写请假申请")) { 
                     
                    JBPMUtil.getTaskService().completeTask(t.getId()); 
                } 
                 
            } 
        } 
        catch (Exception e) { 
            rollback = true; 
            e.printStackTrace(); 
            throw e; 
        } 
        finally { 
            if (ut != null && ut.getStatus() != Status.STATUS_NO_TRANSACTION) { 
                if (rollback) ut.rollback(); 
                else ut.commit(); 
            } 
             
            if (conn != null) conn.close(); 
        } 
    } 
     
    /** 
     * 获取经理的工作列表 
     * @return 
     * @throws Exception 
     */ 
    public static List<Map> getManagerWorkList() throws Exception { 
        List<Map> workList = new ArrayList<Map>(); 
        List<Task> tasks = JBPMUtil.getTaskService().findGroupTasks(managerName); 
        System.out.println("---------task count:" + tasks.size()); 
        for (Task t : tasks) { 
            String processDefinitionId = JBPMUtil.getExecutionService().findExecutionById(t.getExecutionId()).getProcessInstance().getProcessDefinitionId();
            ProcessDefinition processDefinition = JBPMUtil.getRepositoryService().createProcessDefinitionQuery().processDefinitionId(processDefinitionId).uniqueResult();
            System.out.println("---------pro name:" + JBPMUtil.getExecutionService().findExecutionById(t.getExecutionId()).getProcessInstance().getProcessDefinitionId());
            System.out.println("---------acct name:" + t.getActivityName()); 
            if ("请假流程".equals(processDefinition.getName()) 
                    && t.getActivityName().equals("审批")) { 
                Map item = new HashMap(); 
                item.put("wfId", JBPMUtil.getExecutionService().findExecutionById(t.getExecutionId()).getProcessInstance().getId());
                item.put("wfName", "请假流程"); 
                item.put("taskId", t.getId()); 
                item.put("taskName", t.getActivityName()); 
                workList.add(item); 
            } 
        } 
        return workList; 
    } 
     
    /** 
     * 获取位置 
     * @param wfId 
     * @return 
     */ 
    public static List<ActivityCoordinates> getActiveActivityCoordinates(String wfId) { 
        List<ActivityCoordinates> result = new ArrayList<ActivityCoordinates>(); 
        ProcessInstance processInstance = JBPMUtil.getExecutionService().findProcessInstanceById(wfId); 
        String processDefinitionId = processInstance.getProcessDefinitionId(); 
        Set<String> activities = processInstance.findActiveActivityNames(); 
        for (String act : activities) { 
            ActivityCoordinates coor = JBPMUtil.getRepositoryService().getActivityCoordinates(processDefinitionId, act); 
            result.add(coor); 
        } 
         
        return result; 
    } 
     
    /** 
     * 根据请假单id获取请假单信息 
     * @param id 
     * @return 
     * @throws Exception 
     */ 
    public static Map getById(String id) throws Exception { 
        Map form = new HashMap(); 
        Connection conn = DBUtil.getConn(); 
         
        try { 
            Statement stmt = conn.createStatement(); 
            ResultSet rst = stmt.executeQuery("select * from ask_for_leave where id=" + id); 
            if (rst.next()) { 
                form.put("apply_user", rst.getString("apply_user")); 
                form.put("begin_leave_time", rst.getString("begin_leave_time")); 
                form.put("end_leave_time", rst.getString("end_leave_time")); 
                form.put("leave_reason", rst.getString("leave_reason")); 
            } 
            rst.close(); 
            stmt.close(); 
        } 
        catch (Exception e) { 
            e.printStackTrace(); 
            throw e; 
        } 
        finally { 
             
            if (conn != null) conn.close(); 
        } 
         
        return form; 
    } 
     
    /** 
     * 根据工作流id货物请假单id 
     * @param wfId 
     * @return 
     * @throws Exception 
     */ 
    public static String getBizId(String taskId) throws Exception { 
         
        return JBPMUtil.getTaskService().getVariable(taskId, "biz_id").toString(); 
    } 
     
    /** 
     * 审批 
     * @param request 
     * @throws Exception 
     */ 
    public static void approval(HttpServletRequest request) throws Exception { 
        UserTransaction ut = DBUtil.getUserTransaction(); 
        Connection conn = DBUtil.getConn(); 
        boolean rollback = false; 
        try { 
            ut.begin(); 
             
            //*********业务部分 
            //审批信息存入数据库 
            Statement stmt = conn.createStatement(); 
            String sql = "update ask_for_leave set " + 
                  "approve_user='" + managerName + "', " + 
                  "approve_time=now()," + 
                  "is_passed=" + request.getParameter("is_passed") + "," + 
                  "approve_remark='" + request.getParameter("approve_remark") + "' " + 
                  "where id=" + request.getParameter("biz_id"); 
            System.out.println("--------------update:" + sql); 
            stmt.executeUpdate(sql); 
            System.out.println("--------------update complete"); 
             
            //*********工作流部分 
            boolean isPassed = false; 
            if ("1".equals(request.getParameter("is_passed"))) isPassed = true; 
            Map var = new HashMap(); 
            var.put("is_passed", isPassed); 
            JBPMUtil.getTaskService().completeTask(request.getParameter("taskId"), var); 
        } 
        catch (Exception e) { 
            rollback = true; 
            e.printStackTrace(); 
            throw e; 
        } 
        finally { 
            if (ut != null && ut.getStatus() != Status.STATUS_NO_TRANSACTION) { 
                if (rollback) ut.rollback(); 
                else ut.commit(); 
            } 
             
            if (conn != null) conn.close(); 
        } 
    } 
     
    /** 
     * 获取员工的工作列表 
     * @return 
     * @throws Exception 
     */ 
    public static List<Map> getEmployeeWorkList() throws Exception { 
        List<Map> workList = new ArrayList<Map>(); 
        List<Task> tasks = JBPMUtil.getTaskService().findPersonalTasks(employeeName); 
        System.out.println("---------task count:" + tasks.size()); 
        for (Task t : tasks) { 
            String processDefinitionId = JBPMUtil.getExecutionService().findExecutionById(t.getExecutionId()).getProcessInstance().getProcessDefinitionId();
            ProcessDefinition processDefinition = JBPMUtil.getRepositoryService().createProcessDefinitionQuery().processDefinitionId(processDefinitionId).uniqueResult();
            System.out.println("---------pro name:" + JBPMUtil.getExecutionService().findExecutionById(t.getExecutionId()).getProcessInstance().getProcessDefinitionId());
            System.out.println("---------acct name:" + t.getActivityName()); 
            if ("请假流程".equals(processDefinition.getName())) { 
                Map item = new HashMap(); 
                item.put("wfId", JBPMUtil.getExecutionService().findExecutionById(t.getExecutionId()).getProcessInstance().getId());
                item.put("wfName", "请假流程"); 
                item.put("taskId", t.getId()); 
                item.put("taskName", t.getActivityName()); 
                item.put("biz_id", JBPMUtil.getTaskService().getVariable(t.getId(), "biz_id")); 
                workList.add(item); 
            } 
        } 
        return workList; 
    } 
     
    /** 
     * 申请人处理审批后的事务 
     * @param request 
     * @throws Exception 
     */ 
    public static void leave(HttpServletRequest request) throws Exception { 
        UserTransaction ut = DBUtil.getUserTransaction(); 
        Connection conn = DBUtil.getConn(); 
        boolean rollback = false; 
        try { 
            ut.begin(); 
            //处理休假情况 
            boolean isPassed = (Boolean) JBPMUtil.getTaskService().getVariable(request.getParameter("taskId"), "is_passed");
            int bizId = (Integer) JBPMUtil.getTaskService().getVariable(request.getParameter("taskId"), "biz_id"); 
            if (isPassed) { 
                Statement stmt = conn.createStatement(); 
                String sql = "update ask_for_leave set " + 
                      "back_time=now() " + 
                      "where id=" + bizId; 
                System.out.println("--------------update:" + sql); 
                stmt.executeUpdate(sql); 
            } 
             
            //*********工作流部分 
            JBPMUtil.getTaskService().completeTask(request.getParameter("taskId")); 
        } 
        catch (Exception e) { 
            rollback = true; 
            e.printStackTrace(); 
            throw e; 
        } 
        finally { 
            if (ut != null && ut.getStatus() != Status.STATUS_NO_TRANSACTION) { 
                if (rollback) ut.rollback(); 
                else ut.commit(); 
            } 
             
            if (conn != null) conn.close(); 
        } 
    } 
}

    7、建立jsp文件。
    askForLeave/deploy.jsp(用于部署jpdl,需要首先运行,只需要运行一次):
<%@page import="demo.jbpm.AskForLeave"%> 
<% 
AskForLeave.deploy(); 
%>
    askForLeave/apply.jsp(用于启动业务,需要第二个运行):
<%@ page language="java" contentType="text/html; charset=UTF-8"     pageEncoding="UTF-8"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>apply</title> 
</head> 
<body> 
<form name="form1" method="POST" action="apply_result.jsp"> 
申请人:<input type="text" name="apply_user" value="suntao"/><br/> 
假期开始时间:<input type="text" name="begin_leave_time" value="2009-08-07 09:00"/>(YYYY-MM-DD HH24:MI)<br/> 
假期结束时间:<input type="text" name="end_leave_time" value="2009-08-07 18:00"/>(YYYY-MM-DD HH24:MI)<br/> 
请假理由:<input type="text" name="leave_reason" value="事假"/><br/> 
<input type="submit" value="提交"/><br/> 
</form> 
</body> 
</html>
    askForLeave/apply_result.jsp(用于响应apply.jsp):
<%@ page language="java" contentType="text/html; charset=UTF-8" 
    pageEncoding="UTF-8"%> 
<%@page import="demo.jbpm.AskForLeave"%> 
<% 
request.setCharacterEncoding("UTF-8"); 
String result = "成功"; 
try { 
    AskForLeave.apply(request); 
} 
catch(Exception e) { 
    result = "失败"; 
    e.printStackTrace(); 
} 
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>apply</title> 
</head> 
<body> 
<%=result %> 
</body> 
</html>

    askForLeave/managerWorkList.jsp(用于显示经理的工作列表,需要第三个运行):
<%@ page language="java" contentType="text/html; charset=UTF-8" 
    pageEncoding="UTF-8"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<%@page import="demo.jbpm.AskForLeave"%> 
<%@page import="java.util.List"%> 
<%@page import="java.util.Map"%> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>apply</title> 
</head> 
<body> 
<% 
List<Map> workList = AskForLeave.getManagerWorkList(); 
%> 
<table border="1"> 
  <tr> 
    <td>工作名称</td> 
    <td>工作任务</td> 
    <td>处理</td> 
    <td>流程图</td> 
  </tr> 
  <%for(int i=0;i<workList.size();i++){ %> 
  <tr> 
    <td><%=workList.get(i).get("wfName") %></td> 
    <td><%=workList.get(i).get("taskName") %></td> 
    <td><a href="approval.jsp?wfId=<%=workList.get(i).get("wfId")%>&taskId=<%=workList.get(i).get("taskId")%>">处理</a></td> 
    <td><a href="viewWfGraph.jsp?wfId=<%=workList.get(i).get("wfId")%>&wfFileName=askForLeave.png">查看</a></td> 
  </tr> 
  <%} %> 
</table> 
</body> 
</html>
    askForLeave/approval.jsp(用于经理审批):
<%@<page<language="java"<contentType="text/html;<charset=UTF-8" 
<<<<pageEncoding="UTF-8"%> 
<!DOCTYPE<html<PUBLIC<"-//W3C//DTD<HTML<4.01<Transitional//EN"<"http://www.w3.org/TR/html4/loose.dtd"> 
<%@page<import="demo.jbpm.AskForLeave"%> 
<%@page<import="java.util.Map"%> 
<html> 
<head> 
<meta<http-equiv="Content-Type"<content="text/html;<charset=UTF-8"> 
<title>apply</title> 
<script<language="javascript"> 
function<go(is_passed) 
{ 
<<document.getElementById("is_passed").value<=<is_passed; 
<<document.getElementById("form1").submit(); 
} 
</script> 
</head> 
<body> 
<% 
String<taskId=request.getParameter("taskId"); 
String<id<=<AskForLeave.getBizId(taskId); 
Map<formData<=<AskForLeave.getById(id); 
%> 
<form<id="form1"<name="form1"<method="POST"<action="approval_result.jsp"> 
<input<type="hidden"<name="biz_id"<value="<%=id<%>"/> 
<input<type="hidden"<name="taskId"<value="<%=taskId<%>"/> 
<input<type="hidden"<id="is_passed"<name="is_passed"<value=""/> 
申请人:<%=formData.get("apply_user")<%><br/> 
假期开始时间:<%=formData.get("begin_leave_time")<%><br/> 
假期结束时间:<%=formData.get("end_leave_time")<%><br/> 
请假理由:<%=formData.get("leave_reason")<%><br/> 
审批意见:<input<type="text"<name="approve_remark"<value=""/><br/> 
<input<type="button"<value="同意"<onclick="go(1)"/>  <input<type="button"<value="拒绝"<onclick="go(2)"/><br/> 
</form> 
</body> 
</html>
    askForLeave/approval_result.jsp(用于响应approval.jsp):
<%@ page language="java" contentType="text/html; charset=UTF-8" 
    pageEncoding="UTF-8"%> 
<%@page import="demo.jbpm.AskForLeave"%> 
<% 
request.setCharacterEncoding("UTF-8"); 
String result = "成功"; 
try { 
    AskForLeave.approval(request); 
} 
catch(Exception e) { 
    result = "失败"; 
    e.printStackTrace(); 
} 
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>apply</title> 
</head> 
<body> 
<%=result %> 
</body> 
</html>

    askForLeave/employeeWorkList.jsp(用于显示员工工作列表,需要第四个运行):
<%@ page language="java" contentType="text/html; charset=UTF-8" 
    pageEncoding="UTF-8"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<%@page import="demo.jbpm.AskForLeave"%> 
<%@page import="java.util.List"%> 
<%@page import="java.util.Map"%> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>apply</title> 
</head> 
<body> 
<% 
List<Map> workList = AskForLeave.getEmployeeWorkList(); 
%> 
<table border="1"> 
  <tr> 
    <td>工作名称</td> 
    <td>业务id</td> 
    <td>处理</td> 
    <td>流程图</td> 
  </tr> 
  <%for(int i=0;i<workList.size();i++){ %> 
  <tr> 
    <% 
    List<Map> actions = (List<Map>) workList.get(i).get("actions");  
    %> 
    <td><%=workList.get(i).get("wfName") %></td> 
    <td><%=workList.get(i).get("biz_id") %></td> 
    <td> 
    <a href="leave_result.jsp?biz_id=<%=workList.get(i).get("biz_id") %>&wfId=<%=workList.get(i).get("wfId") %>&taskId=<%=workList.get(i).get("taskId") %>"><%=workList.get(i).get("taskName") %></a> 
    </td> 
    <td><a href="viewWfGraph.jsp?wfId=<%=workList.get(i).get("wfId")%>&wfFileName=askForLeave.png">查看</a></td> 
  </tr> 
  <%} %> 
</table> 
</body> 
</html>
    askForLeave/leave_result.jsp(用于员工处理后续事务):
<%@ page language="java" contentType="text/html; charset=UTF-8" 
    pageEncoding="UTF-8"%> 
<%@page import="demo.jbpm.AskForLeave"%> 
<% 
request.setCharacterEncoding("UTF-8"); 
String result = "成功"; 
try { 
    AskForLeave.leave(request); 
} 
catch(Exception e) { 
    result = "失败"; 
    e.printStackTrace(); 
} 
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>apply</title> 
</head> 
<body> 
<%=result %> 
</body> 
</html>

    8、增加图形显示流程状态。
    此处采用OSWorkflow的做法,把OSWorkflow中的wz_jsgraphics.js放到应用的js目录下。
    建立askForLeave/viewWfGraph.jsp:
<%@ page import="java.util.List" %> 
<%@page import="demo.jbpm.JBPMUtil"%> 
<%@page import="demo.jbpm.AskForLeave"%> 
<%@page import="org.jbpm.api.model.ActivityCoordinates"%> 
<% 
String wfId = request.getParameter("wfId"); 
String wfFileName = request.getParameter("wfFileName"); 
List<ActivityCoordinates> coors = AskForLeave.getActiveActivityCoordinates(wfId); 
%>

<div id="workflowCanvas" style="position:relative;height:566px;width:508px;"> 
<img src="<%=wfFileName %>" border=0/> 
</div> 
<script type="text/javascript" src="../js/wz_jsgraphics.js"></script>

<script type="text/javascript"> 
var jg = new jsGraphics("workflowCanvas"); 
jg.setColor("#ff0000"); 
jg.setStroke(3); 
var xAdjust = 4; 
var yAdjust = 4; 
var widthAdjust = -10; 
var heightAdjust = -10; 
<%for (ActivityCoordinates coor : coors) {%> 
jg.drawRect(parseInt("<%=coor.getX()%>") + xAdjust, parseInt("<%=coor.getY()%>") + yAdjust, parseInt("<%=coor.getWidth()%>") + widthAdjust, parseInt("<%=coor.getHeight()%>") + heightAdjust); 
<%}%> 
jg.paint();

</script>

    这样就做完了,运行应用程序,就可以看到效果了。值得一提的是,图形化显示流程状态的效果,如下:
 
流程效果图

java 工作流的更多相关文章

  1. java工作流软件发送邮件的方案

    利用javamail的功能将发送邮件的功能集成到java工作流系统中.javamail包提供有发送邮件的方法,设置发送人地址,收件人地址,抄送,主题,邮件服务器地址,认证用户等信息,再调用javama ...

  2. java工作流bpm开发ERP实例

    今天看了一个java工作流bpm开发ERP的例子,文章介绍:http://tech.it168.com/a2009/0507/275/000000275294_14.shtml 增加数据块 一路照做就 ...

  3. java工作流引擎Jflow流程事件和流程节点事件设置

    流程实例的引入和设置 关键词: 开源工作流引擎  Java工作流开发  .net开源工作流引擎   流程事件 工作流节点事件 应用场景: 在一些复杂的业务逻辑流程中需要在某个节点或者是流程结束后做一些 ...

  4. java工作流快速开发之授权代办的设计

    关键词:工作流快速开发平台  工作流流设计  业务流程管理 Java工作流引擎 asp.net 开源工作流  net开源工作流引擎 开源工作流系统 一.授权代办开发背景 应用需求:项目审批人出差无法及 ...

  5. Java工作流系统-驰骋BPM工作流 引擎的工作模式

    关键字:驰骋工作流引擎 流程引擎工作模式 流程中间件工作模式  工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流bpm工作流系统  java工作流主流框架  自定义工 ...

  6. Java工作流系统-CCBPM如何自动升级?

    关键词:工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流  bpm工作流系统  java工作流主流框架  自定义工作流引擎驰骋工作流引擎ccflow和jflow的升级 ...

  7. Java工作流引擎全局变量的介绍

    关键词:工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流bpm工作流系统  java工作流主流框架  自定义工作流引擎 在系统中有很多的地方需要用到表达式的地方,这些 ...

  8. Java工作流引擎-中间件模式代码集成

    关键词:工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流  bpm工作流系统  java工作流主流框架  自定义工作流引擎 表单设计器  流程设计器 前端代码集成步骤 ...

  9. Java工作流系统jflow向工作处理器传值的方法大全

    关键词:工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流 bpm工作流系统  java工作流主流框架  自定义工作流引擎 表单设计器  流程设计器 在启动开始节点时, ...

  10. Java工作流引擎表单引擎之JS表单字段输入脚本验证

    关键字: 表单设计器, 字段验证. workflow,ccform, ccBPM. 工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流bpm工作流系统  java工作流 ...

随机推荐

  1. Valgrind查找内存泄露利器

    Valgrind是一个GPL的软件,用于Linux(For x86, amd64 and ppc32)程序的内存调试和代码剖析.你可以在它的环境中运行你的程序来监视内存的使用情况,比如C 语言中的ma ...

  2. iOS开发调试技巧总结(持续更新中)

    作者:乞力马扎罗的雪  原文 对于软件开发而言,调试是必须学会的技能,重要性不言而喻.对于调试的技能,基本上是可以迁移的,也就是说你以前在其他平台上掌握的很多调试技巧,很多也是可以用在iOS开发中.不 ...

  3. C++复习14 构造函数初始化调用顺序

    1.关于构造函数初始化调用顺序的问题. 首先是父类和子类的,首先调用父类的构造函数,然后调用子类的构造函数.但是对于子类中有其他类型的数据成员的时候,会在调用该类的构造函数之前,调用其数据成员的构造函 ...

  4. 快速切题 poj 1002 487-3279 按规则处理 模拟 难度:0

    487-3279 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 247781   Accepted: 44015 Descr ...

  5. 【网络编程】inet_addr、inet_ntoa、inet_aton、inet_ntop和inet_pton区分

    先上一张图 1.把ip地址转化为用于网络传输的二进制数值 int inet_aton(const char *cp, struct in_addr *inp); inet_aton() 转换网络主机地 ...

  6. web版源码管理软件SCM-Manager安装配置

    背景 一直使用 “VisualSvn Server” 作为源码管理工具,使用一段时间之后,使用场景遇到以下问题 添加用户必需登录到服务器. 一台服务器,只能安装一个 “VisualSvn Server ...

  7. L148

    You don't know about real loss, because that only occurs when you love something more than you love ...

  8. MATROSKA 文件格式

    MATROSKA 文件格式 1.EBML (Extensible Binary Meta Language): EBML语言使用不定长整数,这种方式相对于固定长度的32位/64位字长的整数值更节约空间 ...

  9. three.js入门系列之光源

    首先创建场景来试验各种光源带来的不同效果: 一.锥形光源(聚光灯) SpotLight 接下来缩小范围(π/7): 二.基础光源(环境光) AmbientLight 上例中没有添加环境光,使得周围黑漆 ...

  10. three.js入门系列之视角和辅助线

    假设你已经创建好了three.js的开发环境(我是写在vue项目中的),那么接下来,从头开始演示是如何用three.js来构建3D图形的.(笔记本写的代码,屏幕小,所以为了能够整屏看到完整代码,就将字 ...