欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)

程序员文章站 2022-07-03 19:48:21
...

先说明这个只是一个例子而已,简单的介绍了一些写法,你真的理解了以后完全可以写出比这个更好的代码来。

 

网上随便找了个请假的流程图,在此先谢谢提供图片的人:


一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
使用jbpm工具画出流程图,中文好像是乱码,所以改为英文:

 
一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
 leave.jpdl.xml内容:

<?xml version="1.0" encoding="UTF-8"?>

<process name="leave" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="159,47,48,48" name="start1">
      <transition to="exclusive1"/>
   </start>
   <decision expr="#{job}" g="161,152,48,48" name="exclusive1">
      <transition g="42,179:43,-27" name="isChief" to="boosApprove"/>
      <transition g="316,175:-83,-23" name="isnotChief" to="chiefApprove"/>
   </decision>
   <state g="-3,220,92,52" name="boosApprove">
      <transition g="47,340:" to="sendEmail"/>
   </state>
   <state g="270,214,92,52" name="chiefApprove">
      <transition to="exclusive2"/>
   </state>
   <decision expr="#{day}" g="160,219,48,48" name="exclusive2">
      <transition g="-2,-20" name="gt10" to="boosApprove"/>
      <transition g="186,323:12,-47" name="le10" to="sendEmail"/>
   </decision>
   <end g="171,410,48,48" name="end"/>
   <state g="146,313,92,52" name="sendEmail">
      <transition to="end"/>
   </state>
	
</process>

 

分析之后,有如下一些表:

用户user_
角色role_(简化到user_)
请假单leave_
假设有这么几个用户:
陈均  --普通员工
唐平 --级别最高的,BOOS,老板
胡杰 --级别比较高的,chief主管
张小 --普通员工

用户测试数据:

INSERT INTO `user_` VALUES ('9', '陈均', '普通员工');
INSERT INTO `user_` VALUES ('10', '胡杰', '主管');
INSERT INTO `user_` VALUES ('11', '唐平', '老板');
INSERT INTO `user_` VALUES ('12', '张小', '普通员工');

 

 

现在集成jbpm4.3,hibernate3,spring2.5,struts2.1.8。

 系统初步设计如图:


一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
 

 

1.因为jbpm里面带有hibernate,所以创建web项目后,导入jbpm-4.3\lib下的所有包,导入jbpm-4.3\jbpm.jar,

把jbpm4.3\lib\下面得juel.jar,juel-engine.jar,juel-impl.jar放到tomcat的lib下面。导入spring2.5的jar,导入struts2.1.8所需jar包。以下jar包不是最简,有些不是必须的。

 

spring2.5所需jar包清单:

aspectjrt.jar

aspectjweaver.jar

cglib-nodep-2.1_3.jar

common-annotations.jar

commons-logging.jar

log4j-1.2.15.jar

spring.jar

spring-webmvc-struts.jar

------------------------------------

struts2.1.8所需jar包清单:

commons-fileupload-1.2.1.jar

commons-io-1.3.2.jar

freemarker-2.3.15.jar

ognl-2.7.3.jar

struts2-core-2.1.8.1.jar

struts2-dojo-plugin-2.1.8.1.jar

struts2-spring-plugin-2.1.8.1.jar

xwork-core-2.1.6.jar

-----------------------------------

数据库和数据源所需jar包:

c3p0-0.9.1.2.jar

mysql-connector-java-5.1.7-bin.jar

找到jbpm-4.3\install\src\cfg\jbpm\下的spring.jbpm.cfg.xml文件,放入项目的src处,改名为jbpm.cfg.xml.

 

在项目src下面创建applicationContext.xml配置文件,内容如下:

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:context="http://www.springframework.org/schema/context"
	 xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

	<!-- 开启注解配置 -->
	<context:annotation-config />
	
	<!-- 对指定的包进行组件扫描 -->
	<context:component-scan base-package="org.forever.leave" />

	<!-- 配置数据源,导入c3p0-0.9.1.2.jar,mysql-connector-java-5.1.7-bin.jar -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">
		<property name="driverClass">
			<value>com.mysql.jdbc.Driver</value>
		</property>
		<property name="jdbcUrl">
			<value>jdbc:mysql://localhost:3306/jbpmdb</value>
		</property>
		<property name="user">
			<value>root</value>
		</property>
		<property name="password">
			<value>root</value>
		</property>
	</bean>

	<!-- 集成hibernate配置 -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="hibernateProperties" ref="hibernateProperties" />
		<property name="mappingLocations">
			<list>
				<value>classpath*:org/forever/leave/entities/*.hbm.xml</value>
				<value>classpath:jbpm.repository.hbm.xml</value>   
                <!-- 以下几个jbpm.*.hbm.xml由jBPM自带 -->                   
                <value>classpath:jbpm.execution.hbm.xml</value>   
                <value>classpath:jbpm.history.hbm.xml</value>   
                <value>classpath:jbpm.task.hbm.xml</value>   
                <value>classpath:jbpm.identity.hbm.xml</value> 
			</list>
		</property>
	</bean>
	
	<bean name="hibernateProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
		<property name="properties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
			</props>
		</property>
	</bean>

	<!-- jbpm配置 -->
	<bean id="springHelper" class="org.jbpm.pvm.internal.processengine.SpringHelper" />
	<bean id="processEngine" factory-bean="springHelper"
		factory-method="createProcessEngine" />
	
	<!-- 模板配置自己写的,不是必须的 -->
	<bean id="jbpmTemplate" class="org.forever.leave.jbpm.JbpmTemplate">
		<property name="processEngine" ref="processEngine"></property>
	</bean>
	
	<!-- 数据层用的模板工具,不是必须的 -->
	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>

	<!-- 事务配置,必须 -->
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

	<!-- 切面配置 -->
	<aop:config>
		<aop:pointcut expression="execution(* org.forever.leave.biz..*.*(..))"
			id="transactionPointcut" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut" />
	</aop:config>
	<!-- 通知配置 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED" />
			<tx:method name="find*" read-only="true" propagation="NOT_SUPPORTED" />
			<tx:method name="*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>



</beans>

 

 

添加 log4j.properties文件;

模板类JbpmTemplate:

package org.forever.leave.jbpm;

import java.util.List;
import java.util.Map;

import org.jbpm.api.Execution;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.HistoryService;
import org.jbpm.api.ManagementService;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.RepositoryService;
import org.jbpm.api.TaskService;
import org.jbpm.api.task.Task;

/**
 * jbpm模板类(初步实现)
 * 
 * @author Administrator
 * 
 */
public class JbpmTemplate {

	/**
	 * 部署流程到数据库
	 * 
	 * @param resourceName
	 *            资源文件名字 比如(org/forever/jbpm/jpdl/process.jpdl.xml)
	 * @return 返回流程定义id(格式:key-version)
	 */
	public String Deploy(String resourceName) {
		return repositoryService.createDeployment().addResourceFromClasspath(
				resourceName).deploy();
	}

	/**
	 * 创建一个新的流程实例
	 * 
	 * @param processDefinitionKey
	 *            (process.jpdl.xml中process标签的key)
	 * @param processInstanceKey
	 *            (用户给的key,比如一个请假单的id)
	 * @return 流程实例
	 */
	public ProcessInstance addProcessInstance(String processDefinitionKey,
			String processInstanceKey) {
		return executionService.startProcessInstanceByKey(processDefinitionKey,
				processInstanceKey);

	}
	
	/**
	 * 创建一个新的流程实例
	 * @param processDefinitionKey(process.jpdl.xml中process标签的key)
	 * @param variables 该流程实例要用到的变量
	 * @param processInstanceKey(用户给定的业务key)
	 * @return
	 */
	public ProcessInstance addProcessInstance(
			String processDefinitionKey,
			Map<String, ?> variables,
			String processInstanceKey){
		return executionService.startProcessInstanceByKey(processDefinitionKey, variables, processInstanceKey);
	}
	
