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>

  

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM