zoukankan      html  css  js  c++  java
  • Liferay7 BPM门户开发之5: Activiti和Spring集成

    参考文档:

    https://github.com/jbarrez/spring-boot-with-activiti-example
    https://github.com/sxyx2008/spring-activiti-webapp
    http://www.cnblogs.com/hongwz/p/5548473.html

    Spring典型配置

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
    <property name="driverClass" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
    <property name="username" value="sa" />
    <property name="password" value="" />
    </bean>
    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
    </bean>
    
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    <property name="dataSource" ref="dataSource" />
    <property name="transactionManager" ref="transactionManager" />
    <property name="databaseSchemaUpdate" value="true" />
    <property name="jobExecutorActivate" value="false" />
    </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" />
    
    ...

    自定义的实体类可以这么设置:

    <beans>
    ...
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <bean id="userBean" class="org.activiti.spring.test.UserBean">
    <property name="runtimeService" ref="runtimeService" />
    </bean>
    
    <bean id="printer" class="org.activiti.spring.test.Printer" />
    
    </beans>

    写注解:

    @ContextConfiguration("classpath:org/activiti/spring/test/transaction/SpringTransactionIntegrationTest-context.xml")

    然后就可以访问Activiti的工厂类和自定义的实体类,
    比如RepositoryService的实例这样获得,同时这也是Spring集成环境下的bpmn文件的部署方式:

    RepositoryService repositoryService =
    (RepositoryService) applicationContext.getBean("repositoryService");
    String deploymentId = repositoryService
    .createDeployment()
    .addClasspathResource("org/activiti/spring/test/hello.bpmn20.xml")
    .deploy()
    .getId();

    new 一个自定义的实体类实例:

    UserBean userBean = (UserBean) applicationContext.getBean("userBean");
    userBean.hello();

    自定义的实体类:

    public class UserBean {
    
    /** Spring 注入 */
    private RuntimeService runtimeService;
    
    @Transactional
    public void hello() {
    runtimeService.startProcessInstanceByKey("helloProcess");
    }
    
    public void setRuntimeService(RuntimeService runtimeService) {
    this.runtimeService = runtimeService;
    }
    }

    表达式

    在流程定义文件bpmn20.xml使用表达式

    表达式可以灵活动态的使用类的方法,他可以实现流程计算逻辑和实体类的解耦,说具体些就是流程定义文件可以不用Hardcode了,直接通过接口调用的形式访问具体的类,
    举例,定义一个输出打印的类,

    public class Printer {
    
    public void printMessage() {
      System.out.println("hello world");
    }
    }

    在Spring里注册:

    <beans>
    ...
    
    <bean id="printer" class="org.activiti.examples.spring.Printer" />
    
    </beans>

    建立关联配置:

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    ...
    <property name="beans">
    <map>
    <entry key="printer" value-ref="printer" />
    </map>
    </property>
    </bean>

    最后,就可以在流程定义文件bpmn20.xml使用表达式,定义了一个serviceTask:
    这种调用方法非常灵活,也是集成Spring高效和方便的地方

    <definitions id="definitions">
    
    <process id="helloProcess">
    
    <startEvent id="start" />
    <sequenceFlow id="flow1" sourceRef="start" targetRef="print" />
    
    <serviceTask id="print" activiti:expression="#{printer.printMessage()}" />
    <sequenceFlow id="flow2" sourceRef="print" targetRef="end" />
    
    <endEvent id="end" />
    
    </process>
    
    </definitions>

    使用Spring自动部署bpmn20.xml
    仅当文件变化的时候,才会被重新部署,特别方便用于系统调试,程序员必备

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
    ...
    <property name="deploymentResources"
    value="classpath*:/org/activiti/spring/test/autodeployment/autodeploy.*.bpmn20.xml" />
    </bean>
    
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
    <property name="processEngineConfiguration" ref="processEngineConfiguration" />
    </bean>

    可以使用通配符

    <property name="deploymentResources" value="classpath*:/activiti/*.bpmn" />
    <property name="deploymentMode" value="single-resource" />

    Hibernate 4.2.x集成

    POM:

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${org.springframework.version}</version>
    </dependency>
    
    <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.183</version>
    </dependency>

    配置是不是很简单?

    然后就可以开发了

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan
    @EnableAutoConfiguration
    public class MyApplication {
    
    public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
    }
    
    @Bean
    public CommandLineRunner init(final RepositoryService repositoryService,
    final RuntimeService runtimeService,
    final TaskService taskService) {
    
    return new CommandLineRunner() {
    @Override
    public void run(String... strings) throws Exception {
    System.out.println("Number of process definitions : "
    + repositoryService.createProcessDefinitionQuery().count());
    System.out.println("Number of tasks : " + taskService.createTaskQuery().count());
    runtimeService.startProcessInstanceByKey("oneTaskProcess");
    System.out.println("Number of tasks after process start: " + taskService.createTaskQuery().count());
    }
    };
    
    }
    }

    使用MySQL数据库
    POM:

    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.34</version>
    </dependency>
    <dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jdbc</artifactId>
    <version>8.0.15</version>
    </dependency>

    数据源

    @Bean
    public DataSource database() {
    return DataSourceBuilder.create()
    .url("jdbc:mysql://127.0.0.1:3306/activiti-spring-boot?characterEncoding=UTF-8")
    .username("alfresco")
    .password("alfresco")
    .driverClassName("com.mysql.jdbc.Driver")
    .build();
    }

    REST开发扩展

    Spring Boot可以快速开发web api接口,REST对集成第三方应用非常重要
    POM:

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>${spring.boot.version}</version>
    </dependency>

    开发服务类,服务类是用于控制器的重复调用,即帮助类

    @Service
    public class MyService {
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Transactional
    public void startProcess() {
    runtimeService.startProcessInstanceByKey("oneTaskProcess");
    }
    
    @Transactional
    public List<Task> getTasks(String assignee) {
    return taskService.createTaskQuery().taskAssignee(assignee).list();
    }
    
    }

    控制器:
    注意:启动流程使用POST,获取任务使用了GET,在输出时自动把实体类(TaskRepresentation)转换为JSON格式

    @RestController
    public class MyRestController {
    
    @Autowired
    private MyService myService;
    
    @RequestMapping(value="/process", method= RequestMethod.POST)
    public void startProcessInstance() {
    myService.startProcess();
    }
    
    @RequestMapping(value="/tasks", method= RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
    public List<TaskRepresentation> getTasks(@RequestParam String assignee) {
    List<Task> tasks = myService.getTasks(assignee);
    List<TaskRepresentation> dtos = new ArrayList<TaskRepresentation>();
    for (Task task : tasks) {
    dtos.add(new TaskRepresentation(task.getId(), task.getName()));
    }
    return dtos;
    }
    
    static class TaskRepresentation {
    
    private String id;
    private String name;
    
    public TaskRepresentation(String id, String name) {
    this.id = id;
    this.name = name;
    }
    
    public String getId() {
    return id;
    }
    public void setId(String id) {
    this.id = id;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    
    }
    
    }

    需要注意@ComponentScan一定在加在application类的注解

    测试:
    curl -X POST http://localhost:8080/process
    curl http://localhost:8080/tasks?assignee=kermit
    [{"id":"10004","name":"my task"}]

    JPA支持

    默认JPA是Hibernate

    POM:

    <dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter-jpa</artifactId>
    <version>${activiti.version}</version>
    </dependency>

    实体类:

    @Entity
    class Person {
    
    @Id
    @GeneratedValue
    private Long id;
    
    private String username;
    
    private String firstName;
    
    private String lastName;
    
    private Date birthDate;
    
    public Person() {
    }
    
    public Person(String username, String firstName, String lastName, Date birthDate) {
    this.username = username;
    this.firstName = firstName;
    this.lastName = lastName;
    this.birthDate = birthDate;
    }
    
    public Long getId() {
    return id;
    }
    
    public void setId(Long id) {
    this.id = id;
    }
    
    public String getUsername() {
    return username;
    }
    
    public void setUsername(String username) {
    this.username = username;
    }
    
    public String getFirstName() {
    return firstName;
    }
    
    public void setFirstName(String firstName) {
    this.firstName = firstName;
    }
    
    public String getLastName() {
    return lastName;
    }
    
    public void setLastName(String lastName) {
    this.lastName = lastName;
    }
    
    public Date getBirthDate() {
    return birthDate;
    }
    
    public void setBirthDate(Date birthDate) {
    this.birthDate = birthDate;
    }
    }

    如果不使用in-memory数据库,数据表不会自动建立,需要 application.properties 增加配置:
    spring.jpa.hibernate.ddl-auto=update

    增加接口:

    public interface PersonRepository extends JpaRepository<Person, Long> {
    
    Person findByUsername(String username);
    
    }

    服务类:

    @Service
    @Transactional
    public class MyService {
    
    @Autowired
    private RuntimeService runtimeService;
    
    @Autowired
    private TaskService taskService;
    
    @Autowired
    private PersonRepository personRepository;
    
    public void startProcess(String assignee) {
    
    Person person = personRepository.findByUsername(assignee);
    
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("person", person);
    runtimeService.startProcessInstanceByKey("oneTaskProcess", variables);
    }
    
    public List<Task> getTasks(String assignee) {
    return taskService.createTaskQuery().taskAssignee(assignee).list();
    }
    
    public void createDemoUsers() {
    if (personRepository.findAll().size() == 0) {
    personRepository.save(new Person("jbarrez", "Joram", "Barrez", new Date()));
    personRepository.save(new Person("trademakers", "Tijs", "Rademakers", new Date()));
    }
    }
    
    }

    在CommandLineRunner 初始化的时候,添加用户持久化数据(createDemoUsers())

    @Bean
    public CommandLineRunner init(final MyService myService) {
    
    return new CommandLineRunner() {
    public void run(String... strings) throws Exception {
      myService.createDemoUsers();
    }
    };
    
    }

    控制器:

    @RestController
    public class MyRestController {
    
    @Autowired
    private MyService myService;
    
    @RequestMapping(value="/process", method= RequestMethod.POST)
    public void startProcessInstance(@RequestBody StartProcessRepresentation startProcessRepresentation) {
    myService.startProcess(startProcessRepresentation.getAssignee());
    }
    
    ...
    
    static class StartProcessRepresentation {
    
    private String assignee;
    
    public String getAssignee() {
    return assignee;
    }
    
    public void setAssignee(String assignee) {
    this.assignee = assignee;
    }
    }

    流程定义再一次使用了表达式:

    <userTask id="theTask" name="my task" activiti:assignee="${person.id}"/>

    测试:POST一个流程启动者的username
    curl -H "Content-Type: application/json" -d '{"assignee" : "jbarrez"}' http://localhost:8080/process
    curl http://localhost:8080/tasks?assignee=1

    [{"id":"12505","name":"my task"}]

    更高级的内容可以自行研究:

    • Actuator support
    • Spring Integration support
    • Rest API integration
    • Spring Security support
  • 相关阅读:
    面试:div水平垂直居中方案--img自适应
    面试:call、apply、bind原理以及自己手写简易模式
    面试之:判断js类型的方式总结
    git的项目完整操作
    vue3.x版本新建项目相关知识和注意事项
    面试常问平时项目中【Date】的常用操作方法总结
    面试常问平时项目中【Math】的常用操作方法总结
    面试常问平时项目中数组【Array】的常用操作方法总结
    面试常问平时用的对象【Object】的创建方式和常用的对象方法总结
    优化无限列表性能vue-virtual-scroll-list【测试90w条数据】
  • 原文地址:https://www.cnblogs.com/starcrm/p/5948485.html
Copyright © 2011-2022 走看看