	/**
	 * 提交任务
	 * @param taskId 任务id
	 */
	public void completeTask(String taskId){
		taskService.completeTask(taskId);
	}
	
	/**
	 * 将任务流转到指定名字的流程中去
	 * @param taskId
	 * @param outcome
	 */
	public void completeTask(String taskId,String outcome){
		taskService.completeTask(taskId, outcome);
	}

	/**
	 * 根据key获取流程实例(这里我使用的uuid)
	 * 
	 * @param key
	 *            (对应于数据库表jbpm4_execution中的KEY_字段)
	 * @return 返回查找到得流程实例,没有返回null
	 */
	public ProcessInstance getProcessInstance(String key) {
		return executionService.createProcessInstanceQuery()
				.processInstanceKey(key).uniqueResult();
	}
	
	
	/**
	 * 根据executionId获取指定的变量值
	 * @param executionId
	 * @param variableName
	 * @return
	 */
	public Object getVariableByexecutionId(String executionId,String variableName){
		return executionService.getVariable(executionId, variableName);
	}
	
	
	/**
	 * 根据任务id获取指定变量值
	 * @param taskId
	 * @param variableName
	 * @return
	 */
	public Object getVariableByTaskId(String taskId,String variableName){
		return taskService.getVariable(taskId, variableName);
	}
	
	/**
	 * 获取指定用户名字的任务
	 * @param userId
	 * @return
	 */
	public List<Task> findPersonalTasks(String userId){
		return taskService.findPersonalTasks(userId);
	}
	
	/**
	 * 根据任务id获取任务
	 * @param taskId
	 * @return
	 */
	public Task getTask(String taskId) {
		return taskService.getTask(taskId);
		
	}
	
	/**
	 * 根据流程实例id获取
	 * @param executionId
	 * @return
	 */
	public Execution findExecutionById(String executionId) {
		return executionService.findExecutionById(executionId);
	}

	/**
	 * 彻底删除文件的部署
	 * 
	 * @param deploymentId流程定义id
	 */
	public void deleteDeploymentCascade(String deploymentId) {
		repositoryService.deleteDeploymentCascade(deploymentId);
	}

	public JbpmTemplate() {
		
	}

	public JbpmTemplate(ProcessEngine processEngine) {
		this.processEngine = processEngine;
		repositoryService = processEngine.getRepositoryService();
		executionService = processEngine.getExecutionService();
		taskService = processEngine.getTaskService();
		historyService = processEngine.getHistoryService();
		managementService = processEngine.getManagementService();
	}

	private ProcessEngine processEngine;
	private RepositoryService repositoryService = null;
	private ExecutionService executionService = null;
	private TaskService taskService = null;
	private HistoryService historyService = null;
	private ManagementService managementService = null;

	public ProcessEngine getProcessEngine() {
		return processEngine;
	}

	public void setProcessEngine(ProcessEngine processEngine) {
		this.processEngine = processEngine;
		System.out.println(processEngine);
		repositoryService = processEngine.getRepositoryService();
		executionService = processEngine.getExecutionService();
		taskService = processEngine.getTaskService();
		historyService = processEngine.getHistoryService();
		managementService = processEngine.getManagementService();
	}

	//省略get和set方法	

}

 

 创建测试类Test:

import java.util.UUID;

import org.forever.leave.jbpm.JbpmTemplate;
import org.jbpm.api.ProcessInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext(
				"applicationContext.xml");

		JbpmTemplate jbpmTemplate = (JbpmTemplate) context
				.getBean("jbpmTemplate");
		System.out.println(jbpmTemplate);

		jbpmTemplate.Deploy("org/forever/leave/jbpm/jpdl/leave.jpdl.xml");
		UUID uuid = UUID.randomUUID();
	}
}

 控制台输出没有报错说明jbpm和spring初步集成成功;

 访问http://localhost:8080/leave/user/queryList.action获取到用户列表信息,说明集成成功。

