【整合篇】Activiti业务与流程的整合

2023-05-07,,

对于不管是Activtit还是jbpm来说,业务流程整合均类似。启动流程是绑定业务。流程与业务的整合放到动态代理中

[java] view
plain copy

print

" style="text-decoration:none; background-color:inherit; border:none; padding:0px; margin:0px 10px 0px 0px; font-size:9px; color:rgb(12,137,207)">?

    /**
    * 启动改动课程流程Leave leave,
    *
    * @param leave
    */
    @RequestMapping(value = "start", method = RequestMethod.POST)
    public String startWorkflow(Leave leave,RedirectAttributes redirectAttributes, HttpSession session) {
    try {
    User user = UserUtil.getUserFromSession(session);
    // 用户未登录不能操作,实际应用使用权限框架实现,比如Spring Security、Shiro等
    if (user == null || StringUtils.isBlank(user.getId())) {
    return "redirect:/login?timeout=true";
    }
    leave.setUserId(user.getId());
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("leave", leave);
    //保存业务实体
    leave.setTestId(new Date().toString());
    leaveBean.saveBeforeEntity(leave);
    Leave Leavetest=null;
    Leavetest=leaveBean.queryByTestid(leave.getTestId());
    leave=Leavetest;
    logger.debug("save entity: {}", leave);
    //不再获取id,改为获取类  .getClass().getSimpleName().toString();
    //String businessKey = "leave";
    String businessKey = leave.getId().toString();
    ProcessInstance processInstance = null;
    /*加入的代码--begin--Proxy*/
    // 调用业务,保存申请信息
    startNode.common(businessKey, variables,runtimeService,identityService);
    LogHandler1 logHandler = startNode.new LogHandler1();
    //放到代理中设置值了
    //stuCourseApply.setExecuteId(pi.getId());
    LeaveBean leaveBeanProxy=(LeaveBean)logHandler.newProxyInstanceStart(leaveBean);
    leaveBeanProxy.updeatChangeApply(leave);
    /*加入的代码--end--Proxy*/
    /*放到代理中--begin--Proxy*/
    /* try {
    // 用来设置启动流程的人员ID,引擎会自己主动把用户ID保存到activiti:initiator中
    identityService.setAuthenticatedUserId(leave.getUserId());
    processInstance = runtimeService.startProcessInstanceByKey("easyChangeCourse", businessKey, variables);
    String processInstanceId = processInstance.getId();
    leave.setProcessInstanceId(processInstanceId);
    logger.debug("start process of {key={}, bkey={}, pid={}, variables={}}", new Object[]{"easyChangeCourse", processInstanceId, variables});
    } finally {
    identityService.setAuthenticatedUserId(null);
    }*/
    /*放到代理中--end--Proxy*/
    //+ processInstance.getId()
    redirectAttributes.addFlashAttribute("message", "流程已启动" );
    } catch (ActivitiException e) {
    if (e.getMessage().indexOf("no processes deployed with key") != -1) {
    logger.warn("没有部署流程!", e);
    redirectAttributes.addFlashAttribute("error", "没有部署流程,请在[工作流]->[流程管理]页面点击<又一次部署流程>");
    } else {
    logger.error("启动请假流程失败:", e);
    redirectAttributes.addFlashAttribute("error", "系统内部错误!

    ");
    }
    } catch (Exception e) {
    logger.error("启动请假流程失败:", e);
    redirectAttributes.addFlashAttribute("error", "系统内部错误!

    ");
    }
    return "redirect:/oa/leave/apply";
    }

动态代理:

[java] view
plain copy

print?

    package com.tgb.itoo.activiti.controller;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Map;
    import org.activiti.engine.IdentityService;
    import org.activiti.engine.RuntimeService;
    import org.activiti.engine.runtime.ProcessInstance;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Transactional;
    import com.tgb.itoo.basic.entity.Leave;
    @Component
    @Transactional
    public class StartNode{
    private Logger logger = LoggerFactory.getLogger(getClass());
    //定义一个属性变量
    private Map<String, Object> variables;
    private String businessKey;
    //设置人人员
    protected IdentityService identityService;
    @Autowired
    public void setIdentifyService(IdentityService identityService) {
    this.identityService = identityService;
    }
    protected RuntimeService runtimeService;
    @Autowired
    public void setRuntimeService(RuntimeService runtimeService) {
    this.runtimeService = runtimeService;
    }
    @Autowired
    RuntimeService runtimeService1;
    public void common(String businessKey,Map<String, Object> variables,RuntimeService runtimeService,IdentityService identityService){
    this.variables=variables;
    this.businessKey=businessKey;
    this.runtimeService=runtimeService;
    this.identityService=identityService;
    }
    //想尝试是否能依据其它方式传參。new的话太耗费资源
    /*public StartAbstractJBPM(String pdKey,Map<String, Object> variablesMap,JBPMService jbpmService){
    this.variablesMap=variablesMap;
    this.pdKey=pdKey;
    this.jbpmService=jbpmService;
    }*/
    //动态代理类仅仅能代理接口(不支持抽象类),代理类都须要实现InvocationHandler类,实现invoke方法。

    该invoke方法就是调用被代理接口的全部方法时须要调用的,该invoke方法返回的值是被代理接口的一个实现类
    public class LogHandler1 implements InvocationHandler{
    // 目标对象
    private Object targetObject;
    //绑定关系,也就是关联到哪个接口(与详细的实现类绑定)的哪些方法将被调用时,运行invoke方法。
    public Object newProxyInstanceStart(Object targetObject){
    this.targetObject=targetObject;
    //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
    //第一个參数指定产生代理对象的类载入器,须要将其指定为和目标对象同一个类载入器
    //第二个參数要实现和目标对象一样的接口,所以仅仅须要拿到目标对象的实现接口
    //第三个參数表明这些被拦截的方法在被拦截时须要运行哪个InvocationHandler的invoke方法
    //依据传入的目标返回一个代理对象
    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-->>");
    //启动流程
    //调用目标方法
    Leave leave=(Leave)args[0];
    // 用来设置启动流程的人员ID,引擎会自己主动把用户ID保存到activiti:initiator中
    try {
    identityService.setAuthenticatedUserId(leave.getUserId());
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ChangeCourse", businessKey, variables);
    String processInstanceId = processInstance.getId();
    leave.setProcessInstanceId(processInstanceId);
    logger.debug("start process of {key={}, bkey={}, pid={}, variables={}}", new Object[]{"ChangeCourse", processInstanceId, variables});
    } finally {
    identityService.setAuthenticatedUserId(null);
    }
    args[0]=leave;
    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;
    }
    }
    }

[java] view
plain copy

print?

    /**
    * 任务列表ERROR [stderr] (http-localhost/127.0.0.1:8080-3) ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider com.sun.script.javascript.RhinoScriptEngineFactory not found
    *
    * @param leave
    */
    @RequestMapping(value = "list/task")
    public ModelAndView taskList(HttpSession session, HttpServletRequest request) {
    List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
    String userId = UserUtil.getUserFromSession(session).getId();
    results=abstractTaskList(userId);
    return new ModelAndView("/oa/leave/taskList","results",results);
    }

[java] view
plain copy

print?

    /**
    * 抽象出来的查看任务列表。与基本业务无关
    *
    * @param userId 用户id
    * @return
    */
    public List<Map<String, Object>> abstractTaskList(String userId){
    List<Leave> results = new ArrayList<Leave>();
    // 依据当前人的ID查询
    TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateOrAssigned(userId);
    List<Task> tasks = taskQuery.list();
    int i=0;
    List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
    // 依据流程的业务ID查询实体并关联
    for (Task task : tasks) {
    String processInstanceId = task.getProcessInstanceId();
    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).active().singleResult();
    String businessKey = processInstance.getBusinessKey();
    if (businessKey == null) {
    continue;
    }
    Map<String, Object> map = new HashMap<String, Object>();
    Leave leave = leaveBean.findEntityById(businessKey);
    //leave.setProcessInstance(processInstance);
    //leave.setProcessDefinition(getProcessDefinition(processInstance.getProcessDefinitionId()));
    //leave.setTask(task);
    map.put("leave", leave);//存入“申请信息”
    map.put("task", task);
    map.put("processDefinition", getProcessDefinition(processInstance.getProcessDefinitionId()));
    map.put("processInstance", processInstance);//存入“流程实例”
    mapList.add(map);
    /*Leave leave=updateEntity(processInstance,task,businessKey);
    results.add(leave); */
    i=i+1;
    }
    return mapList;
    }

[java] view
plain copy

print?

    /**
    * 读取执行中的流程实例(查看我的申请)involvedUser(userId)(涉及到的用户)
    *
    * @return
    */
    @RequestMapping(value = "list/running")
    public ModelAndView runningList(HttpSession session,HttpServletRequest request) {
    String userId = UserUtil.getUserFromSession(session).getId();
    List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
    results=abstractRuningList(userId);
    return new ModelAndView ("/oa/leave/running","results",results);
    }

[java] view
plain copy

print

" style="text-decoration:none; background-color:inherit; border:none; padding:0px; margin:0px 10px 0px 0px; font-size:9px; color:rgb(12,137,207)">?

    /**
    * 抽象出来读取执行中的流程实例(查看我的申请)。与基本业务无关
    *
    * @param userId 用户id
    * @return
    */
    public List<Map<String, Object>> abstractRuningList(String userId){
    List<Leave> results = new ArrayList<Leave>();
    ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processDefinitionKey("ChangeCourse").involvedUser(userId).active().orderByProcessInstanceId().desc();//依据流程定义Key查询流程实例
    List<ProcessInstance> list = query.list();
    List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
    // 关联业务实体
    for (ProcessInstance processInstance : list) {
    String businessKey = processInstance.getBusinessKey();
    if (businessKey == null) {
    continue;
    }
    // 设置当前任务信息
    List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstance.getId()).active().orderByTaskCreateTime().desc().listPage(0, 1);
    Map<String, Object> map = new HashMap<String, Object>();
    Leave leave = leaveBean.findEntityById(businessKey);
    /*leave.setProcessInstance(processInstance);
    leave.setProcessDefinition(getProcessDefinition(processInstance.getProcessDefinitionId()));
    leave.setTask(tasks.get(0));*/
    map.put("leave", leave);//存入“考试信息”
    map.put("task", tasks.get(0));
    map.put("processDefinition", getProcessDefinition(processInstance.getProcessDefinitionId()));
    map.put("processInstance", processInstance);//存入“流程实例”
    mapList.add(map);
    /*Leave leave=updateEntity(processInstance,task,businessKey);
    results.add(leave); */
    //Leave leave=updateEntity(processInstance,tasks.get(0),businessKey);
    }
    return mapList;
    }

