upgrade:
1、R 返回值去掉 dataMap 2、basecontroller 插入和 批量插入都使用 id返回值 3、优化postgres支持 修改 com.mybatisflex.core.handler 为 com.cool.core.mybatis.handler
This commit is contained in:
@@ -119,7 +119,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
|
||||
if (JSONUtil.isTypeJSONArray(body)) {
|
||||
JSONArray array = JSONUtil.parseArray(body);
|
||||
return R.ok(Dict.create()
|
||||
.set("ids", service.addBatch(requestParams, array.toList(currentEntityClass()))));
|
||||
.set("id", service.addBatch(requestParams, array.toList(currentEntityClass()))));
|
||||
} else {
|
||||
return R.ok(Dict.create().set("id",
|
||||
service.add(requestParams, requestParams.toBean(currentEntityClass()))));
|
||||
|
||||
@@ -9,6 +9,8 @@ import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.cool.core.base.service.MapperProviderService;
|
||||
import com.cool.core.mybatis.pg.PostgresSequenceSyncService;
|
||||
import com.cool.core.util.DatabaseDialectUtils;
|
||||
import com.cool.core.util.EntityUtils;
|
||||
import com.cool.modules.base.entity.sys.BaseSysConfEntity;
|
||||
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
|
||||
@@ -49,6 +51,8 @@ public class DBFromJsonInit {
|
||||
|
||||
final private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
final private PostgresSequenceSyncService postgresSequenceSyncService;
|
||||
|
||||
@Value("${cool.initData}")
|
||||
private boolean initData;
|
||||
|
||||
@@ -58,14 +62,24 @@ public class DBFromJsonInit {
|
||||
return;
|
||||
}
|
||||
// 初始化自定义的数据
|
||||
extractedDb();
|
||||
boolean initFlag = extractedDb();
|
||||
// 初始化菜单数据
|
||||
extractedMenu();
|
||||
initFlag = extractedMenu() || initFlag;
|
||||
// 发送数据库初始化完成事件
|
||||
eventPublisher.publishEvent(new DbInitCompleteEvent(this));
|
||||
if (initFlag) {
|
||||
// 如果是postgresql,同步序列
|
||||
syncIdentitySequences();
|
||||
}
|
||||
log.info("数据初始化完成!");
|
||||
}
|
||||
|
||||
private void syncIdentitySequences() {
|
||||
if (DatabaseDialectUtils.isPostgresql()) {
|
||||
postgresSequenceSyncService.syncIdentitySequences();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class DbInitCompleteEvent {
|
||||
private final Object source;
|
||||
@@ -79,21 +93,23 @@ public class DBFromJsonInit {
|
||||
/**
|
||||
* 解析插入业务数据
|
||||
*/
|
||||
private void extractedDb() {
|
||||
private boolean extractedDb() {
|
||||
try {
|
||||
// 加载 JSON 文件
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
Resource[] resources = resolver.getResources("classpath:cool/data/db/*.json");
|
||||
// 遍历所有.json文件
|
||||
analysisResources(resources);
|
||||
return analysisResources(resources);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to initialize data", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void analysisResources(Resource[] resources)
|
||||
private boolean analysisResources(Resource[] resources)
|
||||
throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
|
||||
String prefix = "db_";
|
||||
boolean isInit = false;
|
||||
for (Resource resource : resources) {
|
||||
File resourceFile = new File(resource.getURL().getFile());
|
||||
String fileName = prefix + resourceFile.getName();
|
||||
@@ -112,8 +128,10 @@ public class DBFromJsonInit {
|
||||
baseSysUserEntity.setCValue("success");
|
||||
// 当前文件已加载
|
||||
baseSysConfService.add(baseSysUserEntity);
|
||||
isInit = true;
|
||||
log.info("{} 业务数据初始化成功...", fileName);
|
||||
}
|
||||
return isInit;
|
||||
}
|
||||
|
||||
private void analysisJson(JSONObject jsonObject)
|
||||
@@ -158,7 +176,8 @@ public class DBFromJsonInit {
|
||||
/**
|
||||
* 解析插入菜单数据
|
||||
*/
|
||||
public void extractedMenu() {
|
||||
public boolean extractedMenu() {
|
||||
boolean initFlag = false;
|
||||
try {
|
||||
String prefix = "menu_";
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
@@ -173,10 +192,12 @@ public class DBFromJsonInit {
|
||||
continue;
|
||||
}
|
||||
analysisResources(resource, fileName);
|
||||
initFlag = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to initialize data", e);
|
||||
}
|
||||
return initFlag;
|
||||
}
|
||||
|
||||
private void analysisResources(Resource resource, String fileName) throws IOException {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.cool.core.mybatis.handler;
|
||||
|
||||
import com.cool.core.util.DatabaseDialectUtils;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.postgresql.util.PGobject;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
public abstract class BaseJsonTypeHandler<T> extends BaseTypeHandler<T> {
|
||||
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
|
||||
if (DatabaseDialectUtils.isPostgresql()) {
|
||||
PGobject jsonObject = new PGobject();
|
||||
jsonObject.setType("json");
|
||||
jsonObject.setValue(toJson(parameter));
|
||||
ps.setObject(i, jsonObject);
|
||||
} else {
|
||||
ps.setString(i, toJson(parameter));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
final String json = rs.getString(columnName);
|
||||
return StringUtil.noText(json) ? null : parseJson(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
final String json = rs.getString(columnIndex);
|
||||
return StringUtil.noText(json) ? null : parseJson(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
final String json = cs.getString(columnIndex);
|
||||
return StringUtil.noText(json) ? null : parseJson(json);
|
||||
}
|
||||
|
||||
protected abstract T parseJson(String json);
|
||||
|
||||
protected abstract String toJson(T object);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.cool.core.mybatis.handler;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONReader;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
public class Fastjson2TypeHandler extends BaseJsonTypeHandler<Object> {
|
||||
|
||||
private final Class<?> propertyType;
|
||||
private Class<?> genericType;
|
||||
private Type type;
|
||||
|
||||
private boolean supportAutoType = false;
|
||||
|
||||
public Fastjson2TypeHandler(Class<?> propertyType) {
|
||||
this.propertyType = propertyType;
|
||||
this.supportAutoType = propertyType.isInterface() || Modifier.isAbstract(propertyType.getModifiers());
|
||||
}
|
||||
|
||||
|
||||
public Fastjson2TypeHandler(Class<?> propertyType, Class<?> genericType) {
|
||||
this.propertyType = propertyType;
|
||||
this.genericType = genericType;
|
||||
this.type = TypeReference.collectionType((Class<? extends Collection>) propertyType, genericType);
|
||||
|
||||
Type actualTypeArgument = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||
if (actualTypeArgument instanceof Class) {
|
||||
this.supportAutoType = ((Class<?>) actualTypeArgument).isInterface()
|
||||
|| Modifier.isAbstract(((Class<?>) actualTypeArgument).getModifiers());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object parseJson(String json) {
|
||||
if (genericType != null && Collection.class.isAssignableFrom(propertyType)) {
|
||||
if (supportAutoType) {
|
||||
return JSON.parseArray(json, Object.class, JSONReader.Feature.SupportAutoType);
|
||||
} else {
|
||||
return JSON.parseObject(json, type);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (supportAutoType) {
|
||||
return JSON.parseObject(json, Object.class, JSONReader.Feature.SupportAutoType);
|
||||
} else {
|
||||
return JSON.parseObject(json, propertyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toJson(Object object) {
|
||||
if (supportAutoType) {
|
||||
return JSON.toJSONString(object
|
||||
, JSONWriter.Feature.WriteMapNullValue
|
||||
, JSONWriter.Feature.WriteNullListAsEmpty
|
||||
, JSONWriter.Feature.WriteNullStringAsEmpty, JSONWriter.Feature.WriteClassName
|
||||
);
|
||||
} else {
|
||||
return JSON.toJSONString(object
|
||||
, JSONWriter.Feature.WriteMapNullValue
|
||||
, JSONWriter.Feature.WriteNullListAsEmpty
|
||||
, JSONWriter.Feature.WriteNullStringAsEmpty
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.cool.core.mybatis.handler;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.mybatisflex.core.exception.FlexExceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public class JacksonTypeHandler extends BaseJsonTypeHandler<Object> {
|
||||
|
||||
private static ObjectMapper objectMapper;
|
||||
private final Class<?> propertyType;
|
||||
private Class<?> genericType;
|
||||
private JavaType javaType;
|
||||
|
||||
public JacksonTypeHandler(Class<?> propertyType) {
|
||||
this.propertyType = propertyType;
|
||||
}
|
||||
|
||||
public JacksonTypeHandler(Class<?> propertyType, Class<?> genericType) {
|
||||
this.propertyType = propertyType;
|
||||
this.genericType = genericType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object parseJson(String json) {
|
||||
try {
|
||||
if (genericType != null && Collection.class.isAssignableFrom(propertyType)) {
|
||||
return getObjectMapper().readValue(json, getJavaType());
|
||||
} else {
|
||||
return getObjectMapper().readValue(json, propertyType);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw FlexExceptions.wrap(e, "Can not parseJson by JacksonTypeHandler: " + json);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toJson(Object object) {
|
||||
try {
|
||||
return getObjectMapper().writeValueAsString(object);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw FlexExceptions.wrap(e, "Can not convert object to Json by JacksonTypeHandler: " + object);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public JavaType getJavaType() {
|
||||
if (javaType == null){
|
||||
javaType = getObjectMapper().getTypeFactory().constructCollectionType((Class<? extends Collection>) propertyType, genericType);
|
||||
}
|
||||
return javaType;
|
||||
}
|
||||
|
||||
public static ObjectMapper getObjectMapper() {
|
||||
if (null == objectMapper) {
|
||||
objectMapper = new ObjectMapper();
|
||||
}
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
public static void setObjectMapper(ObjectMapper objectMapper) {
|
||||
JacksonTypeHandler.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.cool.core.mybatis.pg;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
/**
|
||||
* PostgreSQL Identity 序列同步服务
|
||||
* 解决PostgreSQL 默认的序列机制,序列会自动递增,当手动插入指定id时需调用同步接口,否则id会重复。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class PostgresSequenceSyncService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
public PostgresSequenceSyncService(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public void syncIdentitySequences() {
|
||||
log.info("⏳ 开始同步 PostgreSQL Identity 序列...");
|
||||
|
||||
// 查询所有 identity 字段
|
||||
String identityColumnQuery = """
|
||||
SELECT table_schema, table_name, column_name
|
||||
FROM information_schema.columns
|
||||
WHERE is_identity = 'YES'
|
||||
AND table_schema = 'public'
|
||||
""";
|
||||
|
||||
List<Map<String, Object>> identityColumns = jdbcTemplate.queryForList(identityColumnQuery);
|
||||
|
||||
for (Map<String, Object> col : identityColumns) {
|
||||
String schema = (String) col.get("table_schema");
|
||||
String table = (String) col.get("table_name");
|
||||
String column = (String) col.get("column_name");
|
||||
|
||||
String fullTable = schema + "." + table;
|
||||
|
||||
// 获取对应的序列名
|
||||
String seqNameSql = "SELECT pg_get_serial_sequence(?, ?)";
|
||||
String seqName = jdbcTemplate.queryForObject(seqNameSql, String.class, fullTable, column);
|
||||
|
||||
if (seqName == null) {
|
||||
log.warn("⚠️ 无法获取序列:{}.{}", table, column);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取当前最大 ID
|
||||
Long maxId = jdbcTemplate.queryForObject(
|
||||
String.format("SELECT COALESCE(MAX(%s), 0) FROM %s", column, fullTable),
|
||||
Long.class
|
||||
);
|
||||
|
||||
if (maxId != null && maxId > 0) { // 正确的:setval 有返回值,必须用 queryForObject
|
||||
String setvalSql = "SELECT setval(?, ?)";
|
||||
Long newVal = jdbcTemplate.queryForObject(setvalSql, Long.class, seqName, maxId);
|
||||
log.info("✅ 同步序列 [{}] -> 当前最大 ID: {}", seqName, newVal);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("✅ PostgreSQL Identity 序列同步完成。");
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 返回信息
|
||||
@@ -24,11 +22,7 @@ public class R<T> implements Serializable {
|
||||
|
||||
@Schema(title = "响应数据")
|
||||
private T data;
|
||||
|
||||
@Schema(title = "响应数据")
|
||||
private Map<String, Object> dataMap = new HashMap<String, Object>();
|
||||
|
||||
|
||||
|
||||
public R() {
|
||||
|
||||
}
|
||||
@@ -70,14 +64,10 @@ public class R<T> implements Serializable {
|
||||
|
||||
|
||||
public R<T> put(String key, Object value) {
|
||||
if ( key.equals( "code") ) {
|
||||
this.code = (int)value;
|
||||
} else if ( key.equals( "message") ) {
|
||||
this.message = (String)value;
|
||||
} else if ( key.equals( "data") ) {
|
||||
this.data = (T) value;
|
||||
} else {
|
||||
dataMap.put(key, value);
|
||||
switch (key) {
|
||||
case "code" -> this.code = (int) value;
|
||||
case "message" -> this.message = (String) value;
|
||||
case "data" -> this.data = (T) value;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
27
src/main/java/com/cool/core/util/AutoTypeConverter.java
Normal file
27
src/main/java/com/cool/core/util/AutoTypeConverter.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.cool.core.util;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class AutoTypeConverter {
|
||||
/**
|
||||
* 将字符串自动转换为数字或保留为字符串
|
||||
*
|
||||
* @param input 输入字符串
|
||||
* @return Integer / Long / String
|
||||
*/
|
||||
public static Serializable autoConvert(Object input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
if (NumberUtil.isInteger(input.toString())) {
|
||||
return Convert.convert(Integer.class, input);
|
||||
} else if (NumberUtil.isLong(input.toString())) {
|
||||
return Convert.convert(Long.class, input);
|
||||
} else {
|
||||
return (Serializable) input;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,16 +12,25 @@ import javax.sql.DataSource;
|
||||
public class DatabaseDialectUtils {
|
||||
private static String dialect;
|
||||
|
||||
public static String getDatabaseDialect() {
|
||||
public static String getDatabaseDialect(DataSource dataSource) {
|
||||
if (dialect == null) {
|
||||
dialect = determineDatabaseType();
|
||||
dialect = determineDatabaseType(dataSource);
|
||||
}
|
||||
return dialect;
|
||||
}
|
||||
|
||||
private static String determineDatabaseType() {
|
||||
// 从 DataSource 获取连接
|
||||
public static boolean isPostgresql() {
|
||||
DataSource dataSource = SpringContextUtils.getBean(DataSource.class);
|
||||
return DatabaseDialect.PostgreSQL.equals(getDatabaseDialect(dataSource));
|
||||
}
|
||||
|
||||
public static boolean isPostgresql(DataSource dataSource) {
|
||||
return DatabaseDialect.PostgreSQL.equals(getDatabaseDialect(dataSource));
|
||||
}
|
||||
|
||||
|
||||
private static String determineDatabaseType(DataSource dataSource) {
|
||||
// 从 DataSource 获取连接
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
// 获取元数据
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.cool.modules.base.entity.sys;
|
||||
import com.cool.core.base.BaseEntity;
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
|
||||
import com.cool.core.mybatis.handler.Fastjson2TypeHandler;
|
||||
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.cool.modules.base.entity.sys;
|
||||
import com.cool.core.base.BaseEntity;
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
|
||||
import com.cool.core.mybatis.handler.Fastjson2TypeHandler;
|
||||
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.update.UpdateChain;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.autotable.core.constants.DatabaseDialect;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
@@ -55,8 +54,7 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
||||
// 用户的部门权限
|
||||
Long[] permsDepartmentArr = coolCache.get("admin:department:" + tokenInfo.get("userId"),
|
||||
Long[].class);
|
||||
String databaseDialect = DatabaseDialectUtils.getDatabaseDialect();
|
||||
if (databaseDialect.equals(DatabaseDialect.PostgreSQL)) {
|
||||
if (DatabaseDialectUtils.isPostgresql()) {
|
||||
// 兼容postgresql
|
||||
qw.select("base_sys_user.id","base_sys_user.create_time","base_sys_user.department_id",
|
||||
"base_sys_user.email","base_sys_user.head_img","base_sys_user.name","base_sys_user.nick_name",
|
||||
@@ -96,7 +94,7 @@ public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, B
|
||||
permsDepartmentArr == null || permsDepartmentArr.length == 0 ? new Long[]{null}
|
||||
: permsDepartmentArr,
|
||||
!CoolSecurityUtil.getAdminUsername().equals("admin")));
|
||||
if (databaseDialect.equals(DatabaseDialect.PostgreSQL)) {
|
||||
if (DatabaseDialectUtils.isPostgresql()) {
|
||||
// 兼容postgresql
|
||||
qw.groupBy("base_sys_user.id","base_sys_user.create_time","base_sys_user.department_id",
|
||||
"base_sys_user.email","base_sys_user.head_img","base_sys_user.name","base_sys_user.nick_name",
|
||||
|
||||
@@ -4,8 +4,8 @@ import com.cool.core.base.BaseEntity;
|
||||
import com.cool.core.config.PluginJson;
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
|
||||
import com.mybatisflex.core.handler.JacksonTypeHandler;
|
||||
import com.cool.core.mybatis.handler.Fastjson2TypeHandler;
|
||||
import com.cool.core.mybatis.handler.JacksonTypeHandler;
|
||||
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
|
||||
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.cool.modules.recycle.entity;
|
||||
import com.cool.core.base.BaseEntity;
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
|
||||
import com.cool.core.mybatis.handler.Fastjson2TypeHandler;
|
||||
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.cool.core.util.AutoTypeConverter;
|
||||
import com.cool.modules.task.entity.TaskInfoEntity;
|
||||
import com.cool.modules.task.entity.TaskLogEntity;
|
||||
import com.cool.modules.task.service.TaskInfoLogService;
|
||||
@@ -36,7 +37,7 @@ public class ScheduleJob extends QuartzJobBean {
|
||||
Scheduler scheduler = SpringUtil.getBean(Scheduler.class);
|
||||
|
||||
TaskInfoEntity taskInfoEntity = taskInfoService
|
||||
.getById(context.getJobDetail().getKey().getName().split("_")[1]);
|
||||
.getById(AutoTypeConverter.autoConvert(context.getJobDetail().getKey().getName().split("_")[1]));
|
||||
if (ObjUtil.isEmpty(taskInfoEntity)) {
|
||||
log.warn("taskInfoEntity is null");
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.dromara.autotable.core.strategy.pgsql.builder;
|
||||
|
||||
import org.dromara.autotable.annotation.enums.DefaultValueEnum;
|
||||
import org.dromara.autotable.core.strategy.ColumnMetadata;
|
||||
import org.dromara.autotable.core.utils.StringConnectHelper;
|
||||
import org.dromara.autotable.core.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 列相关的SQL生成器
|
||||
* 覆盖原始的ColumnSqlBuilder GENERATED ALWAYS AS IDENTITY 改为 GENERATED BY DEFAULT AS IDENTITY
|
||||
* 已提issues https://gitee.com/dromara/auto-table/issues/IC6TR5
|
||||
*/
|
||||
public class ColumnSqlBuilder {
|
||||
|
||||
/**
|
||||
* 生成字段相关的SQL片段
|
||||
*
|
||||
* @param columnMetadata 列元数据
|
||||
* @return 列相关的sql
|
||||
*/
|
||||
public static String buildSql(ColumnMetadata columnMetadata) {
|
||||
// 例子:"name" varchar(100) NULL DEFAULT '张三' COMMENT '名称'
|
||||
// 例子:"id" int4(32) NOT NULL AUTO_INCREMENT COMMENT '主键'
|
||||
StringConnectHelper sql = StringConnectHelper.newInstance("{columnName} {typeAndLength} {null} {default}")
|
||||
.replace("{columnName}", columnMetadata.getName())
|
||||
.replace("{typeAndLength}", () -> columnMetadata.getType().getDefaultFullType());
|
||||
|
||||
// 如果是自增列,则使用GENERATED ALWAYS AS IDENTITY, 忽略not null和默认值的配置
|
||||
if (columnMetadata.isAutoIncrement()) {
|
||||
return sql.replace("{null} {default}", "GENERATED BY DEFAULT AS IDENTITY").toString();
|
||||
}
|
||||
|
||||
return sql.replace("{null}", columnMetadata.isNotNull() ? "NOT NULL" : "")
|
||||
.replace("{default}", () -> {
|
||||
// 指定NULL
|
||||
DefaultValueEnum defaultValueType = columnMetadata.getDefaultValueType();
|
||||
if (defaultValueType == DefaultValueEnum.NULL) {
|
||||
return "DEFAULT NULL";
|
||||
}
|
||||
// 指定空字符串
|
||||
if (defaultValueType == DefaultValueEnum.EMPTY_STRING) {
|
||||
return "DEFAULT ''";
|
||||
}
|
||||
// 自定义
|
||||
String defaultValue = columnMetadata.getDefaultValue();
|
||||
if (DefaultValueEnum.isCustom(defaultValueType) && StringUtils.hasText(defaultValue)) {
|
||||
return "DEFAULT " + defaultValue;
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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 org.springframework.boot.autoconfigure.quartz;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.cool.core.util.DatabaseDialectUtils;
|
||||
import org.quartz.Calendar;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.Trigger;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.sql.init.OnDatabaseInitializationCondition;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Quartz Scheduler.
|
||||
* 覆盖原始的QuartzAutoConfiguration,兼容postgres数据库
|
||||
* properties.getProperties().put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
|
||||
* @author Vedran Pavic
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@AutoConfiguration(after = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
|
||||
LiquibaseAutoConfiguration.class, FlywayAutoConfiguration.class })
|
||||
@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class })
|
||||
@EnableConfigurationProperties(QuartzProperties.class)
|
||||
public class QuartzAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SchedulerFactoryBean quartzScheduler(QuartzProperties properties,
|
||||
ObjectProvider<SchedulerFactoryBeanCustomizer> customizers, ObjectProvider<JobDetail> jobDetails,
|
||||
Map<String, Calendar> calendars, ObjectProvider<Trigger> triggers, ApplicationContext applicationContext) {
|
||||
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
|
||||
SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();
|
||||
jobFactory.setApplicationContext(applicationContext);
|
||||
schedulerFactoryBean.setJobFactory(jobFactory);
|
||||
if (properties.getSchedulerName() != null) {
|
||||
schedulerFactoryBean.setSchedulerName(properties.getSchedulerName());
|
||||
}
|
||||
schedulerFactoryBean.setAutoStartup(properties.isAutoStartup());
|
||||
schedulerFactoryBean.setStartupDelay((int) properties.getStartupDelay().getSeconds());
|
||||
schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(properties.isWaitForJobsToCompleteOnShutdown());
|
||||
schedulerFactoryBean.setOverwriteExistingJobs(properties.isOverwriteExistingJobs());
|
||||
if (!properties.getProperties().isEmpty()) {
|
||||
schedulerFactoryBean.setQuartzProperties(asProperties(properties.getProperties()));
|
||||
}
|
||||
schedulerFactoryBean.setJobDetails(jobDetails.orderedStream().toArray(JobDetail[]::new));
|
||||
schedulerFactoryBean.setCalendars(calendars);
|
||||
schedulerFactoryBean.setTriggers(triggers.orderedStream().toArray(Trigger[]::new));
|
||||
customizers.orderedStream().forEach((customizer) -> customizer.customize(schedulerFactoryBean));
|
||||
return schedulerFactoryBean;
|
||||
}
|
||||
|
||||
private Properties asProperties(Map<String, String> source) {
|
||||
Properties properties = new Properties();
|
||||
properties.putAll(source);
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnSingleCandidate(DataSource.class)
|
||||
@ConditionalOnProperty(prefix = "spring.quartz", name = "job-store-type", havingValue = "jdbc")
|
||||
@Import(DatabaseInitializationDependencyConfigurer.class)
|
||||
protected static class JdbcStoreTypeConfiguration {
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
public SchedulerFactoryBeanCustomizer dataSourceCustomizer(QuartzProperties properties, DataSource dataSource,
|
||||
@QuartzDataSource ObjectProvider<DataSource> quartzDataSource,
|
||||
ObjectProvider<PlatformTransactionManager> transactionManager,
|
||||
@QuartzTransactionManager ObjectProvider<PlatformTransactionManager> quartzTransactionManager) {
|
||||
return (schedulerFactoryBean) -> {
|
||||
DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);
|
||||
schedulerFactoryBean.setDataSource(dataSourceToUse);
|
||||
PlatformTransactionManager txManager = getTransactionManager(transactionManager,
|
||||
quartzTransactionManager);
|
||||
if (txManager != null) {
|
||||
schedulerFactoryBean.setTransactionManager(txManager);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private DataSource getDataSource(DataSource dataSource, ObjectProvider<DataSource> quartzDataSource) {
|
||||
DataSource dataSourceIfAvailable = quartzDataSource.getIfAvailable();
|
||||
return (dataSourceIfAvailable != null) ? dataSourceIfAvailable : dataSource;
|
||||
}
|
||||
|
||||
private PlatformTransactionManager getTransactionManager(
|
||||
ObjectProvider<PlatformTransactionManager> transactionManager,
|
||||
ObjectProvider<PlatformTransactionManager> quartzTransactionManager) {
|
||||
PlatformTransactionManager transactionManagerIfAvailable = quartzTransactionManager.getIfAvailable();
|
||||
return (transactionManagerIfAvailable != null) ? transactionManagerIfAvailable
|
||||
: transactionManager.getIfUnique();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(QuartzDataSourceScriptDatabaseInitializer.class)
|
||||
@Conditional(OnQuartzDatasourceInitializationCondition.class)
|
||||
public QuartzDataSourceScriptDatabaseInitializer quartzDataSourceScriptDatabaseInitializer(
|
||||
DataSource dataSource, @QuartzDataSource ObjectProvider<DataSource> quartzDataSource,
|
||||
QuartzProperties properties) {
|
||||
DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);
|
||||
if (DatabaseDialectUtils.isPostgresql(dataSource)) {
|
||||
properties.getProperties().put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
|
||||
}
|
||||
return new QuartzDataSourceScriptDatabaseInitializer(dataSourceToUse, properties);
|
||||
}
|
||||
|
||||
static class OnQuartzDatasourceInitializationCondition extends OnDatabaseInitializationCondition {
|
||||
|
||||
OnQuartzDatasourceInitializationCondition() {
|
||||
super("Quartz", "spring.quartz.jdbc.initialize-schema");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user