项目中需要修改mysql方言为org.hibernate.dialect.MySQLInnoDBDialect,事务service改为biz,刚发现的,呵呵

下一步进行业务的实现。

未完

因为朋友需要,所以对其进行了简单的实现:

在实现中发现集成的时候,如果你用mysql数据库,请设置你的方言为:org.hibernate.dialect.MySQLInnoDBDialect

先看一哈这个实现了简单业务的一个图,在此用的中文,也是网上找的,呵呵,我都变懒了哈:


一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
 

对应xml文件:

<?xml version="1.0" encoding="UTF-8"?>

<process key="leave" name="leave" xmlns="http://jbpm.org/4.3/jpdl">
   <start g="201,14,48,48" name="开始">
      <transition g="-42,-10" name="请假" to="填写请假单"/>
   </start>
   <task assignee="writerForm" g="178,87,92,52" name="填写请假单">
      <transition g="-97,2" name="判断是不是经理" to="是不是经理"/>
   </task>
   <decision expr="#{manager}" g="204,158,48,48" name="是不是经理">
      <transition g="-23,-11" name="否" to="经理审核"/>
      <transition g="14,-11" name="是" to="老板审批"/>
   </decision>
   <task assignee="#{username}" g="103,252,92,52" name="经理审核">
      <transition g="150,450:10,-21" name="经理批准" to="结束"/>
      <transition g="-22,-22" name="请假天数>5" to="老板审批"/>
      <transition g="-61,-1" name="经理不批准" to="终止"/>
      <transition g="149,114:-55,82" name="经理驳回" to="填写请假单"/>
   </task>
   
   <!-- 这里只有一个老板,所以写死了,如果有多个老板,写法同上,业务就会改变 -->
   <task assignee="张杰" g="278,251,92,52" name="老板审批">
      <transition g="326,450:-58,-24" name="老板批准" to="结束"/>
      <transition g="7,0" name="老板不批准" to="终止"/>
      <transition g="323,114:13,61" name="老板驳回" to="填写请假单"/>
   </task>
   <end g="219,429,48,48" name="结束" state="confirm"/>
   <end g="220,360,48,48" name="终止" state="dissent"/>
</process>

 写了个经理审批的测试类过程:

package org.forever.leave.biz.test;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.forever.leave.entities.Leave;
import org.forever.leave.entities.User;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.task.Task;
import org.junit.Test;

//请假测试
//运行顺序
//testDeploy()
//testCresteLeave()
//testStart()
//testGetTask()
//testGetLeave()
public class LeaveTest extends BaseTest{
	
	//部署流程
	@Test
	public void testDeploy(){
		String resourceName ="org/forever/leave/jbpm/jpdl/leave.jpdl.xml"; 
		jbpmTemplate.Deploy(resourceName);
		
	}
	
	//新建请假单
	@Test
	public void testCresteLeave(){
		
		//现假设用户陈均登陆了系统,然后进行请假
		String loginName = "cj";//登陆者
		String password = "cj";//登陆密码
		User user = userDao.get(loginName,password);
		//status=新建,就是未提交的
		UUID uuid = UUID.randomUUID();
		Leave leave = new Leave(user, 3,new Date(),"新建", "生病了");
		leave.setLeaveId(uuid.toString());
		//保存到数据库
		leaveDao.save(leave);
	}
	