[java] view
plain copy

print?

    /**
    * 读取完毕的流程实例(已经完毕的流程申请-我)
    *
    * @return
    */
    @RequestMapping(value = "list/finished")
    public ModelAndView finishedList(HttpSession session,HttpServletRequest request) {
    String userId = UserUtil.getUserFromSession(session).getId();
    List<Leave> results = new ArrayList<Leave>();
    HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("ChangeCourse").involvedUser(userId).finished().orderByProcessInstanceEndTime().desc();
    List<HistoricProcessInstance> list = query.list();
    List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
    // 关联业务实体
    for (HistoricProcessInstance historicProcessInstance : list) {
    Map<String, Object> map = new HashMap<String, Object>();
    String businessKey = historicProcessInstance.getBusinessKey();
    Leave leave = leaveBean.findEntityById(businessKey);
    /* leave.setProcessDefinition(getProcessDefinition(historicProcessInstance.getProcessDefinitionId()));
    leave.setHistoricProcessInstance(historicProcessInstance);
    results.add(leave);*/
    map.put("leave", leave);//存入“申请信息”
    map.put("processDefinition", getProcessDefinition(historicProcessInstance.getProcessDefinitionId()));
    map.put("historicProcessInstance", historicProcessInstance);//存入“流程实例”
    mapList.add(map);
    }
    return new ModelAndView("/oa/leave/finished","results",mapList);
    }

