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. centos6/7安装 tinyproxy (yum安装)

    centos6/7安装tinyproxy(yum安装)2016年06月06日 运维 暂无评论 阅读 790 次centos7安装tinyproxy,centos6安装tinyproxy,centos6 ...

  2. DB2 设置最大连接数

    db2 connect to dbname user username using passwd db2 update db cfg using MAXAPPLS number 查看最大连接数 查看D ...

  3. 【WPF】影城POS的前世今生

    前言 POS从16年底开始设计到现在都过去快两年了,这里我做一个简单的回顾. 技术选型 NativeUI:性能最高,开发难度最大,代表产品QQ和微信,没有基因没有技术栈. Electron+H5:不支 ...

  4. LeetCode OJ:Jump Game II(跳跃游戏2)

    Given an array of non-negative integers, you are initially positioned at the first index of the arra ...

  5. Python中字符的练习

    一.重复的单词:此处认为分隔符为空格:个整数-]): list.append(random.randint(, ))for i in list: d[i]=list.count(i)print d

  6. 做网站用UTF-8还是GB2312?

    经常我们打开外国网站的时候出现乱码,又或者打开很多非英语的外国网站的时候,显示的都是口口口口口的字符, WordPress程序是用的UTF-8,很多cms用的是GB2312. ● 为什么有这么多编码? ...

  7. css引用第三方字体库

    对应的CSS文件中如下方式进行字体库的引用: @font-face { font-family: '造字工房情书'; src: url('../fonts/MFQingShu_Noncommercia ...

  8. react中路由的跳转

    1.react-router-dom 使用react-router-dom 4.4.2 在页面中直接使用 引入 i mport { Link } from 'react-router-dom' 使用 ...

  9. Springboot项目搭配ELK日志平台

    上一篇讲过了elasticsearch和kibana的可视化组合查询,这一篇就来看看大名鼎鼎的ELK日志平台是如何搞定的. elasticsearch负责数据的存储和检索,kibana提供图形界面便于 ...

  10. Unity内存优化技术测试案例

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...