初始化提交

This commit is contained in:
2021-01-20 18:27:28 +08:00
commit e2c592fd4f
29 changed files with 1504 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
target/
**/target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
*.iml
.idea
modules/log
modules/logs
.project
.settings
.classpath
logs

1
README.md Normal file
View File

@ -0,0 +1 @@
协同办公框架端

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>business.chaoran</groupId>
<artifactId>cooperop-demo-base</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>business.chaoran</groupId>
<artifactId>cooperop-base-cache</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--redis序列化用fastjson业务返回Json还是用gson更加灵活-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,46 @@
package business.cooperop.base.cache.redis;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
/*
**********************************************
* DATE PERSON REASON
* 2020-09-27 FXY Created
**********************************************
*/
/**
* Fastjson集成 spring-data-redis 扩展
*
* @author FXY
* <p>
* 2018年1月23日
*/
public class ExtGenericFastJsonRedisSerializer extends GenericFastJsonRedisSerializer {
private static int NO_SkipTransientFieldFEATURE;
{
int features = SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.SkipTransientField, false);
NO_SkipTransientFieldFEATURE = SerializerFeature.config(features, SerializerFeature.WriteClassName, true);
}
@Override
public byte[] serialize(Object object) throws SerializationException {
if (object == null) {
return new byte[0];
}
try {
return JSON.toJSONBytes(object, NO_SkipTransientFieldFEATURE);
} catch (Exception ex) {
throw new SerializationException("Could not serialize: " + ex.getMessage(), ex);
}
}
}

View File

@ -0,0 +1,37 @@
package business.cooperop.base.cache.redis;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisManager redisManager(RedisTemplate redisTemplate) {
RedisManager redisManager = new RedisManager();
redisManager.setRedisTemplate(redisTemplate);
return redisManager;
}
@ConditionalOnMissingBean(RedisTemplate.class)
@Bean("redisTemplate")
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(factory);
StringRedisSerializer ss = new StringRedisSerializer();
//默认使用JdkSerializationRedisSerializer对value进行序列化
//如果想要保证redis中数据的可读性,可以自定义序列化方式
ExtGenericFastJsonRedisSerializer redisSerializer = new ExtGenericFastJsonRedisSerializer();
redisTemplate.setKeySerializer(ss);
redisTemplate.setValueSerializer(redisSerializer);
redisTemplate.setHashKeySerializer(ss);
redisTemplate.setHashValueSerializer(redisSerializer);
return redisTemplate;
}
}

View File

@ -0,0 +1,68 @@
package business.cooperop.base.cache.redis;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.util.concurrent.TimeUnit;
/**
* RedisManager
*
* @author FXY
* <p>
* 2018年1月23日
*/
public class RedisManager {
/**
* 默认过期时长,单位:秒
*/
public final static long DEFAULT_EXPIRE = 60 * 30 * 1;
/**
* 不设置过期时长
*/
public final static long NOT_EXPIRE = -1;
private RedisTemplate redisTemplate;
public void set(String key, Object value, long expire) {
try {
if (expire == NOT_EXPIRE) {
redisTemplate.opsForValue().set(key, value);
} else {
redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void set(String key, Object value) {
set(key, value, DEFAULT_EXPIRE);
}
public <T> T get(String key, Class<T> clazz) {
ValueOperations<String, T> operations = redisTemplate.opsForValue();
return operations.get(key);
}
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
public void delete(String key) {
redisTemplate.delete(key);
}
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
}

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>cooperop-demo-base</artifactId>
<groupId>business.chaoran</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<properties>
<mybatisplus-spring-boot-starter.version>3.4.0</mybatisplus-spring-boot-starter.version>
<mybatisplus.version>3.4.0</mybatisplus.version>
<lombok.version>1.18.12</lombok.version>
<druid.version>1.1.10</druid.version>
<spring-boot.version>2.2.7.RELEASE</spring-boot.version>
</properties>
<artifactId>cooperop-base-datasource</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- mybatis-plus begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus-spring-boot-starter.version}</version>
</dependency>
<!-- 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<!-- mybatis-plus end -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,18 @@
package business.cooperop.base.datasource.mysql.common;
/*
**********************************************
* DATE PERSON REASON
* 2020/7/24 FXY Created
**********************************************
*/
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MultiDataSource {
String name() default "main";
}

View File

@ -0,0 +1,121 @@
package business.cooperop.base.datasource.mysql.config;
/*
**********************************************
* DATE PERSON REASON
* 2020/7/24 FXY Created
**********************************************
*/
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.util.JdbcConstants;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
@Component
@ConfigurationProperties(prefix = "spring.datasource")
@Setter
@Getter
@Slf4j
public class DruidProperties {
public DruidProperties() {
log.info("default 数据源加载");
}
/**
* 数据源名称
*/
private String datasourceName = "main";
private String url;
private String username;
private String password;
/**
* 默认为 MYSQL 8.x 配置
*/
private String driverClassName;
private Integer initialSize = 10;
private Integer minIdle = 3;
private Integer maxActive = 60;
private Integer maxWait = 60000;
private Boolean removeAbandoned = true;
private Integer removeAbandonedTimeout = 180;
private Integer timeBetweenEvictionRunsMillis = 60000;
private Integer minEvictableIdleTimeMillis = 300000;
private String validationQuery = "SELECT 'x'";
private Boolean testWhileIdle = true;
private Boolean testOnBorrow = false;
private Boolean testOnReturn = false;
private Boolean poolPreparedStatements = true;
private Integer maxPoolPreparedStatementPerConnectionSize = 50;
private String filters = "stat";
public DruidDataSource config() {
DruidDataSource dataSource = new DruidDataSource();
return config(dataSource);
}
public DruidDataSource config(DruidDataSource dataSource) {
dataSource.setDbType(JdbcConstants.SQL_SERVER);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driverClassName);
dataSource.setInitialSize(initialSize); // 定义初始连接数
dataSource.setMinIdle(minIdle); // 最小空闲
dataSource.setMaxActive(maxActive); // 定义最大连接数
dataSource.setMaxWait(maxWait); // 获取连接等待超时的时间
dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收
dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 配置一个连接在池中最小生存的时间,单位是毫秒
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 用来检测连接是否有效的sql要求是一个查询语句
dataSource.setValidationQuery(validationQuery);
// 申请连接的时候检测
dataSource.setTestWhileIdle(testWhileIdle);
// 申请连接时执行validationQuery检测连接是否有效配置为true会降低性能
dataSource.setTestOnBorrow(testOnBorrow);
// 归还连接时执行validationQuery检测连接是否有效配置为true会降低性能
dataSource.setTestOnReturn(testOnReturn);
// 打开PSCache并且指定每个连接上PSCache的大小
dataSource.setPoolPreparedStatements(poolPreparedStatements);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
// 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
// 监控统计用的filter:stat
// 日志用的filter:log4j
// 防御SQL注入的filter:wall
try {
dataSource.setFilters(filters);
} catch (SQLException e) {
log.error("扩展插件失败.{}", e.getMessage());
}
return dataSource;
}
}

View File

@ -0,0 +1,52 @@
package business.cooperop.base.datasource.mysql.config;
/*
**********************************************
* DATE PERSON REASON
* 2020/7/24 FXY Created
**********************************************
*/
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* <p>多 datasource 的上下文</p>
* <p>每个线程独立的数据库连接名称</p>
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
/**
* @param dataSourceDbName 数据库别名
* @Description: 设置数据源别名
*/
public static void setDataSourceDbName(String dataSourceDbName) {
contextHolder.set(dataSourceDbName);
}
/**
* @Description: 获取数据源别名
*/
public static String getDataSourceDbName() {
return contextHolder.get();
}
/**
* @Description: 清除数据源别名
*/
public static void clearDataSourceDbName() {
contextHolder.remove();
}
/**
* 重写获取连接名称的方法
*
* @return 连接名称
*/
@Override
protected Object determineCurrentLookupKey() {
return getDataSourceDbName();
}
}

View File

@ -0,0 +1,76 @@
package business.cooperop.base.datasource.mysql.config;
/*
**********************************************
* DATE PERSON REASON
* 2020/7/24 FXY Created
**********************************************
*/
import business.cooperop.base.datasource.mysql.common.MultiDataSource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
@ConditionalOnProperty(prefix = "business.cooperop.base", name = "multiDatasourceOpen", havingValue = "true")
@Slf4j
public class MultiDataSourceAop implements Ordered {
public MultiDataSourceAop() {
log.info("多数据源初始化 AOP ");
}
@Pointcut(value = "@annotation(business.cooperop.base.datasource.mysql.common.MultiDataSource)")
private void cut() {
}
@Around("cut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Signature signature = point.getSignature();
MethodSignature methodSignature;
if (!(signature instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
methodSignature = (MethodSignature) signature;
//获取当前方法的注解
Object target = point.getTarget();
Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
MultiDataSource datasource = currentMethod.getAnnotation(MultiDataSource.class);
if (datasource != null) {
DynamicDataSource.setDataSourceDbName(datasource.name());
log.info("设置数据源为:" + datasource.name());
} else {
DynamicDataSource.setDataSourceDbName("main");
log.info("设置数据源为:默认 --> main");
}
try {
return point.proceed();
} finally {
log.info("清空数据源信息!");
DynamicDataSource.clearDataSourceDbName();
}
}
/**
* aop的顺序要早于spring的事务
*/
@Override
public int getOrder() {
return 1;
}
}

View File

@ -0,0 +1,33 @@
package business.cooperop.base.datasource.mysql.config;
/*
**********************************************
* DATE PERSON REASON
* 2020/7/24 FXY Created
**********************************************
*/
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "business.cooperop.base")
@Getter
@Setter
@Slf4j
public class MultiDataSourceConfig {
public MultiDataSourceConfig() {
log.info("加载多数据源配置信息 --> {}", "business.cooperop.base");
}
/**
* 多个数据源
*/
private List<DruidProperties> datasource;
}

View File

@ -0,0 +1,89 @@
package business.cooperop.base.datasource.mysql.config;
/*
**********************************************
* DATE PERSON REASON
* 2020/7/24 FXY Created
**********************************************
*/
import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Slf4j
@Configuration
public class MultiSourceConfig {
@Autowired
private DruidProperties druidProperties;
@Autowired
private MultiDataSourceConfig multiDataSourceConfig;
/**
* 单数据源连接池配置
*/
@Bean
@ConditionalOnProperty(name = "business.cooperop.base.multiDatasourceOpen", havingValue = "false")
public DruidDataSource singleDatasource() {
log.info("singleDatasource");
return druidProperties.config(new DruidDataSource());
}
/**
* 多数据源连接池配置
*/
@Bean
@ConditionalOnProperty(name = "business.cooperop.base.multiDatasourceOpen", havingValue = "true")
public DynamicDataSource mutiDataSource() {
log.info("mutiDataSource");
//存储数据源别名与数据源的映射
HashMap<Object, Object> dbNameMap = new HashMap();
// 核心数据源
DruidDataSource mainDataSource = druidProperties.config();
// 这里添加 主要数据库,其它数据库挂了,默认使用主数据库
dbNameMap.put("main", mainDataSource);
// 其它数据源
// 当前多数据源是否存在
if (multiDataSourceConfig.getDatasource() != null) {
//过滤掉没有添加 datasourceName 的数据源,先加载娟全局配置,再次加载当前配置
List<DruidDataSource> multiDataSourceList = multiDataSourceConfig.getDatasource().stream()
.filter(dp -> !"".equals(Optional.ofNullable(dp.getDatasourceName()).orElse("")))
.map(dp -> {
DruidDataSource druidDataSource = dp.config(druidProperties.config());
dbNameMap.put(dp.getDatasourceName(), druidDataSource);
return druidDataSource;
})
.collect(Collectors.toList());
// 测试所有的数据源
try {
mainDataSource.init();
for (DruidDataSource druidDataSource : multiDataSourceList) {
druidDataSource.init();
}
} catch (SQLException sql) {
log.error("======================= 多数据源配置错误 ==========================");
sql.printStackTrace();
}
}
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(dbNameMap);
dynamicDataSource.setDefaultTargetDataSource(mainDataSource);
return dynamicDataSource;
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>cooperop-demo-base</artifactId>
<groupId>business.chaoran</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cooperop-base-dictionary</artifactId>
</project>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>business.chaoran</groupId>
<artifactId>cooperop-demo-base</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>business.chaoran</groupId>
<artifactId>cooperop-base-message</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--邮件依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,28 @@
package business.cooperop.base.message;
/**
* 外部消息接口
* @author inaisen
*/
public interface ExternalMessage {
/**
* 发送手机消息
*/
void sendMobileMessage();
/**
* 发送邮件
*/
void sendEmailMessage();
/**
* 发送微信消息
*/
void sendWeChartMessage();
/**
* 发送钉钉消息
*/
void sendDingTalkMessage();
}

View File

@ -0,0 +1,41 @@
package business.cooperop.base.message;
/**
* 外部消息接口实现类
* @author inaisen
*/
public class ExternalMessageImpl implements ExternalMessage {
/**
* 发送手机消息实现
*/
@Override
public void sendMobileMessage() {
}
/**
* 发送邮件消息实现
*/
@Override
public void sendEmailMessage() {
}
/**
* 发送微信消息实现
*/
@Override
public void sendWeChartMessage() {
}
/**
* 发送手机钉钉实现
*/
@Override
public void sendDingTalkMessage() {
}
}

View File

@ -0,0 +1,19 @@
package business.cooperop.base.message;
/**
* 内部消息接口
* @author inaisen
*/
public interface InternalMessage {
/**
* 设置内部消息接口
*/
void settingInternalMessage();
/**
* 查询内部消息接口
*/
void queryInternalMessage();
}

View File

@ -0,0 +1,24 @@
package business.cooperop.base.message;
/**
* 内部消息接口实现
* @author inaisen
*/
public class InternalMessageImpl implements InternalMessage {
/**
* 设置内部消息
*/
@Override
public void settingInternalMessage() {
}
/**
* 查询内部消息
*/
@Override
public void queryInternalMessage() {
}
}

View File

@ -0,0 +1,36 @@
package business.cooperop.base.message.email.service;
/**
* 天下风云出我辈, 一入代码岁月催
*
* @Author: deadline
* @Date: 2020-12-22 9:38
*/
public interface EmailService {
/**
* 发送文本邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
void sendSimpleMail(String[] to, String subject, String content);
/**
* 发送HTML邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
void sendHtmlMail(String[] to, String subject, String content);
/**
* 发送带附件的邮件
* @param to 收件人
* @param subject 主题
* @param content 内容
* @param filePath 附件
*/
public void sendAttachmentsMail(String[] to, String subject, String content, String...filePath);
}

View File

@ -0,0 +1,89 @@
package business.cooperop.base.message.email.service.impl;
import business.cooperop.base.message.email.service.EmailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
/**
* 天下风云出我辈, 一入代码岁月催
*
* @Author: deadline
* @Date: 2020-12-22 9:38
*/
@Slf4j
public class EmailServiceImpl implements EmailService {
@Autowired
private JavaMailSender javaMailSender;
//注入配置文件中配置的信息——>from
@Value("${spring.mail.from}")
private String from;
@Override
public void sendSimpleMail(String[] to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
//发件人
message.setFrom(from);
//收件人
message.setTo(to);
//邮件主题
message.setSubject(subject);
//邮件内容
message.setText(content);
//发送邮件
javaMailSender.send(message);
}
@Override
public void sendHtmlMail(String[] to, String subject, String content) {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper;
try {
messageHelper = new MimeMessageHelper(message,true);
messageHelper.setFrom(from);
messageHelper.setTo(to);
message.setSubject(subject);
messageHelper.setText(content,true);
javaMailSender.send(message);
log.info("邮件已经发送!");
} catch (MessagingException e) {
log.error("发送邮件时发生异常:" + e);
}
}
@Override
public void sendAttachmentsMail(String[] to, String subject, String content, String...filePath) {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper;
try {
messageHelper = new MimeMessageHelper(message,true);
messageHelper.setFrom(from);
messageHelper.setTo(to);
messageHelper.setSubject(subject);
messageHelper.setText(content,true);
for (String path : filePath) {
//携带附件
FileSystemResource file = new FileSystemResource(path);
String fileName = path.substring(path.lastIndexOf(File.separator));
messageHelper.addAttachment(fileName, file);
}
javaMailSender.send(message);
log.info("邮件加附件发送成功!");
} catch (MessagingException e) {
log.error("发送失败:"+e);
}
}
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>cooperop-demo-base</artifactId>
<groupId>business.chaoran</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cooperop-base-schedule</artifactId>
</project>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>cooperop-demo-base</artifactId>
<groupId>business.chaoran</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cooperop-base-taglib</artifactId>
</project>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>cooperop-demo-base</artifactId>
<groupId>business.chaoran</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cooperop-base-workflow</artifactId>
<dependencies>
<dependency>
<groupId>com.github.snakerflow-starter</groupId>
<artifactId>snakerflow-spring-boot-starter</artifactId>
<version>1.0.3</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,37 @@
package business.cooperop.base.workflow.snakerflow;
/*
**********************************************
* DATE PERSON REASON
* 2020-11-25 FXY Created
**********************************************
*/
import org.snaker.engine.SnakerEngine;
import java.util.List;
public interface SnakerEngineBaseService {
/**
* 初始化状态机流程
*
* @return 流程主键
* @param relativePath
*/
String initFlows(String relativePath);
/**
* 获得执行引擎
*
* @return SnakerEngine
*/
SnakerEngine getEngine();
/**
* 获得所有流程的名字
*
* @return List<String>
*/
List<String> getAllProcessNames();
}

View File

@ -0,0 +1,104 @@
package business.cooperop.base.workflow.snakerflow;
/*
**********************************************
* DATE PERSON REASON
* 2020-11-25 FXY Created
**********************************************
*/
import org.snaker.engine.entity.Order;
import org.snaker.engine.entity.Process;
import org.snaker.engine.entity.Task;
import java.util.List;
import java.util.Map;
public interface SnakerEngineService extends SnakerEngineBaseService {
/**
* 获得所有有效流程
*
* @return List<Process>
*/
List<Process> getAllProcess();
/**
* 通过orderId 获得流程
*
* @param orderId 流程实例Id
* @return List<Process>
*/
List<Process> getProcessByOrderId(String orderId);
/**
* 通过processId发起一个流程实例
*
* @param processId 流程ID
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
Order startInstanceById(String processId, String operator, Map<String, Object> args);
/**
* 通过process name发起一个流程实例
*
* @param name 流程 name
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
Order startInstanceByName(String name, Integer version, String operator, Map<String, Object> args);
/**
* 执行流程实例
*
* @param name 流程 name
* @param version 版本
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
Order startAndExecute(String name, Integer version, String operator, Map<String, Object> args);
/**
* 执行流程实例
*
* @param processId 流程Id
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
Order startAndExecute(String processId, String operator, Map<String, Object> args);
/**
* 通过taskId执行
*
* @param taskId 任务Id
* @param operator 操作人
* @param args 自定义参数
* @return List<Task>
*/
List<Task> execute(String taskId, String operator, Map<String, Object> args);
/**
* 流程跳转
*
* @param taskId 任务Id
* @param operator 操作人
* @param args 自定义参数
* @param nodeName 跳转到的节点名称
* @return List<Task>
*/
List<Task> executeAndJump(String taskId, String operator, Map<String, Object> args, String nodeName);
/**
* 通过orderId获取对应的流程task
*
* @param orderId 流程实例Id
* @return List<Task>
*/
List<Task> getTasks(String orderId);
}

View File

@ -0,0 +1,212 @@
/* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package business.cooperop.base.workflow.snakerflow;
import org.snaker.engine.SnakerEngine;
import org.snaker.engine.access.QueryFilter;
import org.snaker.engine.entity.Order;
import org.snaker.engine.entity.Process;
import org.snaker.engine.entity.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* SnakerEngineFacets封装snakerflow基本操作可以直接使用
*
* @author zhaoguoqing
* @since 0.1
*/
@Component
public class SnakerEngineServiceImpl implements SnakerEngineService {
@Autowired
private SnakerEngine engine;
/**
* 初始化状态机流程
*
* @return 流程主键
* @param relativePath 相对路径
*/
@Override
public String initFlows(String relativePath) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream stream = classLoader.getResourceAsStream(relativePath);
String deploy = engine.process().deploy(stream);
return deploy;
}
/**
* 获得所有有效流程
*
* @return List<Process>
*/
@Override
public List<Process> getAllProcess() {
QueryFilter filter = new QueryFilter();
return engine.process().getProcesss(filter);
}
/**
* 通过orderId 获得流程
*
* @param orderId 流程实例Id
* @return List<Process>
*/
@Override
public List<Process> getProcessByOrderId(String orderId) {
QueryFilter filter = new QueryFilter();
filter.setOrderId(orderId);
return engine.process().getProcesss(filter);
}
/**
* 获得执行引擎
*
* @return SnakerEngine
*/
@Override
public SnakerEngine getEngine() {
return engine;
}
/**
* 获得所有流程的名字
*
* @return List<String>
*/
@Override
public List<String> getAllProcessNames() {
List<Process> list = engine.process().getProcesss(new QueryFilter());
List<String> names = new ArrayList<>();
for (Process entity : list) {
if (names.contains(entity.getName())) {
continue;
} else {
names.add(entity.getName());
}
}
return names;
}
/**
* 通过processId发起一个流程实例
*
* @param processId 流程ID
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
@Override
public Order startInstanceById(String processId, String operator, Map<String, Object> args) {
return engine.startInstanceById(processId, operator, args);
}
/**
* 通过process name发起一个流程实例
*
* @param name 流程 name
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
@Override
public Order startInstanceByName(String name, Integer version, String operator, Map<String, Object> args) {
return engine.startInstanceByName(name, version, operator, args);
}
/**
* 执行流程实例
*
* @param name 流程 name
* @param version 版本
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
@Override
public Order startAndExecute(String name, Integer version, String operator, Map<String, Object> args) {
Order order = engine.startInstanceByName(name, version, operator, args);
List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));
List<Task> newTasks = new ArrayList<Task>();
if (tasks != null && tasks.size() > 0) {
Task task = tasks.get(0);
newTasks.addAll(engine.executeTask(task.getId(), operator, args));
}
return order;
}
/**
* 执行流程实例
*
* @param processId 流程Id
* @param operator 操作人
* @param args 自定义参数
* @return Order流程实例
*/
@Override
public Order startAndExecute(String processId, String operator, Map<String, Object> args) {
Order order = engine.startInstanceById(processId, operator, args);
List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));
List<Task> newTasks = new ArrayList<Task>();
if (tasks != null && tasks.size() > 0) {
Task task = tasks.get(0);
newTasks.addAll(engine.executeTask(task.getId(), operator, args));
}
return order;
}
/**
* 通过taskId执行
*
* @param taskId 任务Id
* @param operator 操作人
* @param args 自定义参数
* @return List<Task>
*/
@Override
public List<Task> execute(String taskId, String operator, Map<String, Object> args) {
return engine.executeTask(taskId, operator, args);
}
/**
* 流程跳转
*
* @param taskId 任务Id
* @param operator 操作人
* @param args 自定义参数
* @param nodeName 跳转到的节点名称
* @return List<Task>
*/
@Override
public List<Task> executeAndJump(String taskId, String operator, Map<String, Object> args, String nodeName) {
return engine.executeAndJumpTask(taskId, operator, args, nodeName);
}
/**
* 通过orderId获取对应的流程task
*
* @param orderId 流程实例Id
* @return List<Task>
*/
@Override
public List<Task> getTasks(String orderId) {
return engine.query().getActiveTasks(new QueryFilter().setOrderId(orderId));
}
}

View File

@ -0,0 +1,96 @@
package business.cooperop.base.workflow.snakerflow.config;
/*
**********************************************
* DATE PERSON REASON
* 2020-11-25 FXY Created
**********************************************
*/
import org.apache.ibatis.session.SqlSessionFactory;
import org.snaker.engine.DBAccess;
import org.snaker.engine.access.mybatis.MybatisAccess;
import org.snaker.engine.cache.CacheManager;
import org.snaker.engine.cache.memory.MemoryCacheManager;
import org.snaker.engine.core.*;
import org.snaker.engine.impl.LogInterceptor;
import org.snaker.engine.spring.SpelExpression;
import org.snaker.engine.spring.SpringSnakerEngine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean("engine")
public SpringSnakerEngine springSnakerEngine(ProcessService processService, OrderService orderService,
TaskService taskService, QueryService queryService, ManagerService managerService) {
SpringSnakerEngine springSnakerEngine = new SpringSnakerEngine();
springSnakerEngine.setProcessService(processService);
springSnakerEngine.setOrderService(orderService);
springSnakerEngine.setTaskService(taskService);
springSnakerEngine.setQueryService(queryService);
springSnakerEngine.setManagerService(managerService);
return springSnakerEngine;
}
@Bean
public ProcessService processService(DBAccess dbAccess, CacheManager cacheManager) {
ProcessService processService=new ProcessService();
processService.setCacheManager(cacheManager);
processService.setAccess(dbAccess);
return processService;
}
@Bean
public OrderService orderService(DBAccess dbAccess) {
OrderService orderService = new OrderService();
orderService.setAccess(dbAccess);
return orderService;
}
@Bean
public TaskService taskService(DBAccess dbAccess) {
TaskService taskService = new TaskService();
taskService.setAccess(dbAccess);
return taskService;
}
@Bean
public QueryService queryService(DBAccess dbAccess) {
QueryService queryService = new QueryService();
queryService.setAccess(dbAccess);
return queryService;
}
@Bean
public ManagerService managerService(DBAccess dbAccess) {
ManagerService managerService = new ManagerService();
managerService.setAccess(dbAccess);
return managerService;
}
@Bean("snakerCacheManager")
public MemoryCacheManager memoryCacheManager(){
return new MemoryCacheManager();
}
@Bean("logInterceptor")
public LogInterceptor logInterceptor(){
return new LogInterceptor();
}
@Bean("spelExpression")
public SpelExpression spelExpression(){
return new SpelExpression();
}
@Bean("dbAccess")
public MybatisAccess mybatisAccess(SqlSessionFactory sqlSessionFactory){
MybatisAccess mybatisAccess=new MybatisAccess();
mybatisAccess.setSqlSessionFactory(sqlSessionFactory);
return mybatisAccess;
}
}

61
pom.xml Normal file
View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/>
</parent>
<groupId>business.chaoran</groupId>
<artifactId>cooperop-demo-base</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>cooperop-base-datasource</module>
<module>cooperop-base-taglib</module>
<module>cooperop-base-workflow</module>
<module>cooperop-base-dictionary</module>
<module>cooperop-base-message</module>
<module>cooperop-base-cache</module>
<module>cooperop-base-schedule</module>
</modules>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<fastjson.version>1.2.73</fastjson.version>
</properties>
<dependencyManagement>
<dependencies>
<!--redis序列化用fastjson业务返回Json还是用gson更加灵活-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>