SSM框架中整一个工作流WorkFlow

  工作流直译就是工作的流程,但是怎样设计与实现并应用到程序中还是有一些难度,不然为什么有些公司可以靠工作流起家呢?其中大量的逻辑充斥其中,稍不注意就会出错。

  本次在Eclipse中使用了Activity插件,方便使用。

  1.首先引入工作流相关的pom包,由于其中会有冲突,我将所有的都贴出来:

  

<properties>
		<c3p0.version>0.9.1.2</c3p0.version>
		<!-- spring版本号 -->
		<spring.version>4.1.9.RELEASE</spring.version>
		<!-- mybatis版本号 -->
		<mybatis.version>3.2.6</mybatis.version>
		<!-- log4j日志文件管理包版本 -->
		<slf4j.version>1.7.7</slf4j.version>
		<log4j.version>1.2.17</log4j.version>
		<cxf.version>2.2.3</cxf.version>
		<activti.engine.version>6.0.0</activti.engine.version>
	</properties>

	<dependencies>
		<!-- c3p0 -->
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>${c3p0.version}</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<!-- 表示开发的时候引入,发布的时候不会加载此包 -->
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.2.5</version>
			<exclusions>
				<exclusion>
					<groupId>org.ow2.asm</groupId>
					<artifactId>asm</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<!-- spring核心包 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>


		<!-- spring mvc aop -->
		<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.5.3</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.4</version>
		</dependency>
		<dependency>
			<groupId>aopalliance</groupId>
			<artifactId>aopalliance</artifactId>
			<version>1.0</version>
		</dependency>
		<!-- mybatis核心包 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.1</version>
		</dependency>
		<!-- mybatis/spring包 -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!-- 导入java ee jar 包 -->
		<dependency>
			<groupId>javax</groupId>
			<artifactId>javaee-api</artifactId>
			<version>7.0</version>
			<scope>provided</scope>
		</dependency>
		<!-- 导入Mysql数据库链接jar包 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.30</version>
		</dependency>
		<!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.2</version>
		</dependency>
		<!-- JSTL标签类 -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!-- 日志文件管理包 -->
		<!-- log start -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>


		<!-- 格式化对象,方便输出日志 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.1.41</version>
		</dependency>


		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<!-- log end -->
		<!-- 映入JSON -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.9.13</version>
		</dependency>
		<!-- 上传组件包 -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.9</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>2.1.0</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.1.0</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-annotations</artifactId>
			<version>2.1.0</version>
		</dependency>
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
			<version>2.4.3</version>
			<type>pom</type>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>5.2.10.Final</version>
		</dependency>
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper</artifactId>
			<version>4.1.4</version>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.8.1</version>
		</dependency>
		<!-- webservice -->
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-frontend-jaxws</artifactId>
			<version>${cxf.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http</artifactId>
			<version>${cxf.version}</version>
		</dependency>

		<!-- 工作流 -->
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-engine</artifactId>
			<version>${activti.engine.version}</version>
			<exclusions>
				<exclusion>
					<groupId>de.odysseus.juel</groupId>
					<artifactId>juel-spi</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-spring</artifactId>
			<version>${activti.engine.version}</version>
		</dependency>
  



	</dependencies>

  2. 写入相关的jdbc.propertiesspring-mvc-activiti.xml

#this properties -- spring-mybatis.xml&config.xml ,so some properties are distinct.
mysql.driverclass=com.mysql.jdbc.Driver
mysql.jdbcurl=jdbc:mysql://localhost:3306/repairsystem?characterEncoding=utf-8
mysql.user=root
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/repairsystem?useUnicode=true&characterEncoding=utf-8
mysql.username=root
mysql.password=123456
mysql.initialSize=0  
mysql.maxActive=20  
mysql.maxIdle=20  
mysql.minIdle=1
mysql.maxWait=60000

 
jdbc.activiti.driverClass=com.mysql.jdbc.Driver
jdbc.activiti.jdbcUrl=jdbc:mysql://localhost:3306/activitidb?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
jdbc.activiti.user=root
jdbc.activiti.password=123456
 
# basic confog
jdbc.minPoolSize=10
jdbc.maxPoolSize=10
jdbc.initialPoolSize=5
jdbc.acquireIncrement=5
 
# manage connection config
jdbc.maxIdleTime=1800
jdbc.maxConnectionAge=7200
jdbc.maxIdleTimeExcessConnections=0
 
# connection test config, timeunit second
jdbc.idleConnectionTestPeriod=600
jdbc.testConnectionOnCheckin=true
jdbc.testConnectionOnCheckout=false
jdbc.preferredTestQuery=SELECT 1 FROM DUAL
 
# recovery from database outages config, timeunit millisecond
jdbc.acquireRetryAttempts=5
jdbc.acquireRetryDelay=1000
jdbc.breakAfterAcquireFailure=false
 
# statement pool config TODO
jdbc.maxStatements=0
jdbc.maxStatementsPerConnection=0
jdbc.statementCacheNumDeferredCloseThreads=0
 
# connection leak config
jdbc.debugUnreturnedConnectionStackTraces=false
jdbc.unreturnedConnectionTimeout=0
 
# other config
jdbc.checkoutTimeout=10000
jdbc.numHelperThreads=3

  

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans  
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
                        http://www.springframework.org/schema/context  
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd">

  
	<context:property-placeholder location="classpath*:jdbc.properties" ignore-unresolvable="false" />
 
    <bean id="transactionManager_activiti" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource_activiti"></property>
    </bean>
    <!-- activiti datasource -->
    <bean id="dataSource_activiti" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.activiti.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.activiti.jdbcUrl}"/>
        <property name="user" value="${jdbc.activiti.user}"/>
        <property name="password" value="${jdbc.activiti.password}"/>
 
        <property name="minPoolSize" value="${jdbc.minPoolSize}"/>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
        <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
        <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
 
        <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
        <property name="maxConnectionAge" value="${jdbc.maxConnectionAge}"/>
        <property name="maxIdleTimeExcessConnections" value="${jdbc.maxIdleTimeExcessConnections}"/>
 
        <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
        <property name="testConnectionOnCheckin" value="${jdbc.testConnectionOnCheckin}"/>
        <property name="testConnectionOnCheckout" value="${jdbc.testConnectionOnCheckout}"/>
        <property name="preferredTestQuery" value="${jdbc.preferredTestQuery}"/>
 
        <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/>
        <property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}"/>
 
        <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/>
        <property name="numHelperThreads" value="${jdbc.numHelperThreads}"/>
    </bean>
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource_activiti"/>
        <property name="transactionManager" ref="transactionManager_activiti"/>
        <property name="databaseSchemaUpdate" value="true"/>
        <property name="asyncExecutorActivate" value="true"/>
        <property name="deploymentResources" value="classpath*:activiti/*.bpmn"/> 
      <!--   <property name="jobExecutorActivate" value="false" />   -->
        <property name="activityFontName" value="宋体"/>  
        <property name="labelFontName" value="宋体"/>
        <property name="annotationFontName" value="宋体"/>  

        <!-- mail -->
        <property name="mailServerHost" value="localhost"/>
        <property name="mailServerUsername" value="kafeitu"/>
        <property name="mailServerPassword" value="000000"/>
        <property name="mailServerPort" value="2025"/>



        <!-- 缓存支持
        <property name="processDefinitionCache">
            <bean class="me.kafeitu.demo.activiti.util.cache.DistributedCache" />
        </property>-->

        

        <!-- 自定义表单字段类型 -->
        <property name="customFormTypes">
            <list>
<!--                 <bean class="me.kafeitu.demo.activiti.activiti.form.UsersFormType"/> -->
            </list>
        </property>

        <!-- JPA -->
<!--         <property name="jpaEntityManagerFactory" ref="entityManagerFactory" /> -->
<!--         <property name="jpaHandleTransaction" value="false" /> -->
<!--         <property name="jpaCloseEntityManager" value="false" /> -->

        <!-- 全局事件 -->
        <property name="typedEventListeners">
            <map>
                <entry key="VARIABLE_CREATED" >
                    <list>
<!--                         <ref bean="variableCreateListener"/> -->
                    </list>
                </entry>
            </map>
        </property>
    </bean>
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>
    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
    <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
    <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
    <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
    <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService"/>
    <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
 
</beans>

  3. 准备工作中还需要添加一个activitiDB数据库,这个好像是activiti自带可以生成的。

package clack.activity;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.junit.Test;

public class GenDB {

	public void createActivitiEngineByCode() {

		/*
		 * *1.通过代码形式创建 - 取得ProcessEngineConfiguration对象 - 设置数据库连接属性 - 设置创建表的策略
		 * (当没有表时,自动创建表) - 通过ProcessEngineConfiguration对象创建 ProcessEngine 对象
		 */

		// 取得ProcessEngineConfiguration对象
		ProcessEngineConfiguration engineConfiguration = ProcessEngineConfiguration
				.createStandaloneProcessEngineConfiguration();
		// 设置数据库连接属性
		engineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
		engineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activitiDB?createDatabaseIfNotExist=true"
				+ "&useUnicode=true&characterEncoding=utf8");
		engineConfiguration.setJdbcUsername("root");
		engineConfiguration.setJdbcPassword("123456");

