SpringBoot1.5.8 +Activiti6 +MySQL8 +Druid +Thymeleaf

项目整体结构图:

pom.xml添加相关依赖:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.zzg</groupId>
    <artifactId>zzg-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>zzg-activity</artifactId>
  
  	<!-- 版本集中管理  -->
	<properties>
		<javax.servlet-api.version>3.1.0</javax.servlet-api.version>
		<mybatis-spring-boot-starter.version>1.3.2</mybatis-spring-boot-starter.version>
		<mysql-connector-java.version>8.0.11</mysql-connector-java.version>
		<druid-spring-boot-starter.version>1.1.9</druid-spring-boot-starter.version>
		<activiti-spring-boot-starter-basic.version>6.0.0</activiti-spring-boot-starter-basic.version>
	</properties>

	<dependencies>
		<!--springboot web 基础模块 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--servlet-api -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${javax.servlet-api.version}</version>
		</dependency>
		<!--mybatis orm 模块  -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>${mybatis-spring-boot-starter.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql-connector-java.version}</version>
			<scope>runtime</scope>
		</dependency>
		<!--数据库连接池druid 模块  -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>${druid-spring-boot-starter.version}</version>
		</dependency>
		<!-- activiti 工作流程引擎  -->
		<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-basic</artifactId>
            <version>${activiti-spring-boot-starter-basic.version}</version>
        </dependency>
        <!-- Thymeleaf 模板引擎  -->
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
	</dependencies>
</project>

application.properties配置文件

# 指定服务端口
server.port=9092
# 指定服务 名称
# server.context-path=/ureport
#mybatis xml 文件配置
mybatis.mapper-locations=classpath*:mapper/*Mapper.xml
# MyBatis mysql8 配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/activiti?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&nullCatalogMeansCurrent=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Druid 配置
# 初始化时建立物理连接的个数
spring.datasource.druid.initial-size=5
# 最大连接池数量
spring.datasource.druid.max-active=30
# 最小连接池数量
spring.datasource.druid.min-idle=5
# 获取连接时最大等待时间,单位毫秒
spring.datasource.druid.max-wait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.druid.time-between-eviction-runs-millis=60000
# 连接保持空闲而不被驱逐的最小时间
spring.datasource.druid.min-evictable-idle-time-millis=300000
# 用来检测连接是否有效的sql,要求是一个查询语句
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
spring.datasource.druid.test-while-idle=true
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
spring.datasource.druid.test-on-borrow=false
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
spring.datasource.druid.test-on-return=false
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
spring.datasource.druid.pool-prepared-statements=true
# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=50
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计
#spring.datasource.druid.filters=stat,wall
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# 合并多个DruidDataSource的监控数据
spring.datasource.druid.use-global-data-source-stat=true
# 配置sql 注入方式
spring.datasource.druid.filters=stat,log4j

#日志文件配置
logging.config=classpath:logback.xml

#activiti 工作流程引擎
#自动检查、部署流程定义文件
spring.activiti.check-process-definitions=true
#自动更新数据库结构
spring.activiti.database-schema-update=false
#流程定义文件存放目录
spring.activiti.process-definition-location-prefix=classpath*:processes/

#thymeleaf 模板引擎配置
# 开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
# 访问template下的html文件需要配置模板,映射
spring.thymeleaf.prefix.classpath=/templates
spring.thymeleaf.suffix=.html

程序入口Applciation:

import org.activiti.spring.boot.SecurityAutoConfiguration;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication(exclude=SecurityAutoConfiguration.class)
@EnableTransactionManagement
@MapperScan("com.digipower.ucas.mapper")
public class Application extends SpringBootServletInitializer {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SpringApplication.run(Application.class, args);
	}
	
	@Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        // 注意这里要指向原先用main方法执行的Application启动类
        return builder.sources(Application.class);
    }
}

Drudid 配置对象:

import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;

/**
 * Druid 配置对象
 * @author zzg
 *
 */
@Configuration
public class DruidConfig {
	@Bean
    public ServletRegistrationBean druidServletRegistrationBean() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");
        servletRegistrationBean.addInitParameter("allow", "");
        servletRegistrationBean.addInitParameter("deny", "");
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "admin");
        return servletRegistrationBean;
    }

    /**
     * 注册DruidFilter拦截
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean duridFilterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        Map<String, String> initParams = new HashMap<String, String>();
        //设置忽略请求
        initParams.put("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.setInitParameters(initParams);
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }

}

thymeleaf 示列Controller

import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/api/thymeleaf")
public class ThymeleafController {

	@RequestMapping("/index")
	public String index(Map<String, String> map) {
		map.put("username", "深圳世纪位图");
		return "index";
	}
}

thymeleaf 模板文件(/template/index.html)

<!DOCTYPE html>
<!-- 引入thymeleaf 的名称空间 -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Thymeleaf 模板引擎</title>
</head>
<body>
    <h2>Hello <span th:text="${username}">这里用于显示用户名</span></h2>
</body>
</html>

logback.xml 日志文件配置

<?xml version="1.0" encoding="UTF-8"?> 
  
<!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->  
<!-- 日志输出规则  根据当前ROOT 级别,日志输出时,级别高于root默认的级别时  会输出 -->  
<!-- 以下  每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志-->  
  
  
<!-- 属性描述 scan:性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,
默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。   
    debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->  
<configuration scan="true" scanPeriod="60 seconds" debug="false">  
    <!-- 定义日志文件 输入位置 -->  
    <property name="log_dir" value="/logs/activity" />  
    <!-- 日志最大的历史 30天 -->  
    <property name="maxHistory" value="30"/>  
  
  
    <!-- ConsoleAppender 控制台输出日志 -->  
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
        <!-- 对日志进行格式化 -->  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- ERROR级别日志 -->  
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender-->  
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 过滤器,只记录WARN级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>ERROR</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--日志输出位置  可相对、和绝对路径 -->  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-error-log.log</fileNamePattern>  
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6,  
            则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除-->  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
          
        <!-- 按照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。   
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">     
          <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/.log.zip</fileNamePattern>     
          <minIndex>1</minIndex>     
          <maxIndex>3</maxIndex>     
        </rollingPolicy>   -->  
        <!-- 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动   
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">     
            <maxFileSize>5MB</maxFileSize>     
        </triggeringPolicy>   -->  
          
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- WARN级别日志 appender -->  
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 过滤器,只记录WARN级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>WARN</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-warn-log.log  
            </fileNamePattern>  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- INFO级别日志 appender -->  
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 过滤器,只记录INFO级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>INFO</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-info-log.log  
            </fileNamePattern>  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- DEBUG级别日志 appender -->  
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>DEBUG</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-debug-log.log  
            </fileNamePattern>  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
    
    <logger name="java.sql.PreparedStatement" value="DEBUG" />    
    <logger name="java.sql.Connection" value="DEBUG" />    
    <logger name="java.sql.Statement" value="DEBUG" />    
    <logger name="com.ibatis" value="DEBUG" />    
    <logger name="com.ibatis.common.jdbc.SimpleDataSource" value="DEBUG" />    
    <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG"/>    
    <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" value="DEBUG" />    
    <logger name="org.springframework.web" level="DEBUG"/>
    <logger name="com.zzg" level="DEBUG"/>
		
      
    <!-- root级别   DEBUG -->  
    <root level="ERROR">  
        <!-- 控制台输出 -->  
        <appender-ref ref="STDOUT" />  
        <!-- 文件输出 -->  
        <appender-ref ref="ERROR" />  
        <appender-ref ref="INFO" />  
        <appender-ref ref="WARN" />  
        <appender-ref ref="DEBUG" />  
    </root>  
</configuration>

Activiti 流程引擎示列类:

package com.digipower.controller;

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

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

import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/api/leave")
public class LeaveController {
	// 日志记录
	public static final Logger log = LoggerFactory.getLogger(LeaveController.class);

	@Autowired(required = false)
	private RuntimeService runtimeService;

	@Autowired(required = false)
	private TaskService taskService;

	@Autowired(required = false)
	private IdentityService identityService;

	@Autowired(required = false)
	private RepositoryService repositoryService;

	@Autowired(required = false)
	private ProcessEngine processEngine;

	@Autowired(required = false)
	private HistoryService historyService;

	/**
	 * 部署资源
	 * 
	 * @param request
	 * @param response
	 */
	@RequestMapping("/deploy")
	public void deploy(HttpServletRequest request, HttpServletResponse response) {
		Deployment deployment = processEngine.getRepositoryService()// 获取流程定义和部署对象相关的Service
				.createDeployment() // 创建一个部署的构建器
				.name("请假申请审核流程")// 设置流程的名称
				.addClasspathResource("processes/LeaveProcess.bpmn")// 加载资源文件,一次只能加载一个文件
				.addClasspathResource("processes/LeaveProcess.png").deploy();// 完成部署
		log.info("【部署的id】:{}", deployment.getId());
		log.info("【部署的名称】:{}", deployment.getName());
		log.info("【部署时间】:{}" + deployment.getDeploymentTime());
	}

	/**
	 * 查询部署的流程定义
	 * 
	 * @param request
	 * @param response
	 */
	@RequestMapping("/queryDeployProcess")
	public void queryDeployProcess(HttpServletRequest request, HttpServletResponse response) {
		RepositoryService repositoryService = processEngine.getRepositoryService();

		List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myProcess")
				.orderByProcessDefinitionVersion().desc().list();
		for (ProcessDefinition p : list) {
			log.info("------------------------");
			log.info("【流程部署id】:{}", p.getDeploymentId());
			log.info("【流程定义id】:{}", p.getId());
			log.info("【流程定义名称】:{}", p.getName());
			log.info("【流程定义key】:{}", p.getKey());
			log.info("【流程定义版本】:{}", p.getVersion());
		}
	}
	
	 /**
     * 删除部署的流程定义
     */
    @RequestMapping("/deleteDeployProcess")
    public void deleteDeployProcess(HttpServletRequest request, HttpServletResponse response) {
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 下面的参数是 DeploymentId
        repositoryService.deleteDeployment("***"); // 根据部署的id来删除
    }
    
    /**
     * @desc: 发起流程
     * @auth: cao_wencao
     * @date: 2020/1/9 15:54
     */
    @RequestMapping("/initProcess")
    public void initProcess(HttpServletRequest request, HttpServletResponse response) {
        log.debug("【流程开启开始执行】。。。。。。。。。");
        Map<String, Object> map = new HashMap<String, Object>();
        //流程图里写的${user} ,这里传进去user
        map.put("user", "周");

        //流程启动
        //指定流程的发起者 不指定发起者的字段就为空,注意跟审核人分开
        identityService.setAuthenticatedUserId("zhangsan");
        runtimeService.startProcessInstanceByKey("myProcess", map);
        ExecutionEntity pi = (ExecutionEntity) runtimeService.startProcessInstanceByKey("myProcess", map);
        log.info("启动流程成功!");

        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        log.info("任务ID: {}", task.getId());
        log.info("任务的办理人: {}", task.getAssignee());
        log.info("任务名称: {}", task.getName());
        log.info("任务的创建时间: {}", task.getCreateTime());
        log.info("流程实例ID: {}", task.getProcessInstanceId());

       
    }
    
    /**
     * @desc: 根据taskid审核任务
     * @auth: cao_wencao
     * @date: 2020/1/9 16:07
     */
    @RequestMapping("/audit")
    public void audit(HttpServletRequest request, HttpServletResponse response) {

        String taskId = request.getParameter("taskId");
        Map<String, Object> map2 = new HashMap<String, Object>();
        map2.put("projectUser", "黄");
        // 开启后,环节会走到发起请假请求,要完成这个环节,才能到下一个审核环节
        taskService.complete(taskId, map2);
        
    }
    
 // 通过用户名查询该用户的所有任务
    @RequestMapping("/checkByUser")
    @ResponseBody
    public String checkByUser(HttpServletRequest request, HttpServletResponse response) {
    	String user = request.getParameter("user");
        List<Task> tasks = taskService//与任务相关的Service
                .createTaskQuery()//创建一个任务查询对象
                .taskAssignee(user)
                .list();
        if (tasks != null && tasks.size() > 0) {
            for (Task task : tasks) {
                System.out.println("任务ID:" + task.getId());
                System.out.println("任务的办理人:" + task.getAssignee());
                System.out.println("任务名称:" + task.getName());
                System.out.println("任务的创建时间:" + task.getCreateTime());
                System.out.println("流程实例ID:" + task.getProcessInstanceId());
            }
        }
        return "success";
    }

}

Activiti 流程引擎资源文件(processes/LeaveProcess.bpmn 和processes/LeaveProcesses.png)

具体流程文件创建,请参考:com.zzg.mapping 代码文件夹和mapping/ucas 资源文件夹为MyBatis3 ORM 框架使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值