Activiti之流程图查看

原创
2016/03/23 11:22
阅读数 6.5K

本文将介绍怎么在自己的系统内显示activiti的流程图,示例代码是从官方demo里提取的一部分流程图展示的代码,这里是结合springmvc来实现的,大家可以从官方代码里提取,也可以参照本博文来直接使用。

1、代码目录结构

2、代码详情

JacksonConfiguration.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author Joram Barrez
 */
@Configuration
public class JacksonConfiguration
{

	@Bean()
	public ObjectMapper objectMapper()
	{
		// To avoid instantiating and configuring the mapper everywhere
		ObjectMapper mapper = new ObjectMapper();
		return mapper;
	}

}

BaseProcessDefinitionDiagramLayoutResource.java

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.ActivitiObjectNotFoundException;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.bpmn.behavior.BoundaryEventActivityBehavior;
import org.activiti.engine.impl.bpmn.behavior.CallActivityBehavior;
import org.activiti.engine.impl.bpmn.parser.BpmnParse;
import org.activiti.engine.impl.bpmn.parser.ErrorEventDefinition;
import org.activiti.engine.impl.bpmn.parser.EventSubscriptionDeclaration;
import org.activiti.engine.impl.jobexecutor.TimerDeclarationImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.Lane;
import org.activiti.engine.impl.pvm.process.LaneSet;
import org.activiti.engine.impl.pvm.process.ParticipantProcess;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class BaseProcessDefinitionDiagramLayoutResource
{

	@Autowired
	private RuntimeService		runtimeService;

	@Autowired
	private RepositoryService	repositoryService;

	@Autowired
	private HistoryService		historyService;

	public ObjectNode getDiagramNode(String processInstanceId, String processDefinitionId)
	{

		List<String> highLightedFlows = Collections.<String> emptyList();
		List<String> highLightedActivities = Collections.<String> emptyList();

		Map<String, ObjectNode> subProcessInstanceMap = new HashMap<String, ObjectNode>();

		ProcessInstance processInstance = null;
		if (processInstanceId != null)
		{
			processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId)
					.singleResult();
			if (processInstance == null)
			{
				throw new ActivitiObjectNotFoundException("Process instance could not be found");
			}
			processDefinitionId = processInstance.getProcessDefinitionId();

			List<ProcessInstance> subProcessInstances = runtimeService.createProcessInstanceQuery()
					.superProcessInstanceId(processInstanceId).list();

			for (ProcessInstance subProcessInstance : subProcessInstances)
			{
				String subDefId = subProcessInstance.getProcessDefinitionId();

				String superExecutionId = ((ExecutionEntity) subProcessInstance).getSuperExecutionId();
				ProcessDefinitionEntity subDef = (ProcessDefinitionEntity) repositoryService
						.getProcessDefinition(subDefId);

				ObjectNode processInstanceJSON = new ObjectMapper().createObjectNode();
				processInstanceJSON.put("processInstanceId", subProcessInstance.getId());
				processInstanceJSON.put("superExecutionId", superExecutionId);
				processInstanceJSON.put("processDefinitionId", subDef.getId());
				processInstanceJSON.put("processDefinitionKey", subDef.getKey());
				processInstanceJSON.put("processDefinitionName", subDef.getName());

				subProcessInstanceMap.put(superExecutionId, processInstanceJSON);
			}
		}

		if (processDefinitionId == null)
		{
			throw new ActivitiObjectNotFoundException("No process definition id provided");
		}

		ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
				.getProcessDefinition(processDefinitionId);

		if (processDefinition == null)
		{
			throw new ActivitiException("Process definition " + processDefinitionId + " could not be found");
		}

		ObjectNode responseJSON = new ObjectMapper().createObjectNode();

		// Process definition
		JsonNode pdrJSON = getProcessDefinitionResponse(processDefinition);

		if (pdrJSON != null)
		{
			responseJSON.put("processDefinition", pdrJSON);
		}

		// Highlighted activities
		if (processInstance != null)
		{
			ArrayNode activityArray = new ObjectMapper().createArrayNode();
			ArrayNode flowsArray = new ObjectMapper().createArrayNode();

			highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
			highLightedFlows = getHighLightedFlows(processInstanceId, processDefinition);

			for (String activityName : highLightedActivities)
			{
				activityArray.add(activityName);
			}

			for (String flow : highLightedFlows)
				flowsArray.add(flow);

			responseJSON.put("highLightedActivities", activityArray);
			responseJSON.put("highLightedFlows", flowsArray);
		}

		// Pool shape, if process is participant in collaboration
		if (processDefinition.getParticipantProcess() != null)
		{
			ParticipantProcess pProc = processDefinition.getParticipantProcess();

			ObjectNode participantProcessJSON = new ObjectMapper().createObjectNode();
			participantProcessJSON.put("id", pProc.getId());
			if (StringUtils.isNotEmpty(pProc.getName()))
			{
				participantProcessJSON.put("name", pProc.getName());
			}
			else
			{
				participantProcessJSON.put("name", "");
			}
			participantProcessJSON.put("x", pProc.getX());
			participantProcessJSON.put("y", pProc.getY());
			participantProcessJSON.put("width", pProc.getWidth());
			participantProcessJSON.put("height", pProc.getHeight());

			responseJSON.put("participantProcess", participantProcessJSON);
		}

		// Draw lanes

		if (processDefinition.getLaneSets() != null && !processDefinition.getLaneSets().isEmpty())
		{
			ArrayNode laneSetArray = new ObjectMapper().createArrayNode();
			for (LaneSet laneSet : processDefinition.getLaneSets())
			{
				ArrayNode laneArray = new ObjectMapper().createArrayNode();
				if (laneSet.getLanes() != null && !laneSet.getLanes().isEmpty())
				{
					for (Lane lane : laneSet.getLanes())
					{
						ObjectNode laneJSON = new ObjectMapper().createObjectNode();
						laneJSON.put("id", lane.getId());
						if (StringUtils.isNotEmpty(lane.getName()))
						{
							laneJSON.put("name", lane.getName());
						}
						else
						{
							laneJSON.put("name", "");
						}
						laneJSON.put("x", lane.getX());
						laneJSON.put("y", lane.getY());
						laneJSON.put("width", lane.getWidth());
						laneJSON.put("height", lane.getHeight());

						List<String> flowNodeIds = lane.getFlowNodeIds();
						ArrayNode flowNodeIdsArray = new ObjectMapper().createArrayNode();
						for (String flowNodeId : flowNodeIds)
						{
							flowNodeIdsArray.add(flowNodeId);
						}
						laneJSON.put("flowNodeIds", flowNodeIdsArray);

						laneArray.add(laneJSON);
					}
				}
				ObjectNode laneSetJSON = new ObjectMapper().createObjectNode();
				laneSetJSON.put("id", laneSet.getId());
				if (StringUtils.isNotEmpty(laneSet.getName()))
				{
					laneSetJSON.put("name", laneSet.getName());
				}
				else
				{
					laneSetJSON.put("name", "");
				}
				laneSetJSON.put("lanes", laneArray);

				laneSetArray.add(laneSetJSON);
			}

			if (laneSetArray.size() > 0)
				responseJSON.put("laneSets", laneSetArray);
		}

		ArrayNode sequenceFlowArray = new ObjectMapper().createArrayNode();
		ArrayNode activityArray = new ObjectMapper().createArrayNode();

		// Activities and their sequence-flows

		for (ActivityImpl activity : processDefinition.getActivities())
		{
			getActivity(processInstanceId, activity, activityArray, sequenceFlowArray, processInstance,
					highLightedFlows, subProcessInstanceMap);
		}

		responseJSON.put("activities", activityArray);
		responseJSON.put("sequenceFlows", sequenceFlowArray);

		return responseJSON;
	}

	private List<String> getHighLightedFlows(String processInstanceId, ProcessDefinitionEntity processDefinition)
	{

		List<String> highLightedFlows = new ArrayList<String>();
		List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
				.processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();

		List<String> historicActivityInstanceList = new ArrayList<String>();
		for (HistoricActivityInstance hai : historicActivityInstances)
		{
			historicActivityInstanceList.add(hai.getActivityId());
		}

		// add current activities to list
		List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
		historicActivityInstanceList.addAll(highLightedActivities);

		// activities and their sequence-flows
		for (ActivityImpl activity : processDefinition.getActivities())
		{
			int index = historicActivityInstanceList.indexOf(activity.getId());

			if (index >= 0 && index + 1 < historicActivityInstanceList.size())
			{
				List<PvmTransition> pvmTransitionList = activity.getOutgoingTransitions();
				for (PvmTransition pvmTransition : pvmTransitionList)
				{
					String destinationFlowId = pvmTransition.getDestination().getId();
					if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1)))
					{
						highLightedFlows.add(pvmTransition.getId());
					}
				}
			}
		}
		return highLightedFlows;
	}

	@SuppressWarnings("unchecked")
	private void getActivity(String processInstanceId, ActivityImpl activity, ArrayNode activityArray,
			ArrayNode sequenceFlowArray, ProcessInstance processInstance, List<String> highLightedFlows,
			Map<String, ObjectNode> subProcessInstanceMap)
	{

		ObjectNode activityJSON = new ObjectMapper().createObjectNode();

		// Gather info on the multi instance marker
		String multiInstance = (String) activity.getProperty("multiInstance");
		if (multiInstance != null)
		{
			if (!"sequential".equals(multiInstance))
			{
				multiInstance = "parallel";
			}
		}

		ActivityBehavior activityBehavior = activity.getActivityBehavior();
		// Gather info on the collapsed marker
		Boolean collapsed = (activityBehavior instanceof CallActivityBehavior);
		Boolean expanded = (Boolean) activity.getProperty(BpmnParse.PROPERTYNAME_ISEXPANDED);
		if (expanded != null)
		{
			collapsed = !expanded;
		}

		Boolean isInterrupting = null;
		if (activityBehavior instanceof BoundaryEventActivityBehavior)
		{
			isInterrupting = ((BoundaryEventActivityBehavior) activityBehavior).isInterrupting();
		}

		// Outgoing transitions of activity
		for (PvmTransition sequenceFlow : activity.getOutgoingTransitions())
		{
			String flowName = (String) sequenceFlow.getProperty("name");
			boolean isHighLighted = (highLightedFlows.contains(sequenceFlow.getId()));
			boolean isConditional = sequenceFlow.getProperty(BpmnParse.PROPERTYNAME_CONDITION) != null
					&& !((String) activity.getProperty("type")).toLowerCase().contains("gateway");
			boolean isDefault = sequenceFlow.getId().equals(activity.getProperty("default"))
					&& ((String) activity.getProperty("type")).toLowerCase().contains("gateway");

			List<Integer> waypoints = ((TransitionImpl) sequenceFlow).getWaypoints();
			ArrayNode xPointArray = new ObjectMapper().createArrayNode();
			ArrayNode yPointArray = new ObjectMapper().createArrayNode();
			for (int i = 0; i < waypoints.size(); i += 2)
			{ // waypoints.size()
				// minimally 4: x1, y1,
				// x2, y2
				xPointArray.add(waypoints.get(i));
				yPointArray.add(waypoints.get(i + 1));
			}

			ObjectNode flowJSON = new ObjectMapper().createObjectNode();
			flowJSON.put("id", sequenceFlow.getId());
			flowJSON.put("name", flowName);
			flowJSON.put("flow", "(" + sequenceFlow.getSource().getId() + ")--" + sequenceFlow.getId() + "-->("
					+ sequenceFlow.getDestination().getId() + ")");

			if (isConditional)
				flowJSON.put("isConditional", isConditional);
			if (isDefault)
				flowJSON.put("isDefault", isDefault);
			if (isHighLighted)
				flowJSON.put("isHighLighted", isHighLighted);

			flowJSON.put("xPointArray", xPointArray);
			flowJSON.put("yPointArray", yPointArray);

			sequenceFlowArray.add(flowJSON);
		}

		// Nested activities (boundary events)
		ArrayNode nestedActivityArray = new ObjectMapper().createArrayNode();
		for (ActivityImpl nestedActivity : activity.getActivities())
		{
			nestedActivityArray.add(nestedActivity.getId());
		}

		Map<String, Object> properties = activity.getProperties();
		ObjectNode propertiesJSON = new ObjectMapper().createObjectNode();
		for (String key : properties.keySet())
		{
			Object prop = properties.get(key);
			if (prop instanceof String)
				propertiesJSON.put(key, (String) properties.get(key));
			else if (prop instanceof Integer)
				propertiesJSON.put(key, (Integer) properties.get(key));
			else if (prop instanceof Boolean)
				propertiesJSON.put(key, (Boolean) properties.get(key));
			else if ("initial".equals(key))
			{
				ActivityImpl act = (ActivityImpl) properties.get(key);
				propertiesJSON.put(key, act.getId());
			}
			else if ("timerDeclarations".equals(key))
			{
				ArrayList<TimerDeclarationImpl> timerDeclarations = (ArrayList<TimerDeclarationImpl>) properties
						.get(key);
				ArrayNode timerDeclarationArray = new ObjectMapper().createArrayNode();

				if (timerDeclarations != null)
					for (TimerDeclarationImpl timerDeclaration : timerDeclarations)
					{
						ObjectNode timerDeclarationJSON = new ObjectMapper().createObjectNode();

						timerDeclarationJSON.put("isExclusive", timerDeclaration.isExclusive());
						if (timerDeclaration.getRepeat() != null)
							timerDeclarationJSON.put("repeat", timerDeclaration.getRepeat());

						timerDeclarationJSON.put("retries", String.valueOf(timerDeclaration.getRetries()));
						timerDeclarationJSON.put("type", timerDeclaration.getJobHandlerType());
						timerDeclarationJSON.put("configuration", timerDeclaration.getJobHandlerConfiguration());
						// timerDeclarationJSON.put("expression",
						// timerDeclaration.getDescription());

						timerDeclarationArray.add(timerDeclarationJSON);
					}
				if (timerDeclarationArray.size() > 0)
					propertiesJSON.put(key, timerDeclarationArray);
				// TODO: implement getting description
			}
			else if ("eventDefinitions".equals(key))
			{
				ArrayList<EventSubscriptionDeclaration> eventDefinitions = (ArrayList<EventSubscriptionDeclaration>) properties
						.get(key);
				ArrayNode eventDefinitionsArray = new ObjectMapper().createArrayNode();

				if (eventDefinitions != null)
				{
					for (EventSubscriptionDeclaration eventDefinition : eventDefinitions)
					{
						ObjectNode eventDefinitionJSON = new ObjectMapper().createObjectNode();

						if (eventDefinition.getActivityId() != null)
							eventDefinitionJSON.put("activityId", eventDefinition.getActivityId());

						eventDefinitionJSON.put("eventName", eventDefinition.getEventName());
						eventDefinitionJSON.put("eventType", eventDefinition.getEventType());
						eventDefinitionJSON.put("isAsync", eventDefinition.isAsync());
						eventDefinitionJSON.put("isStartEvent", eventDefinition.isStartEvent());
						eventDefinitionsArray.add(eventDefinitionJSON);
					}
				}

				if (eventDefinitionsArray.size() > 0)
					propertiesJSON.put(key, eventDefinitionsArray);

				// TODO: implement it
			}
			else if ("errorEventDefinitions".equals(key))
			{
				ArrayList<ErrorEventDefinition> errorEventDefinitions = (ArrayList<ErrorEventDefinition>) properties
						.get(key);
				ArrayNode errorEventDefinitionsArray = new ObjectMapper().createArrayNode();

				if (errorEventDefinitions != null)
				{
					for (ErrorEventDefinition errorEventDefinition : errorEventDefinitions)
					{
						ObjectNode errorEventDefinitionJSON = new ObjectMapper().createObjectNode();

						if (errorEventDefinition.getErrorCode() != null)
							errorEventDefinitionJSON.put("errorCode", errorEventDefinition.getErrorCode());
						else
							errorEventDefinitionJSON.putNull("errorCode");

						errorEventDefinitionJSON.put("handlerActivityId", errorEventDefinition.getHandlerActivityId());

						errorEventDefinitionsArray.add(errorEventDefinitionJSON);
					}
				}

				if (errorEventDefinitionsArray.size() > 0)
					propertiesJSON.put(key, errorEventDefinitionsArray);
			}

		}

		if ("callActivity".equals(properties.get("type")))
		{
			CallActivityBehavior callActivityBehavior = null;

			if (activityBehavior instanceof CallActivityBehavior)
			{
				callActivityBehavior = (CallActivityBehavior) activityBehavior;
			}

			if (callActivityBehavior != null)
			{
				propertiesJSON.put("processDefinitonKey", callActivityBehavior.getProcessDefinitonKey());

				// get processDefinitonId from execution or get last
				// processDefinitonId
				// by key
				ArrayNode processInstanceArray = new ObjectMapper().createArrayNode();
				if (processInstance != null)
				{
					List<Execution> executionList = runtimeService.createExecutionQuery()
							.processInstanceId(processInstanceId).activityId(activity.getId()).list();
					if (!executionList.isEmpty())
					{
						for (Execution execution : executionList)
						{
							ObjectNode processInstanceJSON = subProcessInstanceMap.get(execution.getId());
							processInstanceArray.add(processInstanceJSON);
						}
					}
				}

				// If active activities nas no instance of this callActivity
				// then add
				// last definition
				if (processInstanceArray.size() == 0
						&& StringUtils.isNotEmpty(callActivityBehavior.getProcessDefinitonKey()))
				{
					// Get last definition by key
					ProcessDefinition lastProcessDefinition = repositoryService.createProcessDefinitionQuery()
							.processDefinitionKey(callActivityBehavior.getProcessDefinitonKey()).latestVersion()
							.singleResult();

					if (lastProcessDefinition != null)
					{
						ObjectNode processInstanceJSON = new ObjectMapper().createObjectNode();
						processInstanceJSON.put("processDefinitionId", lastProcessDefinition.getId());
						processInstanceJSON.put("processDefinitionKey", lastProcessDefinition.getKey());
						processInstanceJSON.put("processDefinitionName", lastProcessDefinition.getName());
						processInstanceArray.add(processInstanceJSON);
					}
				}

				if (processInstanceArray.size() > 0)
				{
					propertiesJSON.put("processDefinitons", processInstanceArray);
				}
			}
		}

		activityJSON.put("activityId", activity.getId());
		activityJSON.put("properties", propertiesJSON);
		if (multiInstance != null)
			activityJSON.put("multiInstance", multiInstance);
		if (collapsed)
			activityJSON.put("collapsed", collapsed);
		if (nestedActivityArray.size() > 0)
			activityJSON.put("nestedActivities", nestedActivityArray);
		if (isInterrupting != null)
			activityJSON.put("isInterrupting", isInterrupting);

		activityJSON.put("x", activity.getX());
		activityJSON.put("y", activity.getY());
		activityJSON.put("width", activity.getWidth());
		activityJSON.put("height", activity.getHeight());

		activityArray.add(activityJSON);

		// Nested activities (boundary events)
		for (ActivityImpl nestedActivity : activity.getActivities())
		{
			getActivity(processInstanceId, nestedActivity, activityArray, sequenceFlowArray, processInstance,
					highLightedFlows, subProcessInstanceMap);
		}
	}

	private JsonNode getProcessDefinitionResponse(ProcessDefinitionEntity processDefinition)
	{
		ObjectMapper mapper = new ObjectMapper();
		ObjectNode pdrJSON = mapper.createObjectNode();
		pdrJSON.put("id", processDefinition.getId());
		pdrJSON.put("name", processDefinition.getName());
		pdrJSON.put("key", processDefinition.getKey());
		pdrJSON.put("version", processDefinition.getVersion());
		pdrJSON.put("deploymentId", processDefinition.getDeploymentId());
		pdrJSON.put("isGraphicNotationDefined", isGraphicNotationDefined(processDefinition));
		return pdrJSON;
	}

	private boolean isGraphicNotationDefined(ProcessDefinitionEntity processDefinition)
	{
		return ((ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinition.getId()))
				.isGraphicalNotationDefined();
	}
}