	// 启动流程实例,提交请假申请
	//注意(如果要对该测试类成功测试,首先确保存在juel-engine.jar,juel-impl.jar,juel.jar)
	//部署到tomcat里面的时候就把juel.jar,juel-engine.jar,juel-impl.jar放到tomcat的lib下面
	@Test
	public void testStart() {
		//进行业务流转所需的变量
		String loginName = "cj";//登陆者
		String password = "cj";//登陆密码
		User user = userDao.get(loginName,password);
		// 3.启动流程实例,绑定业务key,key最好是唯一的
		List<?> list = leaveDao.findByUserLeave(user.getUserId());//该用户可能有多次请假的记录
		//假设用户选择的是index=0的那个请假单
		Leave leave = (Leave)list.get(0);
		
		
		String position = user.getPosition();//用户的职位
		Map<String, Object> variables = new HashMap<String, Object>();//流程中要用到的变量信息
		
		variables.put("leaveId",leave.getLeaveId());//存放该实例的请假单
		
		if("员工".equals(position)){//如果是员工请假
			variables.put("manager", "否");
			variables.put("username","胡杰");//指定一个经理进行审批
			
		}else if("经理".equals(position)){//如果是经理请假
			variables.put("manager", "是");
			//只有一个boos,所以在xml中指定了,在此就不用指定了
		}
		//此时就获取到了该请假单的id
		//通过该leaveId来绑定一个流程实例
		ProcessInstance processInstance = jbpmTemplate.addProcessInstance("leave",variables, leave.getLeaveId());
		//该表单到时候是在web页面进行申请时填写好的
		System.out.println("请假单已填写:" + processInstance.isActive("填写请假单"));
		
		String taskId = jbpmTemplate.findPersonalTasks("writerForm").get(0).getId();
		//让任务向下流转,提交任务
		jbpmTemplate.completeTask(taskId);
		
	}
	
	//获取任务集合
	@Test
	public void testGetTask(){
		//经理登陆系统,获取审批任务
		String username = "胡杰";
		List<Leave> leaves = new ArrayList<Leave>();//该经理可能对多个请假单审批,该集合提供给页面使用的
		List<Task> list = jbpmTemplate.findPersonalTasks(username);
		if(list.size()==0){
			System.out.println(username + "没有任务.........");
		}
		else{
			for (Task task : list) {
				System.out.println("任务名字:" + task.getName());
				System.out.println("任务参与者:" + task.getAssignee());
				String taskId = task.getId();
				String leaveId = (String) jbpmTemplate.getVariableByTaskId(taskId, "leaveId");
				Leave leave = leaveDao.findbyIdLeave(leaveId);
				leave.setTaskId(taskId);
				leaves.add(leave);
			}
		}
		
		//页面显示,并全部通过审批
		for (Leave leave : leaves) {
			System.out.println(leave);
			//批准流程
			ProcessInstance processInstance = jbpmTemplate.getProcessInstance(leave.getLeaveId());
			String taskId = leave.getTaskId();
			int day = leave.getDay();//请假天数
			if(day>5 && true){//如果大于5天,并且经理批准,也要提交给boos审核
				jbpmTemplate.completeTask(taskId, "请假天数>5");
			}else{//直接通过,既让任务流转到结束
				jbpmTemplate.completeTask(taskId,"经理批准");
			}
			System.out.println("审批结果:" + processInstance.getState());
			leave.setStatus("通过");
			leaveDao.update(leave);//更新结果
		}
		
		
	}
	
	//获取指定用户的请假单集合
	@Test
	public void testGetLeave(){
		//进行业务流转所需的变量
		String loginName = "cj";//登陆者
		String password = "cj";//登陆密码
		User user = userDao.get(loginName,password);
		//页面显示用
		List<?> list = leaveDao.findByUserLeave(user.getUserId());
		for (Object object : list) {
			System.out.println(object);
			//是否已经申请
			//已经提交的请假单不能进行删除操作(所以慎重,呵呵)
			//新建状态的请假单可以进行删除操作
		}
		
	}
	
}

 web版的我截几个效果图,具体过程你们下载来感受吧:

login.jsp登陆页面http://localhost:90/leave/login.jsp:第一次需要部署一哈


一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
 普通员工登陆用户名和密码为cj:


一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
 经理用户名和密码为hj,登陆后如图:



一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
 
 老板的用户名和密码zxp,进去后如图:


一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3)
 项目里面带有数据库脚本。jar自己加哈,有什么问题,欢迎交流