		// 设置创建表的策略 (当没有表时,自动创建表)
		// public static final java.lang.String DB_SCHEMA_UPDATE_FALSE =
		// "false";//不会自动创建表,没有表,则抛异常
		// public static final java.lang.String DB_SCHEMA_UPDATE_CREATE_DROP =
		// "create-drop";//先删除,再创建表
		// public static final java.lang.String DB_SCHEMA_UPDATE_TRUE =
		// "true";//假如没有表,则自动创建
		engineConfiguration.setDatabaseSchemaUpdate("true");
		// 通过ProcessEngineConfiguration对象创建 ProcessEngine 对象
		ProcessEngine processEngine = engineConfiguration.buildProcessEngine();
		System.out.println("流程引擎创建成功!");
	}

	public void createActivitiEngine() {
		ProcessEngineConfiguration engineConfiguration = ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource("spring-context-activiti.xml");
		// 从类加载路径中查找资源 activiti.cfg.xm文件名可以自定义
		ProcessEngine processEngine = engineConfiguration.buildProcessEngine();
		System.out.println("使用配置文件Activiti.cfg.xml获取流程引擎");
	}

	public static void main(String[] args) {
		new GenDB().createActivitiEngineByCode();
	}
}

  4. 接着在activiti视图中创建一张自定义的流程图,并添加相应的监听类,用xml编辑器打开如下:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="apply" name="apply" isExecutable="true">
    <startEvent id="startevent1" name="Start" activiti:initiator="userId">
      <extensionElements>
        <activiti:executionListener event="start" class="clack.activity.listener.MyExecutionListener"></activiti:executionListener>
      </extensionElements>
    </startEvent>
    <userTask id="usertask1" name="组长审批" activiti:assignee="${userId}" xmlns:activiti="http://activiti.org/bpmn" activiti:class="clack.activity.task.TeamApplyServiceTask"></userTask>
    <userTask id="usertask2" name="经理审批" activiti:assignee="${userId}" xmlns:activiti="http://activiti.org/bpmn" activiti:class="clack.activity.task.ManagerApplyServiceTask"></userTask>
    <serviceTask id="servicetask1" name="人事归档" activiti:class="clack.activity.task.HumanResouceServiceTask"></serviceTask>
    <endEvent id="endevent1" name="End">
      <extensionElements>
        <activiti:executionListener event="start" class="clack.activity.listener.MyExecutionListener"></activiti:executionListener>
      </extensionElements>
    </endEvent>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow4" sourceRef="servicetask1" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_apply">
    <bpmndi:BPMNPlane bpmnElement="apply" id="BPMNPlane_apply">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="270.0" y="260.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="410.0" y="250.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="650.0" y="250.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="servicetask1" id="BPMNShape_servicetask1">
        <omgdc:Bounds height="55.0" width="105.0" x="880.0" y="250.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="1100.0" y="260.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="305.0" y="277.0"></omgdi:waypoint>
        <omgdi:waypoint x="410.0" y="277.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="515.0" y="277.0"></omgdi:waypoint>
        <omgdi:waypoint x="650.0" y="277.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="755.0" y="277.0"></omgdi:waypoint>
        <omgdi:waypoint x="880.0" y="277.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="985.0" y="277.0"></omgdi:waypoint>
        <omgdi:waypoint x="1100.0" y="277.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

    其中对应的一些监听类及任务类如下:

  

package clack.activity.listener;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/**
 *@description		executionListern主要用于流程的开始、结束和连线的监听
 *					共有三个值:"start"、"end"、"take"。
 *					其中start和end用于整个流程的开始和结束,take用于连线
 *@auth panmingshuai
 *@time 2018年4月5日下午8:59:16
 * 
 */
public class MyExecutionListener implements ExecutionListener{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void notify(DelegateExecution execution){
		//得到现在事件阶段的值,用"start".endsWith(eventName)来判断
		String eventName = execution.getEventName();
		if("start".endsWith(eventName)){
			System.out.println("-------------------流程开始-------------------");
		} else if("end".equals(eventName)){
			System.out.println("-------------------流程结束-------------------");
		}
		
		
		
	}
}

  

package clack.activity.task;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

public class TeamApplyServiceTask implements JavaDelegate {


	@Override
	public void execute(DelegateExecution execution) {
		// TODO Auto-generated method stub

	}

}

  

package clack.activity.task;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

public class ManagerApplyServiceTask implements JavaDelegate {


	@Override
	public void execute(DelegateExecution execution) {
		// TODO Auto-generated method stub
//		String eventName = execution.getEventName();
//		if("start".endsWith(eventName)){
//			System.out.println("-------------------流程开始-------------------");
//		} else if("end".equals(eventName)){
//			System.out.println("-------------------流程结束-------------------");
//		}
	}

}

  

package clack.activity.task;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

public class HumanResouceServiceTask implements JavaDelegate {


	@Override
	public void execute(DelegateExecution execution) {
		// TODO Auto-generated method stub

	}


}

    5. 接着处理部署方法,由于在一个流程中仅需要部署一次(部署多次没有意义),所以需要将部署方法剥离出来放到监听器中,在运行了一次后将其注释掉,相关的初始部署方法、监听器方法、以及web.xml中的改动如下:

package clack.init;

import java.io.File;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

public class ActivityInit {
	public static ProcessEngine processEngine;
	// 得到流程存储服务实例
	public static RepositoryService repositoryService;
	// 得到运行时服务组件
	public static RuntimeService runtimeService;
	// 得到历史服务组件
	public static HistoryService historyService;
	// 用户 分组信息服务 可以不使用
	public static IdentityService identityService;

	public static TaskService taskService;
	static {

		// ProcessEngineConfiguration engineConfiguration =
		// ProcessEngineConfiguration
		// .createProcessEngineConfigurationFromResource("spring-context-activiti.xml");

		ProcessEngineConfiguration engineConfiguration = ProcessEngineConfiguration
				.createStandaloneProcessEngineConfiguration();
		// 设置数据库连接属性
		engineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
		engineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activitiDB?createDatabaseIfNotExist=true"
				+ "&useUnicode=true&characterEncoding=utf8");
		engineConfiguration.setJdbcUsername("root");
		engineConfiguration.setJdbcPassword("123456");
		engineConfiguration.setActivityFontName("宋体");
		engineConfiguration.setAnnotationFontName("宋体");
		engineConfiguration.setLabelFontName("宋体");
		engineConfiguration.setDatabaseSchemaUpdate("true");

		// 通过ProcessEngineConfiguration对象创建 ProcessEngine 对象

		processEngine = engineConfiguration.buildProcessEngine();
		// 仓储服务
		repositoryService = processEngine.getRepositoryService();
		// 得到运行时服务组件
		runtimeService = processEngine.getRuntimeService();
		// 得到历史服务组件
		historyService = processEngine.getHistoryService();

		identityService = processEngine.getIdentityService();

		taskService = processEngine.getTaskService();

	}

	// 1.参考模板 启动流程 会写入相关数据库,key为自定义编号
	public static Deployment deployeeProcess(String bpmnName, String key) {
		// 指定执行我们刚才部署的工作流程
		// RepositoryService repositoryService =
		// processEngine.getRepositoryService();
		Deployment deployment = repositoryService.createDeployment()// 创建一个部署的构建器
				.addClasspathResource("clack/activity/" + bpmnName + ".bpmn")// 从类路径中添加资源,一次只能添加一个资源
				.name("项目审批")// 设置部署的名称
				.category("审批类别")// 设置部署的类别
				.key(key).deploy();
		org.springframework.web.context.ContextLoaderListener xx;
		System.out.println("部署的id" + deployment.getId());
		System.out.println("部署的名称" + deployment.getName());
		return deployment;
	}

}

  

package clack.activity.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import clack.init.ActivityInit;



public class ApplyListener implements ServletContextListener {
	 
	//1.静态的启动部分放在init中,该方法用于部署工作流,目前仅需要启动服务时配置一次,所以
	//只需要第一次启动时加载ApplyListener中的类,过后注释掉。
	@Override
	public void contextInitialized(ServletContextEvent sce) {
		// TODO Auto-generated method stub
		//ActivityInit.deployeeProcess("apply", "user001");
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		// TODO Auto-generated method stub

	}

}

  

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
    id="WebApp_ID" version="3.1">
    <display-name>Archetype Created Web Application</display-name>
    
    <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-context*.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
	</listener>
    
	<listener>
		<listener-class>clack.activity.listener.ApplyListener</listener-class>
	</listener>
<!--注意,由于activiti.xml应该在springmvc中启动,所以已经改名让SpringMVC访问读取-->

  6. 然后就是Controller层与JSP页面的交互,大量的逻辑就是在这个文件中,里面还包含了同时将流程图例绘制到服务器上和本地磁盘上,耗时耗力,并在处理activiti数据库中不同的ID之间的对应与取值浪费了许多时间,

package clack.controller;

import java.io.File;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/apply")
public class ActivityController {
	private String savePath = "activity";

	public String getSavePath() {
		return savePath;
	}

	public void setSavePath(String savePath) {
		this.savePath = savePath;
	}

	@Autowired
	public ProcessEngine processEngine;
	// 得到流程存储服务实例
	@Autowired
	public RepositoryService repositoryService;
	// 得到运行时服务组件
	@Autowired
	public RuntimeService runtimeService;
	// 得到历史服务组件
	@Autowired
	public HistoryService historyService;
	// 用户 分组信息服务 可以不使用
	@Autowired
	public IdentityService identityService;
	@Autowired
	public TaskService taskService;
	// static {
	//
	// // ProcessEngineConfiguration engineConfiguration =
	// // ProcessEngineConfiguration
	// //
	// .createProcessEngineConfigurationFromResource("spring-context-activiti.xml");
	//
	// ProcessEngineConfiguration engineConfiguration =
	// ProcessEngineConfiguration
	// .createStandaloneProcessEngineConfiguration();
	// // 设置数据库连接属性
	// engineConfiguration.setJdbcDriver("com.mysql.jdbc.Driver");
	// engineConfiguration.setJdbcUrl("jdbc:mysql://localhost:3306/activitiDB?createDatabaseIfNotExist=true"
	// + "&useUnicode=true&characterEncoding=utf8");
	// engineConfiguration.setJdbcUsername("root");
	// engineConfiguration.setJdbcPassword("root");
	// engineConfiguration.setActivityFontName("宋体");
	// engineConfiguration.setAnnotationFontName("宋体");
	// engineConfiguration.setLabelFontName("宋体");
	// engineConfiguration.setDatabaseSchemaUpdate("true");
	//
	// // 通过ProcessEngineConfiguration对象创建 ProcessEngine 对象
	//
	// processEngine = engineConfiguration.buildProcessEngine();
	// // 仓储服务
	// repositoryService = processEngine.getRepositoryService();
	// // 得到运行时服务组件
	// runtimeService = processEngine.getRuntimeService();
	// // 得到历史服务组件
	// historyService = processEngine.getHistoryService();
	//
	// identityService = processEngine.getIdentityService();
	//
	// taskService = processEngine.getTaskService();
	//
	// }

	// 1.参考模板 启动流程 会写入相关数据库,key为自定义编号
	//1.静态的启动部分放在init中,该方法用于部署工作流,目前仅需要启动服务时配置一次,所以
	//只需要第一次启动时加载ApplyListener中的类,过后注释掉。
	public Deployment deployeeProcess(String bpmnName, String key) {
		// 指定执行我们刚才部署的工作流程
		// RepositoryService repositoryService =
		// processEngine.getRepositoryService();
		Deployment deployment = repositoryService.createDeployment()// 创建一个部署的构建器
				.addClasspathResource("com/activity/" + bpmnName + ".bpmn")// 从类路径中添加资源,一次只能添加一个资源
				.name("项目审批")// 设置部署的名称
				.category("审批类别")// 设置部署的类别
				.key(key).deploy();
		org.springframework.web.context.ContextLoaderListener xx;
		System.out.println("部署的id" + deployment.getId());
		System.out.println("部署的名称" + deployment.getName());
		return deployment;
	}

	// 2.启动流程 写入相关数据库,processDefinitionKey 为自定义流程模板名称
	@RequestMapping(value = "/startProcess")
	@ResponseBody
	public List<String> startProcess(String appid, String businessKey, String processDefinitionKey,
			HttpServletRequest request) {
		// String processDefinitionKey = "leave";
		// 取运行时服务
		System.err.println("userId" + "  " + appid + " " + businessKey + " " + processDefinitionKey);
		// RuntimeService runtimeService = processEngine.getRuntimeService();

		Map<String, Object> variables = new HashMap<String, Object>();
		//userId为bpmn文件中xml编辑器中自定义的用户变量
		variables.put("userId", appid);

		// 设置流程启动用户
		identityService.setAuthenticatedUserId(appid);

		// 取得流程实例
		ProcessInstance pi = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);// 通过流程定义的key
		// 来执行流程

		System.out.println("流程实例id:" + pi.getId());// 流程实例id
		System.out.println("流程定义id:" + pi.getProcessDefinitionId());// 输出流程定义的id
		String imgsrc = getActivitiProccessImage(pi.getId(), request);
		System.err.println("pi:" + pi);
		//list中存放的三个值分别为服务器上的图片生成名称、流程实例的Id、以及获取流程图像
		List<String> list = new ArrayList<String>();
		list.add(imgsrc);
		list.add(pi.getId());
		//getActivitiByPiId(pi.getId());
		list.add(getActivitiByPiId(pi.getId()));
		return list;
	}

	@RequestMapping(value = "/viewImage")
	@ResponseBody
	public void viewImage(String deploymentId) throws Exception {
		// 创建仓库服务对对象
		// RepositoryService repositoryService =
		// processEngine.getRepositoryService();
		// 从仓库中找需要展示的文件

		List<String> names = repositoryService.getDeploymentResourceNames(deploymentId);
		String imageName = null;
		for (String name : names) {
			if (name.indexOf(".png") >= 0) {
				imageName = name;
			}
		}
		if (imageName != null) {
			System.out.println(imageName);
			File f = new File("d:/" + imageName);
			// 通过部署ID和文件名称得到文件的输入流
			InputStream in = repositoryService.getResourceAsStream(deploymentId, imageName);
			FileUtils.copyInputStreamToFile(in, f);
		}
	}

	public String getDeployeeIdByPid(String piInstancetId) {
		HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
				.processInstanceId(piInstancetId).singleResult();
		String deployeeId = "";
		if (historicProcessInstance == null) {
			System.out.println("未获取到");
		} else {
			// 获取流程定义

			ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
					.getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());
			String piId = processDefinition.getId();
			deployeeId = processDefinition.getDeploymentId();
		}
		return deployeeId;

	}

	/**
	 * 获取流程图像,已执行节点和流程线高亮显示
	 */
	public String getActivitiByPiId(String piInstancetId) {
		String imageName = null;
		List<String> executedActivityIdList = new ArrayList<String>();
		String newFileName = "";
		System.out.println("piInstancetId" + piInstancetId);
		// logger.info("[开始]-获取流程图图像");
		try {
			// 获取历史流程实例
			HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
					.processInstanceId(piInstancetId).singleResult();
			System.err.println("his:" + historicProcessInstance);
			if (historicProcessInstance == null) {
				// throw new BusinessException("获取流程实例ID[" + pProcessInstanceId
				// + "]对应的历史流程实例失败!");
			} else {
				// 获取流程定义
				ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
						.getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());

				// 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
				List<HistoricActivityInstance> historicActivityInstanceList = historyService
						.createHistoricActivityInstanceQuery().processInstanceId(piInstancetId)
						.orderByHistoricActivityInstanceId().asc().list();

				// 已执行的节点ID集合
				//List<String> executedActivityIdList = new ArrayList<String>();
				System.out.println("aa:" + executedActivityIdList.size());
				int index = 1;
				// logger.info("获取已经执行的节点ID");
				for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
					executedActivityIdList.add(activityInstance.getTaskId());
					System.out.println("a:"+activityInstance.getActivityId()+" "+activityInstance.getId()+" "+activityInstance.getTaskId());	
					// logger.info("第[" + index + "]个已执行节点=" +
					// activityInstance.getActivityId() + " : "
					// +activityInstance.getActivityName());
					index++;
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return executedActivityIdList.get(executedActivityIdList.size()-1);
	}

	public String getActivitiProccessImage(String piInstancetId, HttpServletRequest request) {
		String imageName = null;
		String newFileName = "";
		System.out.println("piInstancetId" + piInstancetId);
		// logger.info("[开始]-获取流程图图像");
		try {
			// 获取历史流程实例
			HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
					.processInstanceId(piInstancetId).singleResult();
			System.err.println("his:" + historicProcessInstance);
			if (historicProcessInstance == null) {
				// throw new BusinessException("获取流程实例ID[" + pProcessInstanceId
				// + "]对应的历史流程实例失败!");
			} else {
				// 获取流程定义
				ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
						.getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());

				// 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
				List<HistoricActivityInstance> historicActivityInstanceList = historyService
						.createHistoricActivityInstanceQuery().processInstanceId(piInstancetId)
						.orderByHistoricActivityInstanceId().asc().list();

				// 已执行的节点ID集合
				List<String> executedActivityIdList = new ArrayList<String>();
				System.out.println("aa:" + executedActivityIdList.size());
				int index = 1;
				// logger.info("获取已经执行的节点ID");
				for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
					executedActivityIdList.add(activityInstance.getActivityId());

					// logger.info("第[" + index + "]个已执行节点=" +
					// activityInstance.getActivityId() + " : "
					// +activityInstance.getActivityName());
					index++;
				}

				BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());

				// 已执行的线集合
				List<String> flowIds = new ArrayList<String>();
				// 获取流程走过的线 (getHighLightedFlows是下面的方法)
				flowIds = getHighLightedFlows(bpmnModel, processDefinition, historicActivityInstanceList);

				// System.out.println(flowIds.size()+" dddddddd");

				// 获取固定图像名称
				String deploymentId = getDeployeeIdByPid(piInstancetId);
				List<String> names = repositoryService.getDeploymentResourceNames(deploymentId);

				for (String name : names) {
					if (name.indexOf(".png") >= 0) {
						imageName = name;
					}
				}
				System.out.println("imageName" + imageName);
				if (imageName != null) {

					String uploadPath = request.getRealPath(getSavePath());

					System.out.println("path:" + uploadPath);

					newFileName = "" + piInstancetId + ".png";

					String path = uploadPath + "/";

					System.err.println("path:" + path);
					File fileparent = new File(path);
					if (!fileparent.exists()) {
						fileparent.mkdirs();
					}
					File img = new File(path + newFileName);
					System.out.println("img:" + img);
					File f = new File("d:/" + imageName);
					// 获取流程图图像字符流
					ProcessDiagramGenerator pec = processEngine.getProcessEngineConfiguration()
							.getProcessDiagramGenerator();
					// 配置字体
					InputStream in = pec.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds, "宋体",
							"微软雅黑", "黑体", null, 2.0);
					InputStream in1 = pec.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds, "宋体",
							"微软雅黑", "黑体", null, 2.0);
					// response.setContentType("image/png");
					// OutputStream os = response.getOutputStream();
					FileUtils.copyInputStreamToFile(in, f);
					FileUtils.copyInputStreamToFile(in1, img);
					in.close();
					in1.close();
				}

				// int bytesRead = 0;
				// byte[] buffer = new byte[8192];
				// while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1)
				// {
				// os.write(buffer, 0, bytesRead);
				// }
				// os.close();
				// imageStream.close();

				// String deploymentId = getDeployeeIdByPid(piInstancetId);
				// List<String> names =
				// repositoryService.getDeploymentResourceNames(deploymentId);
				// String imageName = null;
				// for (String name : names) {
				// if (name.indexOf(".png") >= 0) {
				// imageName = name;
				// }
				// }
				// if (imageName != null) {
				// System.out.println(imageName);
				// File f = new File("e:/" + imageName);
				// // 通过部署ID和文件名称得到文件的输入流
				// InputStream in =
				// repositoryService.getResourceAsStream(deploymentId,
				// imageName);
				// FileUtils.copyInputStreamToFile(in, f);
				// }
			}
			// logger.info("[完成]-获取流程图图像");
		} catch (Exception e) {
			System.err.println("eee:" + e.getMessage());
			// throw new BusinessException("获取流程图失败!" + e.getMessage());
		}
		System.out.println("img2" + newFileName);
		return newFileName;
	}

	public List<String> getHighLightedFlows(BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity,
			List<HistoricActivityInstance> historicActivityInstances) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 24小时制
		List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId

		for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
			// 对历史流程节点进行遍历
			// 得到节点定义的详细信息
			FlowNode activityImpl = (FlowNode) bpmnModel.getMainProcess()
					.getFlowElement(historicActivityInstances.get(i).getActivityId());

			List<FlowNode> sameStartTimeNodes = new ArrayList<FlowNode>();// 用以保存后续开始时间相同的节点
			FlowNode sameActivityImpl1 = null;

			HistoricActivityInstance activityImpl_ = historicActivityInstances.get(i);// 第一个节点
			HistoricActivityInstance activityImp2_;

			for (int k = i + 1; k <= historicActivityInstances.size() - 1; k++) {
				activityImp2_ = historicActivityInstances.get(k);// 后续第1个节点

				if (activityImpl_.getActivityType().equals("userTask")
						&& activityImp2_.getActivityType().equals("userTask")
						&& df.format(activityImpl_.getStartTime()).equals(df.format(activityImp2_.getStartTime()))) // 都是usertask,且主节点与后续节点的开始时间相同,说明不是真实的后继节点
				{

				} else {
					sameActivityImpl1 = (FlowNode) bpmnModel.getMainProcess()
							.getFlowElement(historicActivityInstances.get(k).getActivityId());// 找到紧跟在后面的一个节点
					break;
				}

			}
			sameStartTimeNodes.add(sameActivityImpl1); // 将后面第一个节点放在时间相同节点的集合里
			for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
				HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
				HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点

				if (df.format(activityImpl1.getStartTime()).equals(df.format(activityImpl2.getStartTime()))) {// 如果第一个节点和第二个节点开始时间相同保存
					FlowNode sameActivityImpl2 = (FlowNode) bpmnModel.getMainProcess()
							.getFlowElement(activityImpl2.getActivityId());
					sameStartTimeNodes.add(sameActivityImpl2);
				} else {// 有不相同跳出循环
					break;
				}
			}
			List<SequenceFlow> pvmTransitions = activityImpl.getOutgoingFlows(); // 取出节点的所有出去的线

			for (SequenceFlow pvmTransition : pvmTransitions) {// 对所有的线进行遍历
				FlowNode pvmActivityImpl = (FlowNode) bpmnModel.getMainProcess()
						.getFlowElement(pvmTransition.getTargetRef());// 如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示
				if (sameStartTimeNodes.contains(pvmActivityImpl)) {
					highFlows.add(pvmTransition.getId());
				}
			}

		}
		return highFlows;

	}

	public String getPiIdbyTid(String taskId) {
		System.err.println("taskId1:" + taskId);
		Task task = taskService.createTaskQuery() // 创建任务查询
				.taskId(taskId) // 根据任务id查询
				.singleResult();
		String piInstancetId = task.getProcessInstanceId(); // 获取流程定义id

		return piInstancetId;
	}

	@RequestMapping(value = "/completeTaskByTaskId")
	@ResponseBody
	public List<String> completeTaskByTaskId(String taskId, HttpServletRequest request) {
		System.out.println("taskId:" + taskId);
		String piInstancetId = getPiIdbyTid(taskId);
		taskService.complete(taskId);
		String img = getActivitiProccessImage(piInstancetId, request);
		System.err.println("img3" + img);
		List<String>  list=new ArrayList<String>();
		list.add(img);
		list.add(getActivitiByPiId(piInstancetId));
		return list;
	}

}

    7. 最后,添加一个简单的JSP用ajax调用Controller中的方法便大功告成。

    但是:其中最坑的一点是jsp页面读取图片(图片名称一样,只是走流程时图片发生了变化)需要等待几秒点击下一个按钮才会生效,不然图片在当前页面不会刷新,但是其实图片的样子已经改变,这其中的原理或许是因为我传的值不好,又或者是浏览器缓存问题,反正需要等待几秒,最后,放一张效果图。

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
			+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>" />