ProcessInstanceDiagramLayoutResource.java

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.node.ObjectNode;

@RestController
public class ProcessInstanceDiagramLayoutResource extends BaseProcessDefinitionDiagramLayoutResource
{

	@RequestMapping(value = "/process-instance/diagram-layout.do", method = RequestMethod.GET, produces = "application/json")
	public ObjectNode getDiagram(@RequestParam("processInstanceId") String processInstanceId)
	{
		return getDiagramNode(processInstanceId, null);
	}
}

ProcessInstanceHighlightsResource.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

@RestController
public class ProcessInstanceHighlightsResource
{

	@Autowired
	private RuntimeService		runtimeService;

	@Autowired
	private RepositoryService	repositoryService;

	@Autowired
	private HistoryService		historyService;

	protected ObjectMapper		objectMapper	= new ObjectMapper();

	@RequestMapping(value = "/process-instance/highlights.do", method = RequestMethod.GET, produces = "application/json")
	public ObjectNode getHighlighted(@RequestParam("processInstanceId") String processInstanceId)
	{
		ObjectNode responseJSON = objectMapper.createObjectNode();
		responseJSON.put("processInstanceId", processInstanceId);
		ArrayNode activitiesArray = objectMapper.createArrayNode();
		ArrayNode flowsArray = objectMapper.createArrayNode();
		try
		{
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).singleResult();
			ProcessDefinitionEntity processDefinition = new ProcessDefinitionEntity();
			if (null == processInstance)
			{
				HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
						.processInstanceId(processInstanceId).singleResult();
				processDefinition = (ProcessDefinitionEntity) repositoryService
						.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
				responseJSON.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());
				List<HistoricActivityInstance> historicActivityInstances = historyService
						.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
				for (HistoricActivityInstance historicActivityInstance : historicActivityInstances)
				{
					activitiesArray.add(historicActivityInstance.getActivityId());
				}
			}
			else
			{
				processDefinition = (ProcessDefinitionEntity) repositoryService
						.getProcessDefinition(processInstance.getProcessDefinitionId());
				responseJSON.put("processDefinitionId", processInstance.getProcessDefinitionId());
				List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
				for (String activityId : highLightedActivities)
				{
					activitiesArray.add(activityId);
				}
			}
			List<String> highLightedFlows = getHighLightedFlows(processDefinition, processInstanceId);
			for (String flow : highLightedFlows)
			{
				flowsArray.add(flow);
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		responseJSON.put("activities", activitiesArray);
		responseJSON.put("flows", flowsArray);
		return responseJSON;
	}

