feat: 项目初始化
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
package com.byhah.cloud.autoconfigure;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
|
||||
|
||||
public interface IBaseMapper<T> extends BaseMapper<T> {
|
||||
|
||||
default QueryChainWrapper<T> queryChain() {
|
||||
return ChainWrappers.queryChain(this);
|
||||
}
|
||||
|
||||
default LambdaQueryChainWrapper<T> lambdaQueryChain() {
|
||||
return ChainWrappers.lambdaQueryChain(this);
|
||||
}
|
||||
|
||||
default UpdateChainWrapper<T> updateChain() {
|
||||
return ChainWrappers.updateChain(this);
|
||||
}
|
||||
|
||||
default LambdaUpdateChainWrapper<T> lambdaUpdateChain() {
|
||||
return ChainWrappers.lambdaUpdateChain(this);
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.byhah.cloud.autoconfigure;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.ReplacePlaceholderInnerInterceptor;
|
||||
import com.byhah.deploy.basic.core.model.GeoPoint;
|
||||
import com.byhah.deploy.basic.core.model.LongList;
|
||||
import com.byhah.deploy.basic.core.model.StringList;
|
||||
import com.byhah.cloud.autoconfigure.auto.TableInfoInitHandler;
|
||||
import com.byhah.cloud.autoconfigure.properties.CloudProperties;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.apache.ibatis.type.TypeHandlerRegistry;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@Configuration
|
||||
@MapperScan("com.byhah.cloud.orm.mapper")
|
||||
@AutoConfiguration(before = MybatisPlusAutoConfiguration.class, after = DataSourceAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(CloudProperties.class)
|
||||
public class OrmAutoConfiguration {
|
||||
|
||||
private static final String CREATED_AT = "createdAt";
|
||||
private static final String CREATED_BY = "createdBy";
|
||||
private static final String UPDATED_AT = "updatedAt";
|
||||
private static final String UPDATED_BY = "updatedBy";
|
||||
|
||||
@Bean
|
||||
public MybatisPlusPropertiesCustomizer mybatisPlusProperties() {
|
||||
return i -> i.getGlobalConfig().setEnableSqlRunner(true).getDbConfig()
|
||||
.setLogicDeleteValue("true")
|
||||
.setLogicNotDeleteValue("false")
|
||||
.setReplacePlaceholder(false).setEscapeSymbol("\"");
|
||||
}
|
||||
|
||||
@Bean
|
||||
ConfigurationCustomizer configurationCustomizer() {
|
||||
return i -> {
|
||||
TypeHandlerRegistry registry = i.getTypeHandlerRegistry();
|
||||
registry.register(GeoPoint.class, PgJsonTypeHandler.class);
|
||||
registry.register(StringList.class, PgJsonTypeHandler.class);
|
||||
registry.register(LongList.class, PgJsonTypeHandler.class);
|
||||
registry.register(ArrayList.class, PgJsonbTypeHandler.class);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
TableInfoInitHandler tableInfoInitHandler() {
|
||||
return new TableInfoInitHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MetaObjectHandler metaObjectHandler() {
|
||||
return new MetaObjectHandler() {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
fillStrategy(metaObject, CREATED_AT, LocalDateTime.now());
|
||||
fillStrategy(metaObject, CREATED_BY, getUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
setFieldValByName(UPDATED_AT, LocalDateTime.now(), metaObject);
|
||||
setFieldValByName(UPDATED_BY, getUserId(), metaObject);
|
||||
}
|
||||
|
||||
private Long getUserId() {
|
||||
try {
|
||||
return StpUtil.getLoginIdAsLong();
|
||||
} catch (Exception e) {
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new ReplacePlaceholderInnerInterceptor("\""));
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.byhah.cloud.autoconfigure;
|
||||
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("com.byhah.cloud.orm.support.service")
|
||||
@AutoConfigureAfter({OrmAutoConfiguration.class, MybatisPlusAutoConfiguration.class})
|
||||
public class OrmSupportAutoConfiguration {
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.byhah.cloud.autoconfigure;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.postgresql.util.PGobject;
|
||||
import org.springframework.util.StringUtils;
|
||||
import com.byhah.deploy.basic.core.utils.Asserts;
|
||||
import com.byhah.deploy.basic.jackson.util.JacksonUtil;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Slf4j
|
||||
public class PgJsonTypeHandler extends BaseTypeHandler<Object> {
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
public PgJsonTypeHandler(Class<?> type) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("PgJsonTypeHandler(" + type + ")");
|
||||
}
|
||||
Asserts.notNull(type, "Type argument cannot be null");
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement statement, int i, Object t, JdbcType jdbcType) throws SQLException {
|
||||
PGobject object = new PGobject();
|
||||
object.setType("json");
|
||||
object.setValue(toJson(t));
|
||||
statement.setObject(i, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
return parse(rs.getString(columnName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
return parse(rs.getString(columnIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
return parse(cs.getString(columnIndex));
|
||||
}
|
||||
|
||||
protected String toJson(Object t) {
|
||||
try {
|
||||
return JacksonUtil.toJson(t);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object parse(String json) {
|
||||
if (StringUtils.hasText(json)) {
|
||||
try {
|
||||
return JacksonUtil.fromJson(json, type);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.byhah.cloud.autoconfigure;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.postgresql.util.PGobject;
|
||||
import org.springframework.util.StringUtils;
|
||||
import com.byhah.deploy.basic.core.utils.Asserts;
|
||||
import com.byhah.deploy.basic.jackson.util.JacksonUtil;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Slf4j
|
||||
public class PgJsonbTypeHandler extends BaseTypeHandler<Object> {
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
public PgJsonbTypeHandler(Class<?> type) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("PgJsonbTypeHandler(" + type + ")");
|
||||
}
|
||||
Asserts.notNull(type, "Type argument cannot be null");
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement statement, int i, Object t, JdbcType jdbcType) throws SQLException {
|
||||
PGobject object = new PGobject();
|
||||
object.setType("jsonb");
|
||||
object.setValue(toJson(t));
|
||||
statement.setObject(i, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
return parse(rs.getString(columnName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
return parse(rs.getString(columnIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
return parse(cs.getString(columnIndex));
|
||||
}
|
||||
|
||||
protected String toJson(Object t) {
|
||||
try {
|
||||
return JacksonUtil.toJson(t);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object parse(String json) {
|
||||
if (StringUtils.hasText(json)) {
|
||||
try {
|
||||
return JacksonUtil.fromJson(json, type);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.byhah.cloud.autoconfigure.auto;
|
||||
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.event.GenericApplicationListener;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
public class EndAutoTableApplicationListener implements GenericApplicationListener {
|
||||
|
||||
@Override
|
||||
public boolean supportsEventType(ResolvableType eventType) {
|
||||
return eventType.getRawClass().isAssignableFrom(ApplicationStartedEvent.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动建表
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
TableInfoInitHandler.initClear();
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package com.byhah.cloud.autoconfigure.auto;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import com.byhah.cloud.autoconfigure.PgJsonTypeHandler;
|
||||
import com.byhah.cloud.autoconfigure.PgJsonbTypeHandler;
|
||||
import com.byhah.deploy.basic.core.annotation.PgJson;
|
||||
import com.byhah.deploy.basic.core.annotation.PgJsonb;
|
||||
import com.byhah.deploy.basic.core.model.GeoPoint;
|
||||
import com.byhah.deploy.basic.core.model.LongList;
|
||||
import com.byhah.deploy.basic.core.model.StringList;
|
||||
import com.byhah.deploy.basic.core.utils.AutoTableUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 自动建表 - 自动新增字段 - 自动创建索引
|
||||
* 其他的没有比如: 更新字段类型 - 删除字段
|
||||
*/
|
||||
@Slf4j
|
||||
public class TableInfoInitHandler implements PostInitTableInfoHandler {
|
||||
private static final List<Class<?>> cache = new ArrayList<>();
|
||||
private static final List<String> tableNames = new ArrayList<>();
|
||||
private static final List<String> tableIndex = new ArrayList<>();
|
||||
static DataSourceTransactionManager transactionManager;
|
||||
static TransactionStatus transactionStatus;
|
||||
private static boolean init = false;
|
||||
|
||||
static {
|
||||
cache.add(GeoPoint.class);
|
||||
cache.add(StringList.class);
|
||||
cache.add(LongList.class);
|
||||
}
|
||||
|
||||
private static void checkColumn(DataSource dataSource, String tableName, Map<String, String> columns, List<String> sqlList) {
|
||||
Map<String, String> copy = new HashMap<>(columns);
|
||||
List<String> tableColumns = tableColumns(dataSource, tableName);
|
||||
tableColumns.forEach(copy::remove);
|
||||
if (!CollectionUtils.isEmpty(copy)) {
|
||||
copy.forEach((k, v) -> sqlList.add(String.format(AutoTableUtils.addColumn, tableName, v)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void inits(DataSource dataSource) {
|
||||
if (!init) {
|
||||
init(dataSource);
|
||||
try {
|
||||
JdbcUtils.extractDatabaseMetaData(dataSource, i -> {
|
||||
ResultSet rs = i.getTables(null, "public", null, new String[]{"TABLE", "INDEX"});
|
||||
while (rs.next()) {
|
||||
String name = rs.getString(3);
|
||||
String type = rs.getString(4);
|
||||
if (type.equals("TABLE")) {
|
||||
tableNames.add(name);
|
||||
} else {
|
||||
if (!name.endsWith("_pk")) {
|
||||
tableIndex.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rs;
|
||||
});
|
||||
} catch (MetaDataAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> tableColumns(DataSource dataSource, String tableName) {
|
||||
List<String> list = new ArrayList<>();
|
||||
try {
|
||||
JdbcUtils.extractDatabaseMetaData(dataSource, i -> {
|
||||
ResultSet rs = i.getColumns(null, "public", tableName, null);
|
||||
while (rs.next()) {
|
||||
String name = rs.getString(4);
|
||||
list.add(name);
|
||||
}
|
||||
return rs;
|
||||
});
|
||||
} catch (MetaDataAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void init(DataSource dataSource) {
|
||||
if (transactionStatus == null) {
|
||||
log.info("初始化建表事务");
|
||||
transactionManager = new DataSourceTransactionManager(dataSource);
|
||||
transactionStatus = transactionManager.getTransaction(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void initClear() {
|
||||
log.info("提交建表事务");
|
||||
if (transactionStatus != null) {
|
||||
transactionManager.commit(transactionStatus);
|
||||
transactionStatus = null;
|
||||
transactionManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postFieldInfo(TableFieldInfo fieldInfo, org.apache.ibatis.session.Configuration configuration) {
|
||||
Field field = fieldInfo.getField();
|
||||
if (field.getAnnotation(PgJson.class) != null) {
|
||||
Class<?> type = field.getType();
|
||||
if (!cache.contains(type)) {
|
||||
configuration.getTypeHandlerRegistry().register(type, PgJsonTypeHandler.class);
|
||||
cache.add(type);
|
||||
}
|
||||
} else if (field.getAnnotation(PgJsonb.class) != null) {
|
||||
Class<?> type = field.getType();
|
||||
if (!cache.contains(type)) {
|
||||
configuration.getTypeHandlerRegistry().register(type, PgJsonbTypeHandler.class);
|
||||
cache.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postTableInfo(TableInfo tableInfo, org.apache.ibatis.session.Configuration configuration) {
|
||||
DataSource dataSource = configuration.getEnvironment().getDataSource();
|
||||
inits(dataSource);
|
||||
// final Class<?> entity = tableInfo.getEntityType();
|
||||
// AutoTable autoTable = entity.getAnnotation(AutoTable.class);
|
||||
// if (Objects.isNull(autoTable)) return;
|
||||
// if (autoTable.notProd() && SbProfileUtil.isProd()) return;
|
||||
String tableName = tableInfo.getTableName();
|
||||
AutoTableUtils.Result result = AutoTableUtils.autoTable(tableInfo, false);
|
||||
List<String> sqlList = new ArrayList<>();
|
||||
if (!tableNames.contains(tableName)) {
|
||||
sqlList.add(result.getCreateTable());
|
||||
} else {
|
||||
checkColumn(dataSource, tableName, result.getColumns(), sqlList);
|
||||
}
|
||||
result.getCreateIndexMap().forEach((k, v) -> {
|
||||
if (!tableIndex.contains(k)) {
|
||||
sqlList.add(v);
|
||||
}
|
||||
});
|
||||
if (!CollectionUtils.isEmpty(sqlList)) {
|
||||
Connection connection = DataSourceUtils.getConnection(dataSource);
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
for (String sql : sqlList) {
|
||||
log.info("执行sql: {}", sql);
|
||||
stmt.execute(sql);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
|
||||
package com.byhah.cloud.autoconfigure.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 通用基础配置
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = CloudProperties.PREFIX)
|
||||
public class CloudProperties {
|
||||
public static final String PREFIX = "byhah.config";
|
||||
|
||||
/**
|
||||
* 服务域名
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 后端接口地址
|
||||
*/
|
||||
private String serverUrl;
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevConfig;
|
||||
|
||||
public interface IDevConfigMapper extends IBaseMapper<DevConfig> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevDict;
|
||||
|
||||
/**
|
||||
* 字典Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface IDevDictMapper extends IBaseMapper<DevDict> {
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevEmail;
|
||||
|
||||
/**
|
||||
* 邮件Mapper接口
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
public interface IDevEmailMapper extends IBaseMapper<DevEmail> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevFile;
|
||||
|
||||
/**
|
||||
* 文件Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface IDevFileMapper extends IBaseMapper<DevFile> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevLog;
|
||||
|
||||
/**
|
||||
* 日志Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface IDevLogMapper extends IBaseMapper<DevLog> {
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevMessage;
|
||||
|
||||
/**
|
||||
* 站内信Mapper接口
|
||||
**/
|
||||
public interface IDevMessageMapper extends IBaseMapper<DevMessage> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevMessageUser;
|
||||
|
||||
public interface IDevMessageUserMapper extends IBaseMapper<DevMessageUser> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.dev;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevSms;
|
||||
|
||||
/**
|
||||
* 短信Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface IDevSmsMapper extends IBaseMapper<DevSms> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.gen;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.gen.GenBasic;
|
||||
|
||||
/**
|
||||
* 代码生成基础Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface GenBasicMapper extends IBaseMapper<GenBasic> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.gen;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.gen.GenConfig;
|
||||
|
||||
/**
|
||||
* 代码生成详细配置Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface GenConfigMapper extends IBaseMapper<GenConfig> {
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.sys;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.system.SysOrg;
|
||||
|
||||
/**
|
||||
* 组织Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface ISysOrgMapper extends IBaseMapper<SysOrg> {
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.sys;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.system.SysRelation;
|
||||
|
||||
/**
|
||||
* 关系Mapper接口
|
||||
*
|
||||
*
|
||||
*
|
||||
**/
|
||||
public interface ISysRelationMapper extends IBaseMapper<SysRelation> {
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.sys;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.system.SysResource;
|
||||
|
||||
/**
|
||||
* 按钮Mapper接口
|
||||
**/
|
||||
public interface ISysResourceMapper extends IBaseMapper<SysResource> {
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.sys;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.system.SysRole;
|
||||
|
||||
/**
|
||||
* 角色Mapper接口
|
||||
**/
|
||||
public interface ISysRoleMapper extends IBaseMapper<SysRole> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.byhah.cloud.orm.mapper.sys;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.system.SysTenant;
|
||||
|
||||
public interface ISysTenantMapper extends IBaseMapper<SysTenant> {
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
|
||||
package com.byhah.cloud.orm.mapper.sys;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.system.SysUser;
|
||||
|
||||
/**
|
||||
* 用户Mapper接口
|
||||
*
|
||||
**/
|
||||
public interface ISysUserMapper extends IBaseMapper<SysUser> {
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.byhah.cloud.orm.mapper.sys;
|
||||
|
||||
import com.byhah.cloud.autoconfigure.IBaseMapper;
|
||||
import com.byhah.cloud.basic.core.entity.system.ThirdPlatform;
|
||||
|
||||
public interface IThirdPlatformMapper extends IBaseMapper<ThirdPlatform> {
|
||||
}
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
package com.byhah.cloud.orm.support.service;
|
||||
|
||||
import cn.hutool.core.img.ImgUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.byhah.deploy.basic.core.exception.CommonException;
|
||||
import com.byhah.deploy.basic.file.client.*;
|
||||
import com.byhah.cloud.orm.mapper.dev.IDevConfigMapper;
|
||||
import com.byhah.cloud.orm.mapper.dev.IDevFileMapper;
|
||||
import com.byhah.cloud.autoconfigure.properties.CloudProperties;
|
||||
import com.byhah.cloud.basic.constant.CacheKey;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevConfig;
|
||||
import com.byhah.cloud.basic.core.entity.dev.DevFile;
|
||||
import com.byhah.cloud.basic.core.enums.dev.DevFileEngine;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RMapCache;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.byhah.cloud.basic.constant.ConfigKey.File.*;
|
||||
import static com.byhah.cloud.basic.constant.ConfigKey.Sys.SYS_DEFAULT_FILE_ENGINE_KEY;
|
||||
import static com.byhah.cloud.basic.core.enums.dev.DevFileEngine.LOCAL;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DevSupportService {
|
||||
private final IDevFileMapper fileMapper;
|
||||
private final IDevConfigMapper devConfigMapper;
|
||||
private final CloudProperties cloudProperties;
|
||||
private final RedissonClient redissonClient;
|
||||
private final ConcurrentHashMap<DevFileEngine, FileBaseClient> fileClientMap = new ConcurrentHashMap<>();
|
||||
|
||||
public String upload(Integer engine, Boolean isReturnId, Long maxSize, MultipartFile file) throws IOException {
|
||||
if (Objects.isNull(engine)) {
|
||||
engine = Integer.valueOf(getConfig(SYS_DEFAULT_FILE_ENGINE_KEY));
|
||||
}
|
||||
return storageFile(DevFileEngine.forValue(engine), file.getBytes(), isReturnId, file.getOriginalFilename(), maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传后返回url
|
||||
*/
|
||||
public String upload(byte[] bytes, String fileName, Long maxSize) {
|
||||
return storageFile(DevFileEngine.forValue(Integer.valueOf(getConfig(SYS_DEFAULT_FILE_ENGINE_KEY))), bytes, false, fileName, maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存储文件
|
||||
**/
|
||||
private String storageFile(DevFileEngine engine, byte[] bytes, boolean returnFileId, String fileName, Long maxSize) {
|
||||
// 如果引擎为空,默认使用本地
|
||||
if (ObjectUtil.isEmpty(engine)) {
|
||||
engine = LOCAL;
|
||||
}
|
||||
// 获取bucketName
|
||||
FileBaseClient client = getFileClientByEngine(engine);
|
||||
String bucketName = client.getDefaultBucketName();
|
||||
if (StrUtil.isBlank(bucketName)) {
|
||||
bucketName = "defaultBucketName";
|
||||
}
|
||||
// 验证文件md5
|
||||
String md5 = SecureUtil.md5().digestHex(bytes);
|
||||
if (StrUtil.isNotBlank(md5)) {
|
||||
DevFile existFile = fileMapper.lambdaQueryChain()
|
||||
.eq(DevFile::getMd5, md5)
|
||||
.eq(DevFile::getBucket, bucketName)
|
||||
.eq(DevFile::getEngine, engine)
|
||||
.list().stream().findFirst().orElse(null);
|
||||
if (Objects.nonNull(existFile)) {
|
||||
return returnFileId ? existFile.getId().toString() : existFile.getDownloadPath();
|
||||
}
|
||||
}
|
||||
|
||||
Long fileId = IdWorker.getId();
|
||||
DevFile devFile = new DevFile();
|
||||
devFile.setId(fileId);
|
||||
String suffix = FileUtil.getSuffix(fileName);
|
||||
try {
|
||||
uploadFile(devFile, engine, bytes, suffix, maxSize, client, bucketName);
|
||||
} catch (Exception e) {
|
||||
log.error("上传文件错误", e);
|
||||
throw new CommonException("上传异常");
|
||||
}
|
||||
// 保存文件信息
|
||||
devFile.setMd5(md5);
|
||||
devFile.setName(fileName);
|
||||
devFile.setSizeKb(NumberUtil.div(new BigDecimal(bytes.length), BigDecimal.valueOf(1024)).setScale(0, RoundingMode.HALF_UP).longValue());
|
||||
devFile.setSizeInfo(FileUtil.readableFileSize(bytes.length));
|
||||
devFile.setObjName(ObjectUtil.isNotEmpty(devFile.getSuffix()) ? fileId + StrUtil.DOT + devFile.getSuffix() : null);
|
||||
fileMapper.insert(devFile);
|
||||
|
||||
return returnFileId ? fileId.toString() : devFile.getDownloadPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
private DevFile uploadFile(DevFile file, DevFileEngine engine, byte[] bytes,
|
||||
String suffix, Long maxSize, FileBaseClient client, String bucketName) {
|
||||
|
||||
if (Objects.isNull(file.getId())) {
|
||||
file.setId(IdWorker.getId());
|
||||
}
|
||||
// 如果是图片,则压缩
|
||||
if (ObjectUtil.isNotEmpty(suffix) && com.byhah.cloud.basic.core.util.FileUtil.isPic(suffix)) {
|
||||
if (Objects.nonNull(maxSize)) {
|
||||
try {
|
||||
while (bytes.length > maxSize) {
|
||||
Image image = ImgUtil.scale(ImgUtil.toImage(bytes), 0.9f);
|
||||
bytes = ImgUtil.toBytes(image, suffix);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
log.error("e", ignored);
|
||||
}
|
||||
}
|
||||
}
|
||||
String filePath = genFileKey(file.getId(), suffix);
|
||||
String storageUrl = client.storageFileWithReturnUrl(bucketName, filePath, bytes);
|
||||
file.setBucket(bucketName);
|
||||
file.setStoragePath(storageUrl);
|
||||
file.setEngine(engine);
|
||||
file.setSuffix(suffix);
|
||||
|
||||
if (engine == LOCAL) {
|
||||
String apiUrl = cloudProperties.getServerUrl();
|
||||
if (ObjectUtil.isEmpty(apiUrl)) {
|
||||
throw new CommonException("后端域名地址未正确配置:quick.config.common.server-url为空");
|
||||
}
|
||||
file.setDownloadPath(apiUrl + "/dev/file/download?id=" + file.getId());
|
||||
} else {
|
||||
// 阿里云、腾讯云、MINIO可以直接使用存储地址(公网)作为下载地址
|
||||
file.setDownloadPath(storageUrl);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
public String genFileKey(Long fileId, String fileSuffix) {
|
||||
LocalDate now = LocalDate.now();
|
||||
// 生成文件的对象名称,格式如:1377109572375810050.docx
|
||||
String fileObjectName = fileId + StrUtil.DOT + fileSuffix;
|
||||
// 获取日期文件夹,格式如,2021/10/11/
|
||||
String dateFolderPath = now.getYear() + StrUtil.SLASH + now.getMonthValue() + StrUtil.SLASH + now.getDayOfMonth() + StrUtil.SLASH;
|
||||
// 返回
|
||||
return dateFolderPath + fileObjectName;
|
||||
}
|
||||
|
||||
public FileBaseClient getFileClientByEngine() {
|
||||
DevFileEngine engine = DevFileEngine.forValue(Integer.valueOf(getConfig(SYS_DEFAULT_FILE_ENGINE_KEY)));
|
||||
if (Objects.isNull(engine)) {
|
||||
engine = LOCAL;
|
||||
}
|
||||
return getFileClientByEngine(engine);
|
||||
}
|
||||
|
||||
private FileBaseClient getFileClientByEngine(DevFileEngine engine) {
|
||||
FileBaseClient client = fileClientMap.get(engine);
|
||||
if (client == null) {
|
||||
if (engine == LOCAL) {
|
||||
String folder = getConfig(FILE_LOCAL_FOLDER_KEY);
|
||||
String bucketName = getConfig(FILE_LOCAL_DEFAULT_BUCKET_NAME);
|
||||
client = new FileLocalClient(folder, bucketName);
|
||||
} else if (engine == DevFileEngine.ALIYUN) {
|
||||
String accessKey = getConfig(FILE_ALIYUN_ACCESS_KEY_ID_KEY);
|
||||
String accessSecret = getConfig(FILE_ALIYUN_ACCESS_KEY_SECRET_KEY);
|
||||
String endpoint = getConfig(FILE_ALIYUN_END_POINT_KEY);
|
||||
String bucketName = getConfig(FILE_ALIYUN_DEFAULT_BUCKET_NAME);
|
||||
client = new FileAliyunClient(accessKey, accessSecret, endpoint, bucketName);
|
||||
} else if (engine == DevFileEngine.TENCENT) {
|
||||
String secretId = getConfig(FILE_TENCENT_SECRET_ID_KEY);
|
||||
String secretKey = getConfig(FILE_TENCENT_SECRET_KEY_KEY);
|
||||
String regionId = getConfig(FILE_TENCENT_REGION_ID_KEY);
|
||||
String bucketName = getConfig(FILE_TENCENT_DEFAULT_BUCKET_NAME);
|
||||
client = new FileTencentClient(secretId, secretKey, regionId, bucketName);
|
||||
} else if (engine == DevFileEngine.MINIO) {
|
||||
String accessKey = getConfig(FILE_MINIO_ACCESS_KEY_KEY);
|
||||
String accessSecret = getConfig(FILE_MINIO_SECRET_KEY_KEY);
|
||||
String endpoint = getConfig(FILE_MINIO_END_POINT_KEY);
|
||||
String bucketName = getConfig(FILE_MINIO_DEFAULT_BUCKET_NAME);
|
||||
client = new FileMinIoClient(accessKey, accessSecret, endpoint, bucketName);
|
||||
}
|
||||
fileClientMap.put(engine, client);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
*/
|
||||
public String getConfig(String key) {
|
||||
// 从缓存中取
|
||||
RMapCache<String, String> mapCache = redissonClient.getMapCache(CacheKey.CONFIG_CACHE_KEY);
|
||||
String cacheValue = mapCache.get(key);
|
||||
if (CharSequenceUtil.isNotBlank(cacheValue)) {
|
||||
return cacheValue;
|
||||
}
|
||||
DevConfig config = devConfigMapper.lambdaQueryChain().eq(DevConfig::getConfigKey, key).one();
|
||||
if (ObjectUtil.isNotEmpty(config)) {
|
||||
// 更新到缓存
|
||||
mapCache.put(key, config.getConfigValue());
|
||||
return config.getConfigValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除配置缓存
|
||||
*/
|
||||
public void removeConfigCache(String key) {
|
||||
redissonClient.getMapCache(CacheKey.CONFIG_CACHE_KEY).remove(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.byhah.cloud.autoconfigure.OrmAutoConfiguration,\
|
||||
com.byhah.cloud.autoconfigure.OrmSupportAutoConfiguration
|
||||
|
||||
# Application Listeners
|
||||
org.springframework.context.ApplicationListener=\
|
||||
com.byhah.cloud.autoconfigure.auto.EndAutoTableApplicationListener
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
com.byhah.cloud.autoconfigure.OrmAutoConfiguration
|
||||
com.byhah.cloud.autoconfigure.OrmSupportAutoConfiguration
|
||||
Reference in New Issue
Block a user