<meta charset="UTF-8">
<title>首页</title>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" />
<style type="text/css">
.startli,.teamli,.managerli{
	display:none;
}
</style>
<script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
	$(function() {
		$('.btnStart').click(function() {
			//alert($('.btnStart').attr("alt"));
			$.ajax({
				url : "apply/startProcess",
				type : 'post',
				data : {"appid":$('.btnStart').attr("alt"),"businessKey":$('.btnStart').attr("alt1"),"processDefinitionKey":$('.btnStart').attr("alt2")}, //提交给服务器的参数
				dataType : 'json', //返回值类型,服务器out对象输出的内容
				success : function(objs) { //回调函数 ,服务器有返回输出的时候调用的函数
					//alert(objs[0]+"=========="+objs[1]);
					$('.Zu').val(objs[2]);
					$('.img').attr("src",'activity/'+objs[0]);
					$('.startli').text("审批已开启,提交给组长中,请稍后...");
					$('.startli').show();
				}
			});
		});
		$('.Zu1').click(function() {
			//alert($('.Zu').val());
			$.ajax({
				url : "apply/completeTaskByTaskId",
				type : 'post',
				data : {"taskId":$('.Zu').val()}, //提交给服务器的参数
				dataType : 'json', //返回值类型,服务器out对象输出的内容
				success : function(objs) { //回调函数 ,服务器有返回输出的时候调用的函数
					$('.Xj').val(objs[1]);
				   var attr=$('.img').attr('attr');
				   //alert(parseInt(attr+1));
				   var $parent=$('.img').parent();
				   $parent.html('');
				   var m="<img src='activity/"+objs[0]+"?attr="+new Date().getTime()+"'/>";
				   
				   $parent.append(m);
				   $('.teamli').text('组长审批通过,提交给经理中,请稍后...');
				   $('.teamli').show();
				}
			});
		});
		$('.Xj1').click(function() {
			$.ajax({
				url : "apply/completeTaskByTaskId",
				type : 'post',
				data : {"taskId":$('.Xj').val()}, //提交给服务器的参数
				dataType : 'json', //返回值类型,服务器out对象输出的内容
				success : function(objs) { //回调函数 ,服务器有返回输出的时候调用的函数
					   //var attr=$('.img').attr('attr');
					   //alert(parseInt(attr+1));
					   //var $parent=$('.img').parent();
					   $(".imgDiv").html('');
					   var m="<img src='activity/"+objs[0]+"?attr="+new Date().getTime()+"'/>";
					   $(".imgDiv").append(m);
					   $('.managerli').text('经理审批通过,正在自动人事归档,请稍后...');
					   $('.managerli').show();
				}
			});
		});
	});
</script>
</head>
<body>
<h3>项目审批工作:</h3>
	<ul>
		<li><input name="btnStart" class="btnStart" alt="1"
			alt1="user001" alt2="apply" type="hidden">
			<button class="btnStart">开始审批</button></li>
			<li class="startli"></li>
		<li><button class="Zu1">组长审批</button>
			<input name="Zu" class="Zu" type="hidden"></li>
			<li class="teamli"></li>
		<li><button class="Xj1">经理审批</button> <input name="Xj" class="Xj"
			type="hidden"></li>
			<li class="managerli"></li>
		<li>人事归档</li>
	</ul>
	<div class="imgDiv"><img  src="" class="img" id="img1" attr="1"></div>
</body>
</html>

  

当然,其中还有很多小坑,以后还需慢慢完善。

猜你喜欢

转载自www.cnblogs.com/clack/p/10032852.html