《partner4java 讲述jBPM4》之第三步:图形化查看执行位置

图形化查看执行位置(或者称为:查看活动坐标显示在图中的图形位置)

完成起来只需要特殊两部分:

1、发布的时候打包进png图片,显示图形位置时取出(或不打包进发布,能够拼出位置也可)

如:

		InputStream in = new FileInputStream(
				"F:\\workspace\\jbpm\\workspace\\hello_jbpm\\src\\main\\resources\\leave.zip");
		ZipInputStream zipInputStream = new ZipInputStream(in);
		jpdlDeployManager.processEngine.getRepositoryService().createDeployment()
				.addResourcesFromZipInputStream(zipInputStream).deploy();
取出:

// 取出发布id中资源的io流
inputStream = repositoryService.getResourceAsStream(deploymentId, resourceName);

2、取出当前活动坐标

什么意思呢?jbpm4为我们提供一个对象ActivityCoordinates,用于描述某个活动节点相对于图形中的坐标(横坐标、纵坐标、执行任务在图形中的高度和宽度)

/** activity coordinates indicating the graphical position in the diagram.
 * 
 * @see RepositoryService#getActivityCoordinates(String, String)
 * @author Tom Baeyens
 */
public interface ActivityCoordinates {

  int getX();

  int getY();

  int getWidth();

  int getHeight();

}
获取此对象:

	/**
	 * 获取活动坐标显示在图中的图形位置
	 * 
	 * @param processInstance
	 *            流程实例
	 * @return
	 */
	public static ActivityCoordinates getActivityCoordinates(ProcessInstance processInstance) {
		// 两个参数:1个为流程定义id;另一个为流程定义图形中具体活动的名称(或者说当前活动的名称)。
		return repositoryService.getActivityCoordinates(processInstance.getProcessDefinitionId(), processInstance
				.findActiveActivityNames().iterator().next());
	}


helloworld:

首先是我们的业务处理类,我们进行了封装,具体查看注释

package com.partner4java.service;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.jbpm.api.Configuration;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.RepositoryService;
import org.jbpm.api.TaskService;
import org.jbpm.api.model.ActivityCoordinates;
import org.jbpm.api.task.Task;

/**
 * 图片展示执行位置服务类<br/>
 * 提供了两类方法:获取当前流程定义的图形和获取当前活动坐标。<br/>
 * 两类方法都分别有两份:一份是根据taskId获取,另一份是根据processInstanceId获取
 * 
 * @author partner4java
 * 
 */
public class PicViewService {
	public static ProcessEngine processEngine = Configuration.getProcessEngine();
	public static RepositoryService repositoryService = processEngine.getRepositoryService();
	public static ExecutionService executionService = processEngine.getExecutionService();
	public static TaskService taskService = processEngine.getTaskService();
	/** 保存已经查询过的流程定义id对应的图片地址 */
	private static ConcurrentMap<String, String> picViewNames = new ConcurrentHashMap<String, String>();

	/**
	 * 获取图片URL地址<br/>
	 * 打包的png图片名字需与jpdl的name属性名字一致
	 * 
	 * @param taskId
	 *            任务id
	 * @return 如:"jbpm/pic/leave_1.png",相对于web根目录的位置
	 */
	public static String getPicViewByTaskId(String taskId) {
		// 根据taskId获取任务
		Task task = taskService.getTask(taskId);

		// 根据任务获取执行id
		String executionId = task.getExecutionId();

		return getPicView(executionId);
	}

	/**
	 * 获取图片URL地址<br/>
	 * 打包的png图片名字需与jpdl的name属性名字一致
	 * 
	 * @param processInstanceId
	 *            流程实例id
	 * @return 如:"jbpm/pic/leave_1.png",相对于web根目录的位置
	 */
	public static String getPicView(String processInstanceId) {
		// 先根据流程实例id拿到流程实例
		ProcessInstance processInstance = executionService.findProcessInstanceById(processInstanceId);

		// 然后根据流程实例拿到流程定义id
		String processDefinitionId = processInstance.getProcessDefinitionId();

		String fileName = doGetPivView(processDefinitionId);
		return fileName;
	}