[java] view
plain copy

print?

    /**
    * 完毕任务
    *
    * @param id
    * @return
    */
    @RequestMapping(value = "/complete/{id}", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String complete(@PathVariable("id") String taskId, Variable var) {
    try {
    //deptLeaderPass=true or  hrBackReason=666, hrPass=false-----{leaderBackReason=78, deptLeaderPass=false}
    Map<String, Object> variables = var.getVariableMap();
    //taskService.getVariables(taskId);
    //Object variablesResult=variables.get("deptLeaderPass");
    //variablesResult=variables.get("hrPass");
    taskService.complete(taskId, variables);
    //获取map中的值
    //            if(hrPass=true){
    //              //更新业务表信息
    //            }
    return "success";
    } catch (Exception e) {
    logger.error("error on complete task {}", new Object[]{taskId, e});
    return "error";
    }
    }

总结:

对于在流程与业务的整合中应用动态代理也不知道是否符合AOP的理念,类似其它方面的流程操作还未抽取出来(交互太多),在这里记录一下学习Activiti的一个过程,在之后的尝试中能够换个方式。换个思路,直接将整个工作流应用抽取出来(请假,改动课程等)。

【整合篇】Activiti业务与流程的整合的相关教程结束。

《【整合篇】Activiti业务与流程的整合.doc》

下载本文的Word格式文档,以方便收藏与打印。