	/**
	 * getHighLightedFlows
	 * 
	 * @param processDefinition
	 * @param processInstanceId
	 * @return
	 */
	private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId)
	{

		List<String> highLightedFlows = new ArrayList<String>();

		List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
				.processInstanceId(processInstanceId)
				// order by startime asc is not correct. use default order is
				// correct.
				// .orderByHistoricActivityInstanceStartTime().asc()/*.orderByActivityId().asc()*/
				.list();

		LinkedList<HistoricActivityInstance> hisActInstList = new LinkedList<HistoricActivityInstance>();
		hisActInstList.addAll(historicActivityInstances);

		getHighlightedFlows(processDefinition.getActivities(), hisActInstList, highLightedFlows);

		return highLightedFlows;
	}

	/**
	 * getHighlightedFlows code logic: 1. Loop all activities by id asc order;
	 * 2. Check each activity's outgoing transitions and eventBoundery outgoing
	 * transitions, if outgoing transitions's destination.id is in other
	 * executed activityIds, add this transition to highLightedFlows List; 3.
	 * But if activity is not a parallelGateway or inclusiveGateway, only choose
	 * the earliest flow.
	 * 
	 * @param activityList
	 * @param hisActInstList
	 * @param highLightedFlows
	 */
	private void getHighlightedFlows(List<ActivityImpl> activityList,
			LinkedList<HistoricActivityInstance> hisActInstList, List<String> highLightedFlows)
	{

		// check out startEvents in activityList
		List<ActivityImpl> startEventActList = new ArrayList<ActivityImpl>();
		Map<String, ActivityImpl> activityMap = new HashMap<String, ActivityImpl>(activityList.size());
		for (ActivityImpl activity : activityList)
		{

			activityMap.put(activity.getId(), activity);

			String actType = (String) activity.getProperty("type");
			if (actType != null && actType.toLowerCase().indexOf("startevent") >= 0)
			{
				startEventActList.add(activity);
			}
		}

		// These codes is used to avoid a bug:
		// ACT-1728 If the process instance was started by a callActivity, it
		// will be not have the startEvent activity in ACT_HI_ACTINST table
		// Code logic:
		// Check the first activity if it is a startEvent, if not check out the
		// startEvent's highlight outgoing flow.
		HistoricActivityInstance firstHistActInst = hisActInstList.getFirst();
		String firstActType = (String) firstHistActInst.getActivityType();
		if (firstActType != null && firstActType.toLowerCase().indexOf("startevent") < 0)
		{
			PvmTransition startTrans = getStartTransaction(startEventActList, firstHistActInst);
			if (startTrans != null)
			{
				highLightedFlows.add(startTrans.getId());
			}
		}

		while (!hisActInstList.isEmpty())
		{
			HistoricActivityInstance histActInst = hisActInstList.removeFirst();
			ActivityImpl activity = activityMap.get(histActInst.getActivityId());
			if (activity != null)
			{
				boolean isParallel = false;
				String type = histActInst.getActivityType();
				if ("parallelGateway".equals(type) || "inclusiveGateway".equals(type))
				{
					isParallel = true;
				}
				else if ("subProcess".equals(histActInst.getActivityType()))
				{
					getHighlightedFlows(activity.getActivities(), hisActInstList, highLightedFlows);
				}

				List<PvmTransition> allOutgoingTrans = new ArrayList<PvmTransition>();
				allOutgoingTrans.addAll(activity.getOutgoingTransitions());
				allOutgoingTrans.addAll(getBoundaryEventOutgoingTransitions(activity));
				List<String> activityHighLightedFlowIds = getHighlightedFlows(allOutgoingTrans, hisActInstList,
						isParallel);
				highLightedFlows.addAll(activityHighLightedFlowIds);
			}
		}
	}

	/**
	 * Check out the outgoing transition connected to firstActInst from
	 * startEventActList
	 * 
	 * @param startEventActList
	 * @param firstActInst
	 * @return
	 */
	private PvmTransition getStartTransaction(List<ActivityImpl> startEventActList,
			HistoricActivityInstance firstActInst)
	{
		for (ActivityImpl startEventAct : startEventActList)
		{
			for (PvmTransition trans : startEventAct.getOutgoingTransitions())
			{
				if (trans.getDestination().getId().equals(firstActInst.getActivityId()))
				{
					return trans;
				}
			}
		}
		return null;
	}

	/**
	 * getBoundaryEventOutgoingTransitions
	 * 
	 * @param activity
	 * @return
	 */
	private List<PvmTransition> getBoundaryEventOutgoingTransitions(ActivityImpl activity)
	{
		List<PvmTransition> boundaryTrans = new ArrayList<PvmTransition>();
		for (ActivityImpl subActivity : activity.getActivities())
		{
			String type = (String) subActivity.getProperty("type");
			if (type != null && type.toLowerCase().indexOf("boundary") >= 0)
			{
				boundaryTrans.addAll(subActivity.getOutgoingTransitions());
			}
		}
		return boundaryTrans;
	}

	/**
	 * find out single activity's highlighted flowIds
	 * 
	 * @param activity
	 * @param hisActInstList
	 * @param isExclusive if true only return one flowId(Such as
	 *            exclusiveGateway, BoundaryEvent On Task)
	 * @return
	 */
	private List<String> getHighlightedFlows(List<PvmTransition> pvmTransitionList,
			LinkedList<HistoricActivityInstance> hisActInstList, boolean isParallel)
	{

		List<String> highLightedFlowIds = new ArrayList<String>();

		PvmTransition earliestTrans = null;
		HistoricActivityInstance earliestHisActInst = null;

		for (PvmTransition pvmTransition : pvmTransitionList)
		{

			String destActId = pvmTransition.getDestination().getId();
			HistoricActivityInstance destHisActInst = findHisActInst(hisActInstList, destActId);
			if (destHisActInst != null)
			{
				if (isParallel)
				{
					highLightedFlowIds.add(pvmTransition.getId());
				}
				else if (earliestHisActInst == null
						|| (earliestHisActInst.getId().compareTo(destHisActInst.getId()) > 0))
				{
					earliestTrans = pvmTransition;
					earliestHisActInst = destHisActInst;
				}
			}
		}

		if ((!isParallel) && earliestTrans != null)
		{
			highLightedFlowIds.add(earliestTrans.getId());
		}

		return highLightedFlowIds;
	}

	private HistoricActivityInstance findHisActInst(LinkedList<HistoricActivityInstance> hisActInstList, String actId)
	{
		for (HistoricActivityInstance hisActInst : hisActInstList)
		{
			if (hisActInst.getActivityId().equals(actId))
			{
				return hisActInst;
			}
		}
		return null;
	}
}

DispatcherServletConfiguration.java

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
@ComponentScan({ "org.activiti.rest.editor", "org.activiti.rest.diagram" })
@EnableAsync
public class DispatcherServletConfiguration extends WebMvcConfigurationSupport
{

	private final Logger	log	= LoggerFactory.getLogger(DispatcherServletConfiguration.class);

	@Autowired
	private ObjectMapper	objectMapper;

	@Autowired
	private Environment		environment;

	@Bean
	public SessionLocaleResolver localeResolver()
	{
		return new SessionLocaleResolver();
	}

	@Bean
	public LocaleChangeInterceptor localeChangeInterceptor()
	{
		log.debug("Configuring localeChangeInterceptor");
		LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
		localeChangeInterceptor.setParamName("language");
		return localeChangeInterceptor;
	}

	@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping()
	{
		log.debug("Creating requestMappingHandlerMapping");
		RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
		requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
		Object[] interceptors = { localeChangeInterceptor() };
		requestMappingHandlerMapping.setInterceptors(interceptors);
		return requestMappingHandlerMapping;
	}

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
	{
		addDefaultHttpMessageConverters(converters);
		for (HttpMessageConverter<?> converter : converters)
		{
			if (converter instanceof MappingJackson2HttpMessageConverter)
			{
				MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = (MappingJackson2HttpMessageConverter) converter;
				jackson2HttpMessageConverter.setObjectMapper(objectMapper);
				break;
			}
		}
	}

	@Override
	protected void configureContentNegotiation(ContentNegotiationConfigurer configurer)
	{
		configurer.favorPathExtension(false);
	}

}

FilterServletOutputStream.java

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;

public class FilterServletOutputStream extends ServletOutputStream
{

	private DataOutputStream	stream;
	//private WriteListener		writeListener;

	public FilterServletOutputStream(OutputStream output)
	{
		stream = new DataOutputStream(output);
	}

	public void write(int b) throws IOException
	{
		stream.write(b);
	}

	public void write(byte[] b) throws IOException
	{
		stream.write(b);
	}

	public void write(byte[] b, int off, int len) throws IOException
	{
		stream.write(b, off, len);
	}

	@Override
	public void setWriteListener(WriteListener writeListener)
	{
		//this.writeListener = writeListener;
	}

	@Override
	public boolean isReady()
	{
		return true;
	}
}

GenericResponseWrapper.java

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GenericResponseWrapper extends HttpServletResponseWrapper
{
	private ByteArrayOutputStream	output;
	private int						contentLength;
	private String					contentType;

	public GenericResponseWrapper(HttpServletResponse response)
	{
		super(response);
		output = new ByteArrayOutputStream();
	}

	public byte[] getData()
	{
		return output.toByteArray();
	}

	public ServletOutputStream getOutputStream()
	{
		return new FilterServletOutputStream(output);
	}

	public PrintWriter getWriter()
	{
		return new PrintWriter(getOutputStream(), true);
	}

	public void setContentLength(int length)
	{
		this.contentLength = length;
		super.setContentLength(length);
	}

	public int getContentLength()
	{
		return contentLength;
	}

	public void setContentType(String type)
	{
		this.contentType = type;
		super.setContentType(type);
	}

	public String getContentType()
	{
		return contentType;
	}
}

JsonpCallbackFilter.java

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JsonpCallbackFilter implements Filter
{

	private static Logger	log	= LoggerFactory.getLogger(JsonpCallbackFilter.class);

	public void init(FilterConfig fConfig) throws ServletException
	{
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
			ServletException
	{
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		Map<String, String[]> parms = httpRequest.getParameterMap();

		if (parms.containsKey("callback"))
		{
			if (log.isDebugEnabled())
				log.debug("Wrapping response with JSONP callback '" + parms.get("callback")[0] + "'");

			OutputStream out = httpResponse.getOutputStream();

			GenericResponseWrapper wrapper = new GenericResponseWrapper(httpResponse);

			chain.doFilter(request, wrapper);

			// handles the content-size truncation
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			outputStream.write(new String(parms.get("callback")[0] + "(").getBytes());
			outputStream.write(wrapper.getData());
			outputStream.write(new String(");").getBytes());
			byte jsonpResponse[] = outputStream.toByteArray();

			wrapper.setContentType("text/javascript;charset=UTF-8");
			wrapper.setContentLength(jsonpResponse.length);

			out.write(jsonpResponse);

			out.close();

		}
		else
		{
			chain.doFilter(request, response);
		}
	}

	public void destroy()
	{
	}
}

3,前端页面

 

这个也是从官方demo拷贝出来的,这里单独把这个文件夹打包出来,大家也可以从官方demo里提取。

4,如何显示

访问:http://localhost:8080/demo/diagram-viewer/index.html?processDefinitionId=project_approve:123:317507&processInstanceId=325001

其中对应的参数填写自己的流程定义ID和实例ID

5,显示效果

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
1 收藏
1
分享
返回顶部
顶部