	/**
	 * 获取图片URL地址<br/>
	 * 打包的png图片名字需与jpdl的name属性名字一致
	 * 
	 * @param processDefinitionId
	 *            流程定义id
	 * @return 如:"jbpm/pic/leave_1.png",相对于web根目录的位置
	 */
	private static String doGetPivView(String processDefinitionId) {
		// 先判断一下有没有取过,如果取过直接返回缓存地址
		String cachePicName = picViewNames.get(processDefinitionId);
		if (cachePicName != null) {
			return cachePicName;
		}
		// 根据流程实例id拿到流程实例
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
				.processDefinitionId(processDefinitionId).uniqueResult();

		// 根据流程实例拿到发布id(和processDefinitionId的区别一般就是没有key和横杠标识)
		String deploymentId = processDefinition.getDeploymentId();

		// 默认和name属性的名字相同
		String resourceName = processDefinition.getName() + ".png";

		InputStream inputStream = null;
		FileOutputStream fileOutputStream = null;
		BufferedOutputStream out = null;
		String fileName = getFileName(processDefinitionId);
		try {
			// 取出发布id中资源的io流
			inputStream = repositoryService.getResourceAsStream(deploymentId, resourceName);

			// 创建一个文件写入(这里我们做了cache),当然你也可以输出到out中response.getOutputStream().write(b,
			// 0, len);
			File file = createFile(fileName);
			fileOutputStream = new FileOutputStream(file);
			out = new BufferedOutputStream(fileOutputStream);
			byte[] b = new byte[1024];
			int len = -1;
			while ((len = inputStream.read(b, 0, 1024)) > -1) {
				out.write(b, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				inputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		fileName = "jbpm/pic/" + processDefinitionId.replace("-", "_") + ".png";
		picViewNames.put(processDefinitionId, fileName);
		return fileName;
	}

	/**
	 * 创建文件目录
	 * 
	 * @param fileName
	 * @return
	 * @throws IOException
	 */
	private static File createFile(String fileName) throws IOException {
		File file = new File(fileName);
		File parentFile = file.getParentFile();
		if (parentFile != null && !parentFile.exists()) {
			parentFile.mkdirs();
		}
		return file;
	}

	/**
	 * 获取文件的磁盘路径
	 * 
	 * @param processDefinitionId
	 * @return
	 */
	public static String getFileName(String processDefinitionId) {
		URL url = PicViewService.class.getClassLoader().getResource("");
		if (url != null) {
			String path = url.getPath();
			path = path.replace("/WEB-INF/classes", "");
			return path + "jbpm/pic/" + processDefinitionId.replace("-", "_") + ".png";
		}
		return null;
	}

	/**
	 * 获取活动坐标显示在图中的图形位置
	 * 
	 * @param taskId
	 *            任务id
	 * @return
	 */
	public static ActivityCoordinates getActivityCoordinatesByTaskId(String taskId) {
		// 根据taskId获取任务
		Task task = taskService.getTask(taskId);

		// 根据任务获取执行id
		String executionId = task.getExecutionId();
		return getActivityCoordinates(executionId);
	}

	/**
	 * 获取活动坐标显示在图中的图形位置
	 * 
	 * @param processInstanceId
	 *            流程实例id
	 * @return
	 */
	public static ActivityCoordinates getActivityCoordinates(String processInstanceId) {
		ProcessInstance processInstance = executionService.findProcessInstanceById(processInstanceId);
		return getActivityCoordinates(processInstance);
	}

	/**
	 * 获取活动坐标显示在图中的图形位置
	 * 
	 * @param processInstance
	 *            流程实例
	 * @return
	 */
	public static ActivityCoordinates getActivityCoordinates(ProcessInstance processInstance) {
		// 两个参数:1个为流程定义id;另一个为流程定义图形中具体活动的名称(或者说当前活动的名称)。
		return repositoryService.getActivityCoordinates(processInstance.getProcessDefinitionId(), processInstance
				.findActiveActivityNames().iterator().next());
	}

}

有了服务类,然后是我们的servlet:

package com.partner4java.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jbpm.api.model.ActivityCoordinates;

import com.partner4java.service.PicViewService;

/**
 * 以图形的形式展示工作流执行的位置<br/>
 * 如:http://localhost:8080/jbpm_pic/view/pic?taskid=20008或http://localhost:8080/jbpm_pic/view/pic?piid=leave.20001
 * @author partner4java
 * 
 */
public class PicViewServlet extends HttpServlet {
	private static final long serialVersionUID = -1307016588425325378L;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String fileName = null;
		ActivityCoordinates activityCoordinates = null;
		String processInstanceId = req.getParameter("piid");
		// 先根据流程实例id取
		if (processInstanceId != null && !"".equals(processInstanceId)) {
			fileName = PicViewService.getPicView(processInstanceId);
			activityCoordinates = PicViewService.getActivityCoordinates(processInstanceId);
		}
		// 再根据任务id
		else {
			String taskId = req.getParameter("taskid");
			if (taskId != null && !"".equals(taskId)) {
				fileName = PicViewService.getPicViewByTaskId(taskId);
				activityCoordinates = PicViewService.getActivityCoordinatesByTaskId(taskId);
			}
		}

		req.setAttribute("fileName", fileName);
		req.setAttribute("activityCoordinates", activityCoordinates);
		req.getRequestDispatcher("/WEB-INF/view.jsp").forward(req, resp);
	}

}

最后是我们的jsp:

<body>
	<img src="${fileName }"
		style="position:absolute;left:0px;top:0px;">
	<div
		style="position:absolute;border:1px solid red;left:${activityCoordinates.x}px;top:${activityCoordinates.y}px;width:${activityCoordinates.width}px;height:${activityCoordinates.height}px;"></div>

</body>
效果如图:(红框标出了执行位置)


代码下载地址:http://download.csdn.net/detail/partner4java/5013331(你也可以按照servlet注释格式的地址访问,debug进代码看执行流程和涉及到的方法)

你可能感兴趣的:(《partner4java 讲述jBPM4》之第三步:图形化查看执行位置)