继之前的博客,【思想篇】工作流技术JBPM4.4开发入门(4),【思想篇】工作流技术JBPM4.4开发入门(5)本篇博客来结合代码简单说说,如何让流程来管理业务:
先来看看我们抽出来的代理类:
StartAbstractJBPM:流程启动节点
package com.hjy.ssh.action;
import com.hjy.ssh.beans.AbstractApply;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.annotation.Resource;
import org.jbpm.api.ProcessInstance;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import java.lang.reflect.InvocationHandler;
import java.util.Map;
import com.hjy.ssh.service.JBPMService;
import com.opensymphony.xwork2.ActionSupport;
@Controller
@Scope("prototype")
public class StartAbstractJBPM extends ActionSupport {
private static final long serialVersionUID = 1L;
//定义1个属性变量
private Map<String, Object> variablesMap;
private String pdKey;
protected JBPMService jbpmService;
public void common(String pdKey,Map<String, Object> variablesMap,JBPMService jbpmService){
this.variablesMap=variablesMap;
this.pdKey=pdKey;
this.jbpmService=jbpmService;
}
//想尝试能否根据其他方式传参,new的话太耗费资源
/*public StartAbstractJBPM(String pdKey,Map<String, Object> variablesMap,JBPMService jbpmService){
this.variablesMap=variablesMap;
this.pdKey=pdKey;
this.jbpmService=jbpmService;
}*/
//动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的1个实现类
public class LogHandler1 implements InvocationHandler{
// 目标对象
private Object targetObject;
//绑定关系,也就是关联到哪一个接口(与具体的实现类绑定)的哪些方法将被调用时,履行invoke方法。
public Object newProxyInstanceStart(Object targetObject){
this.targetObject=targetObject;
//该方法用于为指定类装载器、1组接口及调用途理器生成动态代理类实例
//第1个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同1个类加载器
//第2个参数要实现和目标对象1样的接口,所以只需要拿到目标对象的实现接口
//第3个参数表明这些被拦截的方法在被拦截时需要履行哪一个InvocationHandler的invoke方法
//根据传入的目标返回1个代理对象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//关联的这个实现类的方法被调用时将被履行
// InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret=null;
try{
//原对象方法调用前处理日志信息
System.out.println("satrt-->>");
//启动流程
ProcessInstance pi=(ProcessInstance) jbpmService.startProcessInstanceByKey(pdKey,variablesMap);
//调用目标方法
AbstractApply abstractApply=(AbstractApply)args[0];
abstractApply.setExecuteId(pi.getId());
args[0]=abstractApply;
ret=method.invoke(targetObject, args);
//调用完成当前结点
// >> 办理完第1个任务“提交申请”
jbpmService.completeFirstTask(pi);
//原对象方法调用后处理日志信息
System.out.println("success-->>");
}catch(Exception e){
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}
}
}
HandleAbstractJBPMAction:任务办理节点
package com.hjy.ssh.action;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.annotation.Resource;
import org.jbpm.api.ProcessInstance;
import java.lang.reflect.InvocationHandler;
import com.hjy.ssh.service.JBPMService;
public abstract class HandleAbstractJBPMAction<T> extends ModelDrivenBaseAction<T> {
protected String outcome;//分支
protected String taskId;//任务id
protected boolean approval;//是不是同意
@Resource
protected JBPMService jbpmService;
//动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的1个实现类
public class LogHandler implements InvocationHandler{
// 目标对象
private Object targetObject;
//绑定关系,也就是关联到哪一个接口(与具体的实现类绑定)的哪些方法将被调用时,履行invoke方法。
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
//该方法用于为指定类装载器、1组接口及调用途理器生成动态代理类实例
//第1个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同1个类加载器
//第2个参数要实现和目标对象1样的接口,所以只需要拿到目标对象的实现接口
//第3个参数表明这些被拦截的方法在被拦截时需要履行哪一个InvocationHandler的invoke方法
//根据传入的目标返回1个代理对象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//关联的这个实现类的方法被调用时将被履行
// InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start-->>");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret=null;
try{
//原对象方法调用前处理日志信息
System.out.println("satrt-->>");
//保存处理信息
//abstractApprove();
// 2,办应当前任务,调用完成当前结点
ProcessInstance pi=jbpmService.completeTask(taskId, outcome);
//调用工作流的操作
if(approval==false){
if (pi != null) { // 如果流程还未结束
//结束当前流程
jbpmService.endProcessInstance(pi);
}
}
//调用目标方法
ret=method.invoke(targetObject, args);
//调用工作流,每一个都实现这么1个接口就能够,判断是不是要修改
isEnd(pi);
//原对象方法调用后处理日志信息
System.out.println("success-->>");
}catch(Exception e){
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}
}
// 抽象方法,实现保存处理信息,和设置同意不同意,但不需要更新
protected abstract void abstractApprove()throws Exception;
// 抽象方法,如果为最后的结点且同意了,那末需要更新的数据表
protected abstract void isEnd(ProcessInstance pi);
//-----------
public String getOutcome() {
return outcome;
}
public void setOutcome(String outcome) {
this.outcome = outcome;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public boolean isApproval() {
return approval;
}
public void setApproval(boolean approval) {
this.approval = approval;
}
}
注:以上的代理使用了两种方式传值,由于java不支持多重继承,故第1种方式更好些,但是第2种方式传值更加简单,大家根据需要来选择便可!
以上这两个是抽象出来的代理类,那末它起到了甚么作用呢?
下面我们来1起看看它们的利用:
对应启动节点:
/** 提交申请 ,启开工作流--想成是宿主程序*/
public String edit() throws Exception {
Long stuCourseId=model.getId();
//提交申请
//封装申请信息,学生的申请信息
StuCourseApply stuCourseApply = new StuCourseApply();
stuCourseApply.setStuCourseId(stuCourseId);
newCourse=new String(newCourse.getBytes("iso⑻859⑴"),"utf⑻");
newTeacher=new String(newTeacher.getBytes("iso⑻859⑴"),"utf⑻");
stuCourseApply.setApplicant(getCurrentUser()); // 申请人,当前用户
stuCourseApply.setOldCourse(model.getCourse());
stuCourseApply.setNewCourse(newCourse);
stuCourseApply.setNewTeacher(newTeacher);
stuCourseApply.setOldTeacher(model.getTeacher());
stuCourseApply.setTitle("修改课程信息");
String processDefinitionKeyStr=new String(processDefinitionKey.getBytes("iso⑻859⑴"),"utf⑻");
stuCourseApply.setProcessDefinitionKey(processDefinitionKeyStr);
// 调用业务方法(保存申请信息)
// 1,设置属性并保存stuCourseApply
stuCourseApply.setApplyTime(sdf.format(new Date())); // 申请时间,当前时间
stuCourseApply.setStatus(StuCourseApply.STATUS_RUNNING);
//两次保存?
stuCourseApplyService.save(stuCourseApply);
// 2, 准备流程变量
Map<String, Object> variablesMap = new HashMap<String, Object>();
variablesMap.put("stuCourseApply", stuCourseApply);
//获得流程定义的key
String pdKey = stuCourseApply.getProcessDefinitionKey();
// 3,启动流程实例开始流转,并带上流程变量(当前的申请信息),调用宿主程序
// 调用业务,保存申请信息
startAbstractJBPM.common(pdKey, variablesMap, jbpmService);
StartAbstractJBPM.LogHandler1 logHandler = startAbstractJBPM.new LogHandler1();
//放到代理中设置值了
//stuCourseApply.setExecuteId(pi.getId());
StuCourseApplyService stuCourseApplyService1=(StuCourseApplyService)logHandler.newProxyInstanceStart(stuCourseApplyService);
stuCourseApplyService1.save(stuCourseApply);
return "toStuApplicationList"; // 成功后转到"我的申请查询"
}
对应办理节点:
/** 审批处理 */
public String approve() throws Exception {
abstractApprove();
// 利用代理
LogHandler logHandler=new LogHandler();
// 调用业务,更新状态,更新状态之前会先调用工作流的完成当前任务方法
StuCourseApplyService stuCourseApplyService1=(StuCourseApplyService)logHandler.newProxyInstance(stuCourseApplyService);
stuCourseApplyService1.update(stuCourseApply);
return "toStuTaskList"; // 成功后转到待我审批页面
}
通过这两段代码,相信大家可以看出在这两段代码中已不存在工作流的任何内容,而此时我们的流程却仍然被工作流来管理着,也就是我们将所有有关工作流的方法均抽象出来,让我们的类单纯的应对业务,在调用业务的方法时我们调用代理,而此时的代理中已将工作流的启动办理等1系列操作封装进去,在我们调用代理方法时已启动了工作流,再处理时也操作了工作流的办理,故全部业务流程在我们无需了解工作流的情况下就已实现了被流程管理。
我们1直在说AOP,那末甚么是AOP?
AOP(AspectOrientedProgramming):将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行动的分离,我们希望可以将它们独立到非指点业务逻辑的方法中,进而改变这些行动的时候不影响业务逻辑的代码---两个字概括:解耦。
总结:
最想说的1句话:会者不难,难者不会。在学习工作流的这段期间,各种的不理解,各种的质疑自己,这个是AOP吗?这样做是我们想要的吗?有时候仍会问自己甚么是工作流,说到底它到底给我们带来了甚么好处?
工作流(Workflow),就是“业务进程的部份或整体在计算机利用环境下的自动化”,它主要解决的是“使在多个参与者之间依照某种预定义的规则自动进行传递文档、信息或任务的进程,从而实现某个预期的业务目标,或促使此目标的实现”这段话说的真的很棒,但是我觉得我们要做到的不单单是这些,要补充的1点就是实现工作流的AOP!