mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-12 07:25:39 +08:00
ref 升级脚手架依赖
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-config</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-exception-handler</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-header-holder</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-jackson</artifactId>
|
||||
|
||||
@@ -8,6 +8,7 @@ import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* jackson常用工具类封装
|
||||
@@ -130,4 +131,24 @@ public class JacksonUtil {
|
||||
throw new RuntimeException("json反序列化失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对象转为map
|
||||
*/
|
||||
public Map<String, Object> parseObj(Object mchApply) {
|
||||
return parseObj(mchApply,true);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> parseObj(Object mchApply, boolean ignoreNull) {
|
||||
try {
|
||||
if (ignoreNull) {
|
||||
return ignoreNullObjectMapper.convertValue(mchApply, Map.class);
|
||||
}
|
||||
return objectMapper.convertValue(mchApply, Map.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new RuntimeException("json反序列化失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-log</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-mybatis-plus</artifactId>
|
||||
@@ -63,6 +63,17 @@
|
||||
<artifactId>common-spring</artifactId>
|
||||
<version>${bootx-platform.version}</version>
|
||||
</dependency>
|
||||
<!-- hutool 组件 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-db</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package cn.bootx.platform.common.mybatisplus.handler;
|
||||
|
||||
import cn.bootx.platform.core.util.JsonUtil;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.MappedJdbcTypes;
|
||||
@@ -35,13 +35,13 @@ public class IntegerListTypeHandler extends AbstractJsonTypeHandler<List<Integer
|
||||
@Override
|
||||
public List<Integer> parse(String json) {
|
||||
if (StrUtil.isNotBlank(json)){
|
||||
return JsonUtil.toBean(json, new TypeReference<>() {}, false);
|
||||
return JSONUtil.toBean(json, new TypeReference<>() {}, false);
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJson(List<Integer> obj) {
|
||||
return JsonUtil.toJsonStr(obj);
|
||||
return JSONUtil.toJsonStr(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package cn.bootx.platform.common.mybatisplus.handler;
|
||||
import cn.bootx.platform.core.util.JsonUtil;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import org.apache.ibatis.type.MappedJdbcTypes;
|
||||
@@ -30,13 +31,13 @@ public class LongListTypeHandler extends AbstractJsonTypeHandler<List<Long>> {
|
||||
@Override
|
||||
public List<Long> parse(String json) {
|
||||
if (StrUtil.isNotBlank(json)){
|
||||
return JsonUtil.toBean(json, new TypeReference<>() {}, false);
|
||||
return JSONUtil.toBean(json, new TypeReference<>() {}, false);
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJson(List<Long> obj) {
|
||||
return JsonUtil.toJsonStr(obj);
|
||||
return JSONUtil.toJsonStr(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,6 @@ public class StringListTypeHandler extends AbstractJsonTypeHandler<List<String>>
|
||||
|
||||
@Override
|
||||
public String toJson(List<String> obj) {
|
||||
return JsonUtil.toJsonStr(obj);
|
||||
return JSONUtil.toJsonStr(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package cn.bootx.platform.common.mybatisplus.util;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.function.ToResult;
|
||||
import cn.bootx.platform.core.annotation.BigField;
|
||||
import cn.bootx.platform.core.exception.BizException;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.core.rest.result.PageResult;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
@@ -20,7 +22,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.apache.ibatis.reflection.property.PropertyNamer;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -159,4 +164,17 @@ public class MpUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前数据库类型, 别忘了关闭, 不然会连接池泄露
|
||||
*/
|
||||
public String getDbType(){
|
||||
try {
|
||||
try (Connection connection = SpringUtil.getBean(DataSource.class).getConnection()) {
|
||||
return connection.getMetaData().getDatabaseProductName();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new BizException("获取数据库类型失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
package cn.bootx.platform.common.mybatisplus.util;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Db;
|
||||
import cn.hutool.db.Entity;
|
||||
import cn.hutool.db.handler.BeanHandler;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.enums.SqlMethod;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 数据库工具类
|
||||
*
|
||||
* @author nn200433
|
||||
* @date 2024-03-28 09:32:34
|
||||
*/
|
||||
@Slf4j
|
||||
public class MybatisDbUtil {
|
||||
|
||||
private static final String PARAM_KEY_PRE = "ew.paramNameValuePairs.";
|
||||
private static final String UPDATE_SET_PREFIX = "SET";
|
||||
private static final String SQL_PREFIX_AND_SUFFIX = "'";
|
||||
public static final String PLACEHOLDER_PREFIX = "#{";
|
||||
private static final String PLACEHOLDER_SUFFIX = "}";
|
||||
private static final PropertyPlaceholderHelper PLACEHOLDER_HELPER = new PropertyPlaceholderHelper(PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX);
|
||||
|
||||
/**
|
||||
* 物理删除
|
||||
*
|
||||
* @param tableClz 数据表实体类型
|
||||
* @param ids 主键
|
||||
* @return int 影响行数
|
||||
* @author nn200433
|
||||
*/
|
||||
public static int delete(Class<?> tableClz, String... ids) {
|
||||
final TableInfo tableInfo = getTableInfo(tableClz);
|
||||
final String tableName = tableInfo.getTableName();
|
||||
final String keyColumn = tableInfo.getKeyColumn();
|
||||
Assert.notBlank(keyColumn, "{} 未设置 @TableId 注解!", tableClz);
|
||||
int count = 0;
|
||||
try {
|
||||
count = Db.use(dataSource()).del(Entity.create(tableName).set(keyColumn, ids));
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 物理删除
|
||||
*
|
||||
* <p>
|
||||
* 请使用{@link com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper}构造wrapper
|
||||
* </p>
|
||||
*
|
||||
* @param wrapper 包装物
|
||||
* @return int 影响行数
|
||||
* @author nn200433
|
||||
*/
|
||||
public static <T> int delete(AbstractWrapper<T, ?, ?> wrapper) {
|
||||
final Class<T> entityClass = (Class<T>) getEntityClass(wrapper);
|
||||
final TableInfo tableInfo = getTableInfo(entityClass);
|
||||
final String whereSql = wrapper.getCustomSqlSegment();
|
||||
final String tableName = tableInfo.getTableName();
|
||||
final Map<String, Object> paramNameValuePairs = wrapper.getParamNameValuePairs();
|
||||
int count = 0;
|
||||
try {
|
||||
final String sql = getSql(SqlMethod.DELETE, tableName, StrUtil.EMPTY, StrUtil.EMPTY, whereSql, null, paramNameValuePairs);
|
||||
count = Db.use(dataSource()).execute(sql);
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过ID查询数据(忽略逻辑删除)
|
||||
*
|
||||
* @param id 主键id值
|
||||
* @param entityClass 返回的实体类型
|
||||
* @return {@link T }
|
||||
* @author nn200433
|
||||
*/
|
||||
public static <T> T selectById(Object id, Class<T> entityClass) {
|
||||
final TableInfo tableInfo = getTableInfo(entityClass);
|
||||
final String keyColumn = tableInfo.getKeyColumn();
|
||||
final QueryWrapper<T> wrapper = new QueryWrapper<T>().eq(keyColumn, id);
|
||||
final String tableName = tableInfo.getTableName();
|
||||
final String whereSql = wrapper.getCustomSqlSegment();
|
||||
final Map<String, Object> paramNameValuePairs = wrapper.getParamNameValuePairs();
|
||||
T result = null;
|
||||
try {
|
||||
final String sql = getSql(SqlMethod.SELECT_BY_MAP, tableName, StrUtil.EMPTY, tableInfo.getAllSqlSelect(), whereSql, null, paramNameValuePairs);
|
||||
result = Db.use(dataSource()).query(sql, new BeanHandler<T>(entityClass));
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询列表(忽略逻辑删除)
|
||||
*
|
||||
* <p>
|
||||
* 请使用{@link com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper}构造wrapper。
|
||||
* <br/>
|
||||
* 举例:new LambdaQueryWrapper<SmsTemplate>(Entity.class).eq(Entity::getCode, "2");
|
||||
* </p>
|
||||
*
|
||||
* @param wrapper 包装物
|
||||
* @return {@link List }<{@link T }>
|
||||
* @author nn200433
|
||||
*/
|
||||
public static <T> List<T> selectList(AbstractWrapper<T, ?, ?> wrapper) {
|
||||
List<T> resultList = new ArrayList<T>();
|
||||
final Class<T> entityClass = (Class<T>) getEntityClass(wrapper);
|
||||
final TableInfo tableInfo = getTableInfo(entityClass);
|
||||
final String whereSql = wrapper.getCustomSqlSegment();
|
||||
final String columnSql = wrapper.getSqlSelect();
|
||||
final String tableName = tableInfo.getTableName();
|
||||
final Map<String, Object> paramNameValuePairs = wrapper.getParamNameValuePairs();
|
||||
try {
|
||||
final String sql = getSql(SqlMethod.SELECT_LIST, tableName, StrUtil.EMPTY, StrUtil.blankToDefault(columnSql, tableInfo.getAllSqlSelect()), whereSql, null, paramNameValuePairs);
|
||||
resultList = Db.use(dataSource()).query(sql, entityClass);
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新(忽略逻辑删除)
|
||||
*
|
||||
* @param entity 实体类
|
||||
* @return int 影响行数
|
||||
* @author nn200433
|
||||
*/
|
||||
public static <T> int update(T entity) {
|
||||
return update(entity, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过条件更新数据(忽略逻辑删除)
|
||||
* <p>
|
||||
* 请使用{@link com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper}构造wrapper
|
||||
* </p>
|
||||
*
|
||||
* @param entity 实体类
|
||||
* @param wrapper 包装物
|
||||
* @return int 影响行数
|
||||
* @author nn200433
|
||||
*/
|
||||
public static <T> int update(T entity, AbstractWrapper<T, ?, ?> wrapper) {
|
||||
final TableInfo tableInfo = getTableInfo(entity.getClass());
|
||||
final String tableName = tableInfo.getTableName();
|
||||
if (null == wrapper) {
|
||||
final String keyProperty = tableInfo.getKeyProperty();
|
||||
Assert.notBlank(keyProperty, "{} 未设置 @TableId 注解!", keyProperty);
|
||||
wrapper = new UpdateWrapper<T>(entity).eq(keyProperty, ReflectUtil.getFieldValue(entity, keyProperty));
|
||||
}
|
||||
final String whereSql = wrapper.getCustomSqlSegment();
|
||||
final Map<String, Object> paramNameValuePairs = wrapper.getParamNameValuePairs();
|
||||
int count = 0;
|
||||
try {
|
||||
final String sql = getSql(SqlMethod.UPDATE, tableName, StrUtil.EMPTY, tableInfo.getAllSqlSet(Boolean.TRUE, StrUtil.EMPTY), whereSql, BeanUtil.beanToMap(entity), paramNameValuePairs);
|
||||
count = Db.use(dataSource()).execute(sql);
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取sql
|
||||
*
|
||||
* @param method SQL方法
|
||||
* @param tableName 数据库表名称
|
||||
* @param firstSql firtSql
|
||||
* @param columnSql 字段sql
|
||||
* @param whereSql where条件sql
|
||||
* @param setMap set参数
|
||||
* @param paramNameValuePairs where条件值
|
||||
* @return {@link String }
|
||||
* @author nn200433
|
||||
*/
|
||||
private static String getSql(SqlMethod method, String tableName, String firstSql, String columnSql, String whereSql,
|
||||
Map<String, Object> setMap, Map<String, Object> paramNameValuePairs) {
|
||||
final Map<String, Object> paramMap = new HashMap<String, Object>(paramNameValuePairs.size());
|
||||
for (final Map.Entry<String, Object> entry : paramNameValuePairs.entrySet()) {
|
||||
paramMap.put(PARAM_KEY_PRE + entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (CollUtil.isNotEmpty(setMap)) {
|
||||
paramMap.putAll(setMap);
|
||||
}
|
||||
// 害人不浅,包了这么标签
|
||||
String originalSql = null;
|
||||
switch (method) {
|
||||
case DELETE:
|
||||
originalSql = String.format(method.getSql(), tableName, whereSql, StrUtil.EMPTY);
|
||||
break;
|
||||
case UPDATE:
|
||||
columnSql = StrUtil.addPrefixIfNot(columnSql, UPDATE_SET_PREFIX + StrUtil.SPACE);
|
||||
columnSql = StrUtil.removeSuffix(columnSql, StrUtil.COMMA);
|
||||
originalSql = String.format(method.getSql(), tableName, columnSql, whereSql, StrUtil.EMPTY);
|
||||
break;
|
||||
case SELECT_LIST:
|
||||
// 判断个锤子OrderBy注解,麻烦
|
||||
originalSql = String.format(method.getSql(), firstSql, columnSql, tableName, whereSql, StrUtil.EMPTY, StrUtil.EMPTY);
|
||||
break;
|
||||
case SELECT_BY_MAP:
|
||||
// 垃圾 SELECT_BY_ID ,限制那么多
|
||||
originalSql = String.format(method.getSql(), columnSql, tableName, whereSql, StrUtil.EMPTY);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
final String preSql = StrUtil.trim(HtmlUtil.cleanHtmlTag(originalSql));
|
||||
return resolveParams(preSql, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从wrapper中尝试获取实体类型
|
||||
*
|
||||
* @param queryWrapper 条件构造器
|
||||
* @param <T> 实体类型
|
||||
* @return 实体类型
|
||||
*/
|
||||
private static <T> Class<T> getEntityClass(AbstractWrapper<T, ?, ?> queryWrapper) {
|
||||
Class<T> entityClass = queryWrapper.getEntityClass();
|
||||
if (entityClass == null) {
|
||||
T entity = queryWrapper.getEntity();
|
||||
if (entity != null) {
|
||||
entityClass = (Class<T>) entity.getClass();
|
||||
}
|
||||
}
|
||||
Assert.notNull(entityClass, "error: can not get entityClass from wrapper");
|
||||
return entityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表信息,获取不到报错提示
|
||||
*
|
||||
* @param entityClass 实体类
|
||||
* @param <T> 实体类型
|
||||
* @return 对应表信息
|
||||
*/
|
||||
private static <T> TableInfo getTableInfo(Class<T> entityClass) {
|
||||
return Optional.ofNullable(TableInfoHelper.getTableInfo(entityClass))
|
||||
.orElseThrow(() -> ExceptionUtils.mpe("error: can not find TableInfo from Class: \"%s\".", entityClass.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析参数
|
||||
*
|
||||
* @param str 包含要替换的占位符的值
|
||||
* @param param 参数
|
||||
* @return @return {@link String }
|
||||
* @author nn200433
|
||||
*/
|
||||
private static String resolveParams(String str, Map<String, Object> param) {
|
||||
return PLACEHOLDER_HELPER.replacePlaceholders(str, key -> {
|
||||
// final String v = MapUtil.(param, key);
|
||||
final Object v = param.get(key);
|
||||
if (null == v) {
|
||||
return "null";
|
||||
}
|
||||
final Class<?> clz = v.getClass();
|
||||
if (clz.equals(Date.class)) {
|
||||
final Date vd = (Date) v;
|
||||
return StrUtil.wrap(DateUtil.format(vd, DatePattern.NORM_DATETIME_FORMAT), SQL_PREFIX_AND_SUFFIX);
|
||||
} else if (clz.equals(LocalDateTime.class)) {
|
||||
final LocalDateTime vd = (LocalDateTime) v;
|
||||
return StrUtil.wrap(DateUtil.formatLocalDateTime(vd), SQL_PREFIX_AND_SUFFIX);
|
||||
}
|
||||
return StrUtil.wrap(Convert.toStr(v), SQL_PREFIX_AND_SUFFIX);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据源
|
||||
*
|
||||
* @return {@link DataSource }
|
||||
* @author nn200433
|
||||
*/
|
||||
private static DataSource dataSource() {
|
||||
return SpringUtil.getBean(DataSource.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-redis</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-spring</artifactId>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.common.spring.configuration;
|
||||
|
||||
import cn.bootx.platform.core.util.JsonUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
@@ -39,7 +40,7 @@ public class AsyncExecutorConfiguration implements AsyncConfigurer {
|
||||
@Override
|
||||
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
|
||||
|
||||
log.error("异步方法中发生异常,方法:{},参数:{},异常:{}", method.getName(), JsonUtil.toJsonStr(objects),
|
||||
log.error("异步方法中发生异常,方法:{},参数:{},异常:{}", method.getName(), JSONUtil.toJsonStr(objects),
|
||||
throwable.getMessage());
|
||||
log.error("详细异常信息", throwable);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-common</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>common-swagger</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 组件忽略注解
|
||||
* 忽略租户数据隔离注解
|
||||
* @author xxm
|
||||
* @since 2024/6/25
|
||||
*/
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.time.LocalDateTime;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BaseResult {
|
||||
public class BaseResult{
|
||||
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@@ -8,7 +8,7 @@ import lombok.experimental.UtilityClass;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* json工具类, 基于hutool的进行封装,
|
||||
* json工具类, 基于hutool的进行封装, 仅用于与业务系统交互使用, 为了保持与SDK
|
||||
* 对java8的LocalDateTime时间格式进行转换, 但无法处理LocalDate, LocalTime格式, 需要使用JacksonUtil进行处理
|
||||
* @author xxm
|
||||
* @since 2024/6/28
|
||||
@@ -17,32 +17,6 @@ import java.util.Collection;
|
||||
public class JsonUtil {
|
||||
private final JSONConfig JSON_CONFIG = JSONConfig.create().setDateFormat(DatePattern.NORM_DATETIME_PATTERN);
|
||||
|
||||
/**
|
||||
* 转换为实体
|
||||
*/
|
||||
public <T> T toBean(String json, Class<T> clazz){
|
||||
JSONObject jsonObject = new JSONObject(json, JSON_CONFIG);
|
||||
return JSONUtil.toBean(jsonObject, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体
|
||||
*/
|
||||
public <T> T toBean(String json, TypeReference<T> reference){
|
||||
JSON parse = JSONUtil.parse(json, JSON_CONFIG);
|
||||
return parse.toBean(reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为实体
|
||||
*/
|
||||
public <T> T toBean(String json, TypeReference<T> reference, boolean ignoreError){
|
||||
JSONConfig jsonConfig = JSONConfig.create()
|
||||
.setDateFormat(DatePattern.NORM_DATETIME_PATTERN)
|
||||
.setIgnoreError(ignoreError);
|
||||
JSON parse = JSONUtil.parse(json, jsonConfig);
|
||||
return parse.toBean(reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化为字符串
|
||||
@@ -61,9 +35,10 @@ public class JsonUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON字符串转JSONObject对象
|
||||
* 转换为实体, 仅供处理验签时使用, 其他场景不要使用
|
||||
*/
|
||||
public JSONObject parseObj(String jsonStr){
|
||||
return JSONUtil.parseObj(jsonStr, JSON_CONFIG);
|
||||
public <T> T toBean(String json, TypeReference<T> reference) {
|
||||
JSON parse = JSONUtil.parse(json, JSON_CONFIG);
|
||||
return parse.toBean(reference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>service-baseapi</module>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-service</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>service-baseapi</artifactId>
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package cn.bootx.platform.baseapi.controller.protocol;
|
||||
|
||||
import cn.bootx.platform.baseapi.param.protocol.UserProtocolParam;
|
||||
import cn.bootx.platform.baseapi.param.protocol.UserProtocolQuery;
|
||||
import cn.bootx.platform.baseapi.result.protocol.UserProtocolResult;
|
||||
import cn.bootx.platform.baseapi.service.protocol.UserProtocolService;
|
||||
import cn.bootx.platform.core.annotation.IgnoreAuth;
|
||||
import cn.bootx.platform.core.annotation.RequestGroup;
|
||||
import cn.bootx.platform.core.annotation.RequestPath;
|
||||
import cn.bootx.platform.core.rest.Res;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.core.rest.result.PageResult;
|
||||
import cn.bootx.platform.core.rest.result.Result;
|
||||
import cn.bootx.platform.core.validation.ValidationGroup;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 用户协议
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@Validated
|
||||
@Tag(name = "用户协议")
|
||||
@RequestGroup(groupCode = "UserProtocol", groupName = "用户协议", moduleCode = "baseapi" )
|
||||
@RestController
|
||||
@RequestMapping("/user/protocol")
|
||||
@RequiredArgsConstructor
|
||||
public class UserProtocolController {
|
||||
private final UserProtocolService userProtocolService;
|
||||
|
||||
@RequestPath("分页")
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public Result<PageResult<UserProtocolResult>> page(PageParam pageParam, UserProtocolQuery query){
|
||||
return Res.ok(userProtocolService.page(pageParam, query));
|
||||
}
|
||||
|
||||
@RequestPath("新增")
|
||||
@Operation(summary = "新增")
|
||||
@PostMapping("/add")
|
||||
public Result<Void> add(@RequestBody @Validated(ValidationGroup.add.class) UserProtocolParam param){
|
||||
userProtocolService.add(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@RequestPath("修改")
|
||||
@Operation(summary = "修改")
|
||||
@PostMapping("/update")
|
||||
public Result<Void> update(@RequestBody @Validated(ValidationGroup.edit.class) UserProtocolParam param){
|
||||
userProtocolService.update(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@RequestPath("删除")
|
||||
@Operation(summary = "删除")
|
||||
@PostMapping("/delete")
|
||||
public Result<Void> delete(@NotNull(message = "主键不可为空") Long id){
|
||||
userProtocolService.delete(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@RequestPath("查询")
|
||||
@Operation(summary = "查询")
|
||||
@GetMapping("/findById")
|
||||
public Result<UserProtocolResult> findById(@NotNull(message = "主键不可为空") Long id){
|
||||
return Res.ok(userProtocolService.findById(id));
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "查询默认协议")
|
||||
@GetMapping("/findDefault")
|
||||
public Result<UserProtocolResult> findDefault(@NotNull(message = "协议类型不可为空") String type){
|
||||
return Res.ok(userProtocolService.findDefault(type));
|
||||
}
|
||||
|
||||
@RequestPath("设置默认")
|
||||
@Operation(summary = "设置默认")
|
||||
@PostMapping("/setDefault")
|
||||
public Result<Void> setDefault(@NotNull(message = "主键不可为空") Long id){
|
||||
userProtocolService.setDefault(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@RequestPath("取消默认")
|
||||
@Operation(summary = "取消默认")
|
||||
@PostMapping("/cancelDefault")
|
||||
public Result<Void> cancelDefault(@NotNull(message = "主键不可为空") Long id){
|
||||
userProtocolService.cancelDefault(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.bootx.platform.baseapi.convert.protocol;
|
||||
|
||||
import cn.bootx.platform.baseapi.entity.protocol.UserProtocol;
|
||||
import cn.bootx.platform.baseapi.param.protocol.UserProtocolParam;
|
||||
import cn.bootx.platform.baseapi.result.protocol.UserProtocolResult;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
*用户协议管理
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@Mapper
|
||||
public interface UserProtocolConvert {
|
||||
UserProtocolConvert CONVERT = Mappers.getMapper(UserProtocolConvert.class);
|
||||
|
||||
UserProtocolResult toResult(UserProtocol userProtocol);
|
||||
|
||||
UserProtocol toEntity(UserProtocolParam param);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package cn.bootx.platform.baseapi.dao.dict;
|
||||
|
||||
import cn.bootx.platform.baseapi.entity.dict.DictionaryItem;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpRealDelEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
@@ -63,7 +64,11 @@ public class DictionaryItemManager extends BaseManager<DictionaryItemMapper, Dic
|
||||
}
|
||||
|
||||
public void updateDictCode(Long dictId, String dictCode) {
|
||||
lambdaUpdate().set(DictionaryItem::getDictCode, dictCode).eq(DictionaryItem::getDictId, dictId).update();
|
||||
lambdaUpdate()
|
||||
.set(DictionaryItem::getDictCode, dictCode)
|
||||
.eq(DictionaryItem::getDictId, dictId)
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
|
||||
public List<DictionaryItem> findAllByEnable(boolean enable) {
|
||||
|
||||
@@ -30,21 +30,21 @@ public class SystemParamManager extends BaseManager<SystemParamMapper, SystemPar
|
||||
* 根据键名获取键值
|
||||
*/
|
||||
public Optional<SystemParameter> findByKey(String key) {
|
||||
return this.findByField(SystemParameter::getKey, key);
|
||||
return this.findByField(SystemParameter::getParamKey, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* key重复检查
|
||||
*/
|
||||
public boolean existsByKey(String key) {
|
||||
return existedByField(SystemParameter::getKey, key);
|
||||
return existedByField(SystemParameter::getParamKey, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* key重复检查
|
||||
*/
|
||||
public boolean existsByKey(String key, Long id) {
|
||||
return existedByField(SystemParameter::getKey, key, id);
|
||||
return existedByField(SystemParameter::getParamKey, key, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ public class SystemParamManager extends BaseManager<SystemParamMapper, SystemPar
|
||||
Page<SystemParameter> mpPage = MpUtil.getMpPage(pageParam);
|
||||
return lambdaQuery().orderByDesc(MpIdEntity::getId)
|
||||
.like(StrUtil.isNotBlank(param.getName()), SystemParameter::getName, param.getName())
|
||||
.like(StrUtil.isNotBlank(param.getKey()), SystemParameter::getKey, param.getKey())
|
||||
.like(StrUtil.isNotBlank(param.getKey()), SystemParameter::getParamKey, param.getKey())
|
||||
.page(mpPage);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package cn.bootx.platform.baseapi.dao.protocol;
|
||||
|
||||
import cn.bootx.platform.baseapi.entity.protocol.UserProtocol;
|
||||
import cn.bootx.platform.baseapi.param.protocol.UserProtocolQuery;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpRealDelEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.query.generator.QueryGenerator;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 用户协议管理
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class UserProtocolManager extends BaseManager<UserProtocolMapper, UserProtocol> {
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public Page<UserProtocol> page(PageParam pageParam, UserProtocolQuery query){
|
||||
Page<UserProtocol> mpPage = MpUtil.getMpPage(pageParam, UserProtocol.class);
|
||||
QueryWrapper<UserProtocol> generator = QueryGenerator.generator(query);
|
||||
return this.page(mpPage,generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分类查询默认协议
|
||||
*/
|
||||
public Optional<UserProtocol> findDefault(String type){
|
||||
return this.lambdaQuery()
|
||||
.eq(UserProtocol::getType,type)
|
||||
.eq(UserProtocol::getDefaultProtocol,true)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除默认协议
|
||||
*/
|
||||
public void clearDefault(String type){
|
||||
this.lambdaUpdate()
|
||||
.eq(UserProtocol::getType,type)
|
||||
.set(UserProtocol::getDefaultProtocol,false)
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认协议
|
||||
*/
|
||||
public void setDefault(Long id){
|
||||
this.lambdaUpdate()
|
||||
.eq(UserProtocol::getId,id)
|
||||
.set(UserProtocol::getDefaultProtocol,true)
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消默认协议
|
||||
*/
|
||||
public void cancelDefault(Long id){
|
||||
this.lambdaUpdate()
|
||||
.eq(UserProtocol::getId,id)
|
||||
.set(UserProtocol::getDefaultProtocol,false)
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.bootx.platform.baseapi.dao.protocol;
|
||||
|
||||
import cn.bootx.platform.baseapi.entity.protocol.UserProtocol;
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@Mapper
|
||||
public interface UserProtocolMapper extends MPJBaseMapper<UserProtocol> {
|
||||
}
|
||||
@@ -28,10 +28,10 @@ public class SystemParameter extends MpBaseEntity implements ToResult<SystemPara
|
||||
private String name;
|
||||
|
||||
/** 参数键名 */
|
||||
private String key;
|
||||
private String paramKey;
|
||||
|
||||
/** 参数值 */
|
||||
private String value;
|
||||
private String paramValue;
|
||||
|
||||
/** 参数类型 */
|
||||
private String type;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package cn.bootx.platform.baseapi.entity.protocol;
|
||||
|
||||
import cn.bootx.platform.baseapi.convert.protocol.UserProtocolConvert;
|
||||
import cn.bootx.platform.baseapi.param.protocol.UserProtocolParam;
|
||||
import cn.bootx.platform.baseapi.result.protocol.UserProtocolResult;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.function.ToResult;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户协议管理
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("base_user_protocol")
|
||||
public class UserProtocol extends MpBaseEntity implements ToResult<UserProtocolResult> {
|
||||
|
||||
/** 名称 */
|
||||
private String name;
|
||||
|
||||
/** 显示名称 */
|
||||
private String showName;
|
||||
|
||||
/** 类型 */
|
||||
private String type;
|
||||
|
||||
/** 默认协议 */
|
||||
private Boolean defaultProtocol;
|
||||
|
||||
/** 内容 */
|
||||
private String content;
|
||||
|
||||
@Override
|
||||
public UserProtocolResult toResult() {
|
||||
return UserProtocolConvert.CONVERT.toResult(this);
|
||||
}
|
||||
|
||||
public static UserProtocol init(UserProtocolParam param) {
|
||||
return UserProtocolConvert.CONVERT.toEntity(param);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package cn.bootx.platform.baseapi.param.protocol;
|
||||
|
||||
import cn.bootx.platform.core.validation.ValidationGroup;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Null;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户协议管理
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "用户协议管理")
|
||||
public class UserProtocolParam {
|
||||
|
||||
@Null(message = "Id需要为空", groups = ValidationGroup.add.class)
|
||||
@NotNull(message = "Id不可为空", groups = ValidationGroup.edit.class)
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
/** 名称 */
|
||||
@NotBlank(message = "名称不能为空")
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
/** 显示名称 */
|
||||
@NotBlank(message = "显示名称不能为空")
|
||||
@Schema(description = "显示名称")
|
||||
private String showName;
|
||||
|
||||
/** 类型 */
|
||||
@NotBlank(message = "类型不能为空")
|
||||
@Schema(description = "类型")
|
||||
private String type;
|
||||
|
||||
/** 内容 */
|
||||
@Schema(description = "内容")
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cn.bootx.platform.baseapi.param.protocol;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.query.entity.SortParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户协议
|
||||
* @author xxm
|
||||
* @since 2025/5/11
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "用户协议")
|
||||
public class UserProtocolQuery extends SortParam {
|
||||
|
||||
|
||||
/** 名称 */
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
/** 显示名称 */
|
||||
@Schema(description = "显示名称")
|
||||
private String showName;
|
||||
|
||||
/** 类型 */
|
||||
@Schema(description = "类型")
|
||||
private String type;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package cn.bootx.platform.baseapi.result.protocol;
|
||||
|
||||
import cn.bootx.platform.core.result.BaseResult;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户协议管理
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "用户协议管理")
|
||||
public class UserProtocolResult extends BaseResult {
|
||||
|
||||
/** 名称 */
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
|
||||
/** 显示名称 */
|
||||
@Schema(description = "显示名称")
|
||||
private String showName;
|
||||
|
||||
/** 类型 */
|
||||
@Schema(description = "类型")
|
||||
private String type;
|
||||
|
||||
/** 默认协议 */
|
||||
@Schema(description = "默认协议")
|
||||
private Boolean defaultProtocol;
|
||||
|
||||
/** 内容 */
|
||||
@Schema(description = "内容")
|
||||
private String content;
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class SystemParamService {
|
||||
*/
|
||||
public void add(SystemParameterParam param) {
|
||||
SystemParameter systemParameter = SystemParameter.init(param);
|
||||
if (systemParamManager.existsByKey(systemParameter.getKey())) {
|
||||
if (systemParamManager.existsByKey(systemParameter.getParamKey())) {
|
||||
throw new BizException("key重复");
|
||||
}
|
||||
// 默认非内置
|
||||
@@ -81,7 +81,7 @@ public class SystemParamService {
|
||||
if (Objects.equals(param.getEnable(), false)) {
|
||||
throw new BizException("该参数已停用");
|
||||
}
|
||||
return param.getValue();
|
||||
return param.getParamValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package cn.bootx.platform.baseapi.service.protocol;
|
||||
|
||||
import cn.bootx.platform.baseapi.dao.protocol.UserProtocolManager;
|
||||
import cn.bootx.platform.baseapi.entity.protocol.UserProtocol;
|
||||
import cn.bootx.platform.baseapi.param.protocol.UserProtocolParam;
|
||||
import cn.bootx.platform.baseapi.param.protocol.UserProtocolQuery;
|
||||
import cn.bootx.platform.baseapi.result.protocol.UserProtocolResult;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.core.exception.BizException;
|
||||
import cn.bootx.platform.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.core.rest.result.PageResult;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* 用户协议管理服务
|
||||
* @author xxm
|
||||
* @since 2025/5/9
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserProtocolService {
|
||||
private final UserProtocolManager userProtocolManager;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public PageResult<UserProtocolResult> page(PageParam pageParam, UserProtocolQuery query){
|
||||
return MpUtil.toPageResult(userProtocolManager.page(pageParam,query));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*/
|
||||
public void add(UserProtocolParam param){
|
||||
var userProtocol = UserProtocol.init(param);
|
||||
userProtocolManager.save(userProtocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
*/
|
||||
public void update(UserProtocolParam param){
|
||||
var userProtocol = userProtocolManager.findById(param.getId())
|
||||
.orElseThrow(() -> new DataNotExistException("用户协议不存在"));
|
||||
BeanUtil.copyProperties(param, userProtocol, CopyOptions.create().ignoreNullValue());
|
||||
userProtocolManager.updateById(userProtocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
public void delete(Long id){
|
||||
// 默认不可被删除
|
||||
var userProtocol = userProtocolManager.findById(id)
|
||||
.orElseThrow(() -> new DataNotExistException("用户协议不存在"));
|
||||
if (userProtocol.getDefaultProtocol()){
|
||||
throw new BizException("默认协议不可删除");
|
||||
}
|
||||
userProtocolManager.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查询
|
||||
*/
|
||||
public UserProtocolResult findById(Long id){
|
||||
return userProtocolManager.findById(id)
|
||||
.map(UserProtocol::toResult)
|
||||
.orElseThrow(() -> new DataNotExistException("用户协议不存在"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分类查询默认协议
|
||||
*/
|
||||
public UserProtocolResult findDefault(String type){
|
||||
return userProtocolManager.findDefault(type)
|
||||
.map(UserProtocol::toResult)
|
||||
.orElseThrow(() -> new DataNotExistException("用户协议不存在"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认协议
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void setDefault(Long id){
|
||||
var userProtocol = userProtocolManager.findById(id)
|
||||
.orElseThrow(() -> new DataNotExistException("用户协议不存在"));
|
||||
userProtocolManager.clearDefault(userProtocol.getType());
|
||||
userProtocolManager.setDefault(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消默认协议
|
||||
*/
|
||||
public void cancelDefault(Long id){
|
||||
var userProtocol = userProtocolManager.findById(id)
|
||||
.orElseThrow(() -> new DataNotExistException("用户协议不存在"));
|
||||
userProtocolManager.cancelDefault(id);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-service</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>service-iam</artifactId>
|
||||
|
||||
@@ -33,8 +33,10 @@ import java.util.Objects;
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
public class PasswordLoginHandler implements AbstractAuthentication {
|
||||
|
||||
@Getter
|
||||
private final String ACCOUNT_PARAMETER = "account";
|
||||
|
||||
@Getter
|
||||
private final String PASSWORD_PARAMETER = "password";
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -70,7 +70,7 @@ public class UserAdminController {
|
||||
@RequestPath("重置密码")
|
||||
@Operation(summary = "重置密码")
|
||||
@PostMapping("/restartPassword")
|
||||
@OperateLog(title = "重置密码", businessType = OperateLog.BusinessType.UPDATE, saveParam = true)
|
||||
@OperateLog(title = "重置密码", businessType = OperateLog.BusinessType.UPDATE)
|
||||
public Result<Void> restartPassword(@RequestBody @Validated RestartPwdParam param) {
|
||||
userAdminService.restartPassword(param.getUserId(), param.getNewPassword());
|
||||
return Res.ok();
|
||||
@@ -79,7 +79,7 @@ public class UserAdminController {
|
||||
@RequestPath("批量重置密码")
|
||||
@Operation(summary = "批量重置密码")
|
||||
@PostMapping("/restartPasswordBatch")
|
||||
@OperateLog(title = "批量重置密码", businessType = OperateLog.BusinessType.UPDATE, saveParam = true)
|
||||
@OperateLog(title = "批量重置密码", businessType = OperateLog.BusinessType.UPDATE)
|
||||
public Result<Void> restartPasswordBatch(@RequestBody @Validated RestartPwdBatchParam param) {
|
||||
userAdminService.restartPasswordBatch(param.getUserIds(), param.getNewPassword());
|
||||
return Res.ok();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.iam.dao.user;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpRealDelEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.query.generator.QueryGenerator;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
@@ -74,7 +75,11 @@ public class UserInfoManager extends BaseManager<UserInfoMapper, UserInfo> {
|
||||
}
|
||||
|
||||
public void setUpStatus(Long userId, String status) {
|
||||
lambdaUpdate().eq(MpIdEntity::getId, userId).set(UserInfo::getStatus, status).update();
|
||||
lambdaUpdate()
|
||||
.eq(MpIdEntity::getId, userId)
|
||||
.set(UserInfo::getStatus, status)
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,6 +91,7 @@ public class UserInfoManager extends BaseManager<UserInfoMapper, UserInfo> {
|
||||
.set(UserInfo::getStatus, status)
|
||||
.set(UserInfo::getLastModifiedTime, LocalDateTime.now())
|
||||
.set(UserInfo::getLastModifier, SecurityUtil.getUserIdOrDefaultId())
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
|
||||
@@ -98,6 +104,7 @@ public class UserInfoManager extends BaseManager<UserInfoMapper, UserInfo> {
|
||||
.set(UserInfo::getPassword, password)
|
||||
.set(UserInfo::getLastModifiedTime, LocalDateTime.now())
|
||||
.set(UserInfo::getLastModifier, SecurityUtil.getUserIdOrDefaultId())
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.iam.entity.permission;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.function.ToResult;
|
||||
import cn.bootx.platform.iam.convert.permission.PermPathConvert;
|
||||
import cn.bootx.platform.iam.result.permission.PermPathResult;
|
||||
@@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("iam_perm_path")
|
||||
public class PermPath extends MpCreateEntity implements ToResult<PermPathResult> {
|
||||
public class PermPath extends MpIdEntity implements ToResult<PermPathResult> {
|
||||
|
||||
/** 上级编码 */
|
||||
private String parentCode;
|
||||
|
||||
@@ -2,10 +2,8 @@ package cn.bootx.platform.iam.handler;
|
||||
|
||||
import cn.bootx.platform.core.entity.UserDetail;
|
||||
import cn.bootx.platform.iam.code.UserStatusEnum;
|
||||
import cn.bootx.platform.iam.service.user.UserAdminService;
|
||||
import cn.bootx.platform.starter.auth.authentication.UserInfoStatusCheck;
|
||||
import cn.bootx.platform.starter.auth.configuration.AuthProperties;
|
||||
import cn.bootx.platform.starter.auth.entity.AuthClient;
|
||||
import cn.bootx.platform.starter.auth.entity.AuthInfoResult;
|
||||
import cn.bootx.platform.starter.auth.entity.LoginAuthContext;
|
||||
import cn.bootx.platform.starter.auth.exception.LoginFailureException;
|
||||
@@ -24,7 +22,6 @@ import java.util.Objects;
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UserInfoStatusCheckImpl implements UserInfoStatusCheck {
|
||||
private final UserAdminService userAdminService;
|
||||
|
||||
/**
|
||||
* 检查用户状态
|
||||
@@ -34,7 +31,6 @@ public class UserInfoStatusCheckImpl implements UserInfoStatusCheck {
|
||||
@Override
|
||||
public void check(AuthInfoResult authInfoResult, LoginAuthContext context) {
|
||||
UserDetail userDetail = authInfoResult.getUserDetail();
|
||||
AuthClient authClient = context.getAuthClient();
|
||||
AuthProperties authProperties = context.getAuthProperties();
|
||||
// 判断是否开启了超级管理员
|
||||
if (!authProperties.isEnableAdmin() && userDetail.isAdmin()) {
|
||||
|
||||
@@ -64,12 +64,12 @@ public class PermPathSyncService {
|
||||
List<String> clientCodes = bootxConfigProperties.getClientCodes();
|
||||
// 查询数据中的数据并转换为请求信息列表
|
||||
for (String clientCode : clientCodes) {
|
||||
sync(clientCode);
|
||||
this.sync(clientCode);
|
||||
}
|
||||
} else {
|
||||
// 分模块模式同步
|
||||
String clientCode = clientCodeService.getClientCode();
|
||||
sync(clientCode);
|
||||
this.sync(clientCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public class PermPathSyncService {
|
||||
// 查询是否包含所有
|
||||
.filter(o -> o.isAllClient() || CollUtil.contains(o.getClientCodes(),clientCode))
|
||||
.toList();
|
||||
List<PermPath> permPaths = permPathManager.findAllByLeafAndClient(true,clientCode);
|
||||
List<PermPath> permPaths = permPathManager.findAllByLeafAndClient(true, clientCode);
|
||||
var requestPathMap = requestPathBos.stream()
|
||||
.collect(Collectors.toMap(o -> o.getPath() + ":" + o.getMethod(), Function.identity()));
|
||||
var permPathMap = permPaths.stream()
|
||||
@@ -95,8 +95,8 @@ public class PermPathSyncService {
|
||||
// 需要更新的数据
|
||||
List<PermPath> updateData = this.getUpdateData(requestPathMap, permPathMap);
|
||||
|
||||
// 保存新增的
|
||||
addData.forEach(o -> o.setClientCode(clientCode));
|
||||
// 保存新增的, ID 由不会变更的终端编码+请求方式+请求路径进行
|
||||
addData.forEach(o -> o.setClientCode(clientCode).setId(this.genPathId(o.getClientCode()+o.getMethod()+o.getPath())));
|
||||
permPathManager.saveAll(addData);
|
||||
// 更新存在的
|
||||
permPathManager.updateAllById(updateData);
|
||||
@@ -161,8 +161,7 @@ public class PermPathSyncService {
|
||||
.map(permPathMap::get)
|
||||
.peek(o -> {
|
||||
RequestPathBo requestPathBo = requestPathMap.get(o.getPath() + ":" + o.getMethod());
|
||||
o.setName(requestPathBo.getName())
|
||||
.setParentCode(requestPathBo.getGroupCode());
|
||||
o.setName(requestPathBo.getName()).setParentCode(requestPathBo.getGroupCode());
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@@ -227,7 +226,7 @@ public class PermPathSyncService {
|
||||
.stream()
|
||||
.filter(pathKey -> {
|
||||
HandlerMethod handlerMethod = map.get(pathKey);
|
||||
return Objects.nonNull(handlerMethod.getMethodAnnotation(cn.bootx.platform.core.annotation.RequestPath.class))
|
||||
return Objects.nonNull(handlerMethod.getMethodAnnotation(RequestPath.class))
|
||||
&&Objects.nonNull(handlerMethod.getBeanType().getAnnotation(RequestGroup.class));
|
||||
}).toList();
|
||||
|
||||
@@ -303,7 +302,7 @@ public class PermPathSyncService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 给分组和模块生成ID, 防止每次更新ID都会发生变化
|
||||
* 给分组/模块/请求路径资源生成ID, 防止每次更新ID都会发生变化
|
||||
*/
|
||||
private long genPathId(String str) {
|
||||
String s = SecureUtil.sha256(str);
|
||||
|
||||
@@ -148,7 +148,7 @@ public class RoleQueryService {
|
||||
// 获取关联的角色和子角色
|
||||
List<RoleResult> unfold = TreeBuildUtil.unfold(tree, RoleResult::getChildren).stream()
|
||||
.filter(role -> roleIds.contains(role.getId()))
|
||||
.collect(Collectors.toList());;
|
||||
.collect(Collectors.toList());
|
||||
var list = new ArrayList<>(unfold);
|
||||
// 将子孙级别的角色移除, 只保留根角色
|
||||
for (var out : unfold) {
|
||||
|
||||
@@ -152,7 +152,7 @@ public class RoleCodeService {
|
||||
// 权限码列表
|
||||
List<PermCode> permCodes = allPermCodes.stream()
|
||||
.filter(PermCode::isLeaf)
|
||||
.toList();;
|
||||
.toList();
|
||||
// 如果有有上级角色, 显示上级角色已分配的权限
|
||||
if (Objects.nonNull(role.getPid())){
|
||||
List<Long> codeIds = roleCodeManager.findAllByRole(role.getPid())
|
||||
|
||||
@@ -47,7 +47,6 @@ public class UserAdminService {
|
||||
|
||||
private final AuthProperties authProperties;
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*/
|
||||
@@ -143,8 +142,7 @@ public class UserAdminService {
|
||||
|
||||
UserInfo userInfo = userInfoManager.findById(userId).orElseThrow(UserInfoNotExistsException::new);
|
||||
// 新密码进行加密
|
||||
newPassword = BCrypt.hashpw(newPassword);
|
||||
userInfo.setPassword(newPassword);
|
||||
userInfo.setPassword(BCrypt.hashpw(newPassword));
|
||||
userInfoManager.updateById(userInfo);
|
||||
}
|
||||
|
||||
@@ -154,8 +152,7 @@ public class UserAdminService {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void restartPasswordBatch(List<Long> userIds, String newPassword){
|
||||
// 新密码进行加密
|
||||
String password = BCrypt.hashpw(newPassword);
|
||||
userInfoManager.restartPasswordBatch(userIds,password);
|
||||
userInfoManager.restartPasswordBatch(userIds,BCrypt.hashpw(newPassword));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,13 +98,16 @@ public class UserInfoService {
|
||||
public void updatePassword(String password, String newPassword) {
|
||||
UserInfo userInfo = userInfoManager.findById(SecurityUtil.getUserId())
|
||||
.orElseThrow(UserInfoNotExistsException::new);
|
||||
|
||||
UserInfo update=new UserInfo();
|
||||
update.setId(userInfo.getId());
|
||||
update.setVersion(userInfo.getVersion());
|
||||
// 判断原密码是否正确
|
||||
if (!BCrypt.checkpw(password, userInfo.getPassword())) {
|
||||
throw new BizException("旧密码错误");
|
||||
}
|
||||
userInfo.setPassword(newPassword);
|
||||
userInfoManager.updateById(userInfo);
|
||||
newPassword=BCrypt.hashpw(newPassword,BCrypt.gensalt());
|
||||
update.setPassword(newPassword);
|
||||
userInfoManager.updateById(update);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>starter-auth</module>
|
||||
@@ -27,7 +27,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-core</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<!-- lombok -->
|
||||
<dependency>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-starter</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>starter-audit-log</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-starter</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>starter-auth</artifactId>
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.bootx.platform.starter.auth.entity.LoginAuthContext;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -19,11 +20,12 @@ public interface AbstractAuthentication {
|
||||
* 获取终端编码
|
||||
*/
|
||||
String getLoginType();
|
||||
|
||||
/**
|
||||
* 获取用户状态检查接口的实现类
|
||||
*/
|
||||
default UserInfoStatusCheck getUserInfoStatusCheck() {
|
||||
return SpringUtil.getBean(UserInfoStatusCheck.class);
|
||||
default List<UserInfoStatusCheck> getUserInfoStatusCheck() {
|
||||
return SpringUtil.getBeansOfType(UserInfoStatusCheck.class).values().stream().toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +64,9 @@ public interface AbstractAuthentication {
|
||||
// 添加用户信息到上下文中
|
||||
context.setUserDetail(authInfoResult.getUserDetail());
|
||||
// 检查用户信息和状态
|
||||
this.getUserInfoStatusCheck().check(authInfoResult, context);
|
||||
for (var userInfoStatusCheck : this.getUserInfoStatusCheck()) {
|
||||
userInfoStatusCheck.check(authInfoResult, context);
|
||||
}
|
||||
// 认证后处理
|
||||
this.authenticationAfter(authInfoResult, context);
|
||||
return authInfoResult;
|
||||
|
||||
@@ -11,7 +11,7 @@ import cn.bootx.platform.starter.auth.entity.LoginAuthContext;
|
||||
public interface UserInfoStatusCheck {
|
||||
|
||||
/**
|
||||
*
|
||||
* 检查用户状态
|
||||
* @param authInfoResult 认证返回结果
|
||||
* @param context 登录认证上下文
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-starter</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>starter-cache</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-starter</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>starter-delay-queue</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-starter</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>starter-file</artifactId>
|
||||
@@ -25,11 +25,10 @@
|
||||
<version>${x-file-storage.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>${qcloud.version}</version>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
<version>${aws-s3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库 -->
|
||||
<dependency>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package cn.bootx.platform.starter.file.code;
|
||||
|
||||
import cn.bootx.platform.core.exception.BizException;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 存储平台类型
|
||||
*
|
||||
@@ -12,22 +16,32 @@ import lombok.RequiredArgsConstructor;
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum FilePlatformTypeEnum {
|
||||
LOCAL("local"),
|
||||
FTP("ftp"),
|
||||
SFTP("sftp"),
|
||||
WEB_DAV("web_dav"),
|
||||
AMAZON("amazon"),
|
||||
MINIO("minio"),
|
||||
ALI("ali"),
|
||||
HUAWEI("huawei"),
|
||||
TENCENT("tencent"),
|
||||
BAIDU("baidu"),
|
||||
UPYUN("upyun"),
|
||||
QINIU("qiniu"),
|
||||
GOOGLE_CLOUD("google_cloud"),
|
||||
FAST_DFS("fast_dfs"),
|
||||
AZURE("azure");
|
||||
LOCAL("local",false),
|
||||
FTP("ftp",false),
|
||||
SFTP("sftp",false),
|
||||
WEB_DAV("web_dav",false),
|
||||
// S3 存储, 现在系统只支持这一种方式
|
||||
AMAZON_S3("amazon-s3",true),
|
||||
MINIO("minio",true),
|
||||
ALI("ali",true),
|
||||
HUAWEI("huawei",true),
|
||||
TENCENT("tencent",true),
|
||||
BAIDU("baidu",true),
|
||||
UPYUN("upyun",true),
|
||||
QINIU("qiniu",true),
|
||||
GOOGLE_CLOUD("google_cloud",true),
|
||||
FAST_DFS("fast_dfs",true),
|
||||
AZURE("azure",true);
|
||||
|
||||
private final String code;
|
||||
/** 前端直传 */
|
||||
private final boolean frontendUpload;
|
||||
|
||||
public static FilePlatformTypeEnum findByCode(String code){
|
||||
return Arrays.stream(values())
|
||||
.filter(e -> Objects.equals(e.code, code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new BizException("不支持的类型"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package cn.bootx.platform.starter.file.configuration;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 文件上传配置
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/1/14
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ConfigurationProperties(prefix = "bootx-platform.starter.file-upload")
|
||||
public class FileUploadProperties {
|
||||
|
||||
/**
|
||||
* 文件访问转发地址(当前后端服务地址或被代理后的地址), 流量会经过后端服务的转发
|
||||
*/
|
||||
private String forwardServerUrl = "http://127.0.0.1:9999";
|
||||
|
||||
/**
|
||||
* 处理为 / 结尾
|
||||
*/
|
||||
public String getForwardServerUrl() {
|
||||
return StrUtil.removeSuffix(forwardServerUrl, "/");
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package cn.bootx.platform.starter.file.configuration;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ConfigurationProperties(prefix = "bootx-platform.starter.oss")
|
||||
/***
|
||||
* oss配置
|
||||
*/
|
||||
public class OssProperties {
|
||||
|
||||
private String filePath;
|
||||
|
||||
|
||||
}
|
||||
@@ -8,20 +8,30 @@ import cn.bootx.platform.core.rest.Res;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.core.rest.result.PageResult;
|
||||
import cn.bootx.platform.core.rest.result.Result;
|
||||
import cn.bootx.platform.starter.file.param.FileUploadRequestParams;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileInfoParam;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileQuery;
|
||||
import cn.bootx.platform.starter.file.result.FileUploadParamsResult;
|
||||
import cn.bootx.platform.starter.file.result.UploadFileResult;
|
||||
import cn.bootx.platform.starter.file.service.FileUploadService;
|
||||
import org.dromara.core.trans.anno.TransMethodResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.core.trans.anno.TransMethodResult;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
@@ -52,14 +62,14 @@ public class FIleUpLoadController {
|
||||
@Operation(summary = "获取单条详情")
|
||||
@GetMapping("/findById")
|
||||
public Result<UploadFileResult> findById(@NotNull(message = "主键不可为空") Long id) {
|
||||
return Res.ok(uploadService.findById(id));
|
||||
return Res.ok(uploadService.findByUrl(id));
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "根据URL获取单条详情")
|
||||
@GetMapping("/findByUrl")
|
||||
public Result<UploadFileResult> findById(@NotBlank(message = "文件URL不可为空") String url) {
|
||||
return Res.ok(uploadService.findById(url));
|
||||
return Res.ok(uploadService.findByUrl(url));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除")
|
||||
@@ -71,31 +81,37 @@ public class FIleUpLoadController {
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "上传")
|
||||
@PostMapping("/upload")
|
||||
public Result<UploadFileResult> local(@RequestPart MultipartFile file, String fileName) {
|
||||
return Res.ok(uploadService.upload(file, fileName));
|
||||
@IgnoreAuth(login = true)
|
||||
@Operation(summary = "下载文件")
|
||||
@GetMapping("/downloadByServer")
|
||||
public ResponseEntity<byte[]> downloadByServer(String attachName) {
|
||||
var bytes = uploadService.downloadAndCheck(attachName);
|
||||
// 设置header信息
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
headers.setContentDispositionFormData("attachment", URLEncoder.encode(attachName, StandardCharsets.UTF_8));
|
||||
return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@IgnoreAuth(login = true)
|
||||
@Operation(summary = "获取前端直传参数")
|
||||
@PostMapping("/getUploadParams")
|
||||
public Result<FileUploadParamsResult> getUploadParams(@RequestBody @Valid FileUploadRequestParams params) {
|
||||
return Res.ok(uploadService.getUploadParams(params));
|
||||
}
|
||||
|
||||
@IgnoreAuth(login = true)
|
||||
@Operation(summary = "前端直传文件信息保存")
|
||||
@PostMapping("/saveFileInfo")
|
||||
public Result<Void> saveFileInfo(@RequestBody @Valid UploadFileInfoParam param) {
|
||||
uploadService.saveFileInfo(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "获取文件预览地址前缀(流量会经过后端)")
|
||||
@GetMapping("/forward/getFilePreviewUrlPrefix")
|
||||
public Result<String> getFilePreviewUrlPrefix() {
|
||||
return Res.ok(uploadService.getServerFilePreviewUrlPrefix());
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "预览文件(流量会经过后端)")
|
||||
@GetMapping("/forward/preview/{id}")
|
||||
public void preview(@PathVariable Long id, HttpServletResponse response) {
|
||||
uploadService.preview(id, response);
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "下载文件(流量会经过后端)")
|
||||
@GetMapping("/forward/download/{id}")
|
||||
public ResponseEntity<byte[]> download(@PathVariable Long id) {
|
||||
return uploadService.download(id);
|
||||
@Operation(summary = "前端直传文件预览/下载(不需要登录)")
|
||||
@GetMapping("/download/{attachName}")
|
||||
public void download(HttpServletResponse httpServletResponse, @Schema(description = "附件名") @PathVariable("attachName") String attachName) {
|
||||
uploadService.ossDownload(httpServletResponse, attachName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.x.file.storage.core.FileStorageService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -24,6 +25,7 @@ import java.util.List;
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Validated
|
||||
@Deprecated
|
||||
@RequestGroup(groupCode = "FilePlatform", groupName = "文件存储平台管理", moduleCode = "starter")
|
||||
@Tag(name = "文件存储平台")
|
||||
@RestController
|
||||
@@ -31,6 +33,7 @@ import java.util.List;
|
||||
@RequiredArgsConstructor
|
||||
public class FilePlatformController {
|
||||
private final FilePlatformService filePlatformService;
|
||||
private final FileStorageService fileStorageService;
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "列表")
|
||||
@@ -63,4 +66,12 @@ public class FilePlatformController {
|
||||
filePlatformService.setDefault(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@IgnoreAuth
|
||||
@Operation(summary = "获取当前默认的文件上传存储平台")
|
||||
@GetMapping("/getDefaultUpload")
|
||||
public Result<String> getDefault(){
|
||||
String defaultPlatform = fileStorageService.getProperties().getDefaultPlatform();
|
||||
return Res.ok(defaultPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package cn.bootx.platform.starter.file.controller;
|
||||
|
||||
import cn.bootx.platform.starter.file.param.FileUploadRequestParams;
|
||||
import cn.bootx.platform.starter.file.result.FileUploadParamsResult;
|
||||
import cn.bootx.platform.starter.file.service.OssService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@Tag(name = "对象存储")
|
||||
@RequestMapping("/oss")
|
||||
@AllArgsConstructor
|
||||
public class OssController {
|
||||
|
||||
|
||||
private final OssService ossService;
|
||||
|
||||
@Operation(summary = "获取上传参数")
|
||||
@PostMapping("/getUploadParams")
|
||||
public FileUploadParamsResult getUploadParams(@RequestBody @Valid FileUploadRequestParams params) {
|
||||
return ossService.getUploadParams(params);
|
||||
}
|
||||
|
||||
@Operation(summary = "文件预览/文件下载")
|
||||
@GetMapping("/download/{attachName}")
|
||||
public void download(HttpServletResponse httpServletResponse, @Schema(description = "附件名") @PathVariable("attachName") String attachName) {
|
||||
ossService.download(httpServletResponse, attachName);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.starter.file.convert;
|
||||
|
||||
import cn.bootx.platform.starter.file.entity.UploadFileInfo;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileInfoParam;
|
||||
import cn.bootx.platform.starter.file.result.UploadFileResult;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.mapstruct.Mapper;
|
||||
@@ -19,6 +20,8 @@ public interface FileConvert {
|
||||
|
||||
UploadFileInfo convert(FileInfo in);
|
||||
|
||||
UploadFileInfo convert(UploadFileInfoParam in);
|
||||
|
||||
FileInfo toFileInfo(UploadFileInfo in);
|
||||
|
||||
UploadFileResult toResult(FileInfo in);
|
||||
|
||||
@@ -6,13 +6,23 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
*
|
||||
* 支付平台配置
|
||||
* @author xxm
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class FilePlatformManager extends BaseManager<FilePlatformMapper, FilePlatform> {
|
||||
|
||||
/**
|
||||
* 根据平台类型查询
|
||||
*/
|
||||
public Optional<FilePlatform> findByType(String platform) {
|
||||
return findByField(FilePlatform::getType, platform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 文件存储平台
|
||||
* @author xxm
|
||||
@@ -41,12 +43,20 @@ public class FilePlatform extends MpRealDelEntity implements ToResult<FilePlatfo
|
||||
private boolean defaultPlatform;
|
||||
|
||||
/** 访问地址 */
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String url;
|
||||
|
||||
/** 前端直传 */
|
||||
private Boolean frontendUpload;
|
||||
|
||||
public String getUrl() {
|
||||
return StrUtil.removeSuffix(url, "/");
|
||||
}
|
||||
|
||||
public Boolean getFrontendUpload() {
|
||||
return Objects.equals(frontendUpload,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.time.LocalDateTime;
|
||||
public class UploadFileInfo extends MpIdEntity implements ToResult<UploadFileResult> {
|
||||
|
||||
/**
|
||||
* 文件访问地址
|
||||
* 文件访问地址(存储在S3中的唯一名称)
|
||||
*/
|
||||
private String url;
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.recorder.DefaultFileRecorder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* x.file.storage 文件上传信息储存
|
||||
* @author xxm
|
||||
@@ -27,7 +25,6 @@ public class FileDetailRecordHandler extends DefaultFileRecorder {
|
||||
@Override
|
||||
public boolean save(FileInfo fileInfo) {
|
||||
UploadFileInfo uploadFileInfo = UploadFileInfo.init(fileInfo);
|
||||
uploadFileInfo.setCreateTime(LocalDateTime.now());
|
||||
uploadFileManager.save(uploadFileInfo);
|
||||
fileInfo.setId(String.valueOf(uploadFileInfo.getId()));
|
||||
return true;
|
||||
|
||||
@@ -20,8 +20,11 @@ public class FilePlatformParam {
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@NotBlank(message = "平台地址不得为空")
|
||||
@Schema(description = "平台地址")
|
||||
private String url;
|
||||
|
||||
/** 前端直传 */
|
||||
@Schema(description = "前端直传")
|
||||
private Boolean frontendUpload;
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public class FileUploadRequestParams {
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "媒体类型 MEDIA_TYPE")
|
||||
@NotBlank(message = "媒体类型不可为")
|
||||
@NotBlank(message = "媒体类型不可为为空")
|
||||
private String mediaType;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package cn.bootx.platform.starter.file.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 上传文件信息
|
||||
* @author xxm
|
||||
* @since 2025/5/15
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "上传文件信息")
|
||||
public class UploadFileInfoParam {
|
||||
|
||||
/**
|
||||
* 文件访问地址(名称)
|
||||
*/
|
||||
@Schema(description = "文件访问地址")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 文件大小,单位字节
|
||||
*/
|
||||
@Schema(description = "文件大小,单位字节")
|
||||
private Long size;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
@Schema(description = "文件名称")
|
||||
private String filename;
|
||||
|
||||
/**
|
||||
* 原始文件名
|
||||
*/
|
||||
@Schema(description = "原始文件名")
|
||||
private String originalFilename;
|
||||
|
||||
/**
|
||||
* 基础存储路径
|
||||
*/
|
||||
@Schema(description = "基础存储路径")
|
||||
private String basePath;
|
||||
|
||||
/**
|
||||
* 存储路径
|
||||
*/
|
||||
@Schema(description = "存储路径")
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 文件扩展名
|
||||
*/
|
||||
@Schema(description = "文件扩展名")
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* MIME 类型
|
||||
*/
|
||||
@Schema(description = "MIME 类型")
|
||||
private String contentType;
|
||||
|
||||
/**
|
||||
* 存储平台
|
||||
*/
|
||||
@Schema(description = "存储平台")
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 缩略图访问路径
|
||||
*/
|
||||
@Schema(description = "缩略图访问路径")
|
||||
private String thUrl;
|
||||
|
||||
/**
|
||||
* 缩略图名称
|
||||
*/
|
||||
@Schema(description = "缩略图名称")
|
||||
private String thFilename;
|
||||
|
||||
/**
|
||||
* 缩略图大小,单位字节
|
||||
*/
|
||||
@Schema(description = "缩略图大小,单位字节")
|
||||
private Long thSize;
|
||||
|
||||
/**
|
||||
* 缩略图 MIME 类型
|
||||
*/
|
||||
@Schema(description = "缩略图 MIME 类型")
|
||||
private String thContentType;
|
||||
|
||||
/**
|
||||
* 文件所属对象id
|
||||
*/
|
||||
@Schema(description = "文件所属对象id")
|
||||
private String objectId;
|
||||
|
||||
/**
|
||||
* 文件所属对象类型,例如用户头像,评价图片
|
||||
*/
|
||||
@Schema(description = "文件所属对象类型,例如用户头像,评价图片")
|
||||
private String objectType;
|
||||
}
|
||||
@@ -36,4 +36,9 @@ public class FilePlatformResult extends BaseResult {
|
||||
/** 访问地址 */
|
||||
@Schema(description = "访问地址")
|
||||
private String url;
|
||||
|
||||
/** 前端直传 */
|
||||
@Schema(description = "前端直传")
|
||||
private Boolean frontendUpload;
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,24 @@ package cn.bootx.platform.starter.file.result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件上传参数
|
||||
*/
|
||||
@Schema(description = "文件上传参数")
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class FileUploadParamsResult {
|
||||
|
||||
@Schema(description = "文件上传地址")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "上传后文件名称")
|
||||
private String attachName;
|
||||
|
||||
@Schema(description = "文件上传请求头,上传时放在请求头里")
|
||||
private Map<String,String> headers;
|
||||
|
||||
|
||||
@@ -22,12 +22,12 @@ import java.util.List;
|
||||
* @since 2024/8/12
|
||||
*/
|
||||
@Slf4j
|
||||
@Deprecated
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FilePlatformService {
|
||||
private final FilePlatformManager filePlatformManager;
|
||||
|
||||
|
||||
/**
|
||||
* 获取全部存储平台
|
||||
*/
|
||||
@@ -62,12 +62,14 @@ public class FilePlatformService {
|
||||
.eq(FilePlatform::isDefaultPlatform, true)
|
||||
.set(FilePlatform::getLastModifiedTime, LocalDateTime.now())
|
||||
.set(MpRealDelEntity::getLastModifier, SecurityUtil.getUserIdOrDefaultId())
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
filePlatformManager.lambdaUpdate()
|
||||
.eq(FilePlatform::getId, id)
|
||||
.set(FilePlatform::getLastModifiedTime, LocalDateTime.now())
|
||||
.set(MpRealDelEntity::getLastModifier, SecurityUtil.getUserIdOrDefaultId())
|
||||
.set(FilePlatform::isDefaultPlatform, true)
|
||||
.setIncrBy(MpRealDelEntity::getVersion, 1)
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,37 @@
|
||||
package cn.bootx.platform.starter.file.service;
|
||||
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.core.exception.BizException;
|
||||
import cn.bootx.platform.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.core.rest.result.PageResult;
|
||||
import cn.bootx.platform.starter.file.configuration.FileUploadProperties;
|
||||
import cn.bootx.platform.starter.file.convert.FileConvert;
|
||||
import cn.bootx.platform.starter.file.dao.UploadFileManager;
|
||||
import cn.bootx.platform.starter.file.entity.UploadFileInfo;
|
||||
import cn.bootx.platform.starter.file.param.FileUploadRequestParams;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileInfoParam;
|
||||
import cn.bootx.platform.starter.file.param.UploadFileQuery;
|
||||
import cn.bootx.platform.starter.file.result.FileUploadParamsResult;
|
||||
import cn.bootx.platform.starter.file.result.UploadFileResult;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.FileStorageService;
|
||||
import org.dromara.x.file.storage.core.upload.UploadPretreatment;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.dromara.x.file.storage.core.constant.Constant;
|
||||
import org.dromara.x.file.storage.core.presigned.GeneratePresignedUrlResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 文件上传管理类
|
||||
@@ -47,108 +45,134 @@ import java.time.LocalDateTime;
|
||||
public class FileUploadService {
|
||||
private final UploadFileManager uploadFileManager;
|
||||
private final FileStorageService fileStorageService;
|
||||
private final FileUploadProperties fileUploadProperties;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public PageResult<UploadFileResult> page(PageParam pageParam, UploadFileQuery param) {
|
||||
return MpUtil.toPageResult(uploadFileManager.page(pageParam,param));
|
||||
return MpUtil.toPageResult(uploadFileManager.page(pageParam, param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条详情
|
||||
*/
|
||||
public UploadFileResult findById(Long id){
|
||||
public UploadFileResult findByUrl(Long id) {
|
||||
return uploadFileManager.findById(id)
|
||||
.map(UploadFileInfo::toResult)
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据URL获取单条详情
|
||||
*/
|
||||
public UploadFileResult findById(String url){
|
||||
public UploadFileResult findByUrl(String url) {
|
||||
return uploadFileManager.findByUrl(url)
|
||||
.map(UploadFileInfo::toResult)
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件删除
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Long id){
|
||||
public void delete(Long id) {
|
||||
UploadFileInfo uploadFileInfo = uploadFileManager.findById(id)
|
||||
.orElseThrow(DataNotExistException::new);
|
||||
fileStorageService.delete(FileConvert.CONVERT.toFileInfo(uploadFileInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* @param file 文件
|
||||
* @param fileName 文件名称
|
||||
* 根据文件名称下载
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public UploadFileResult upload(@RequestPart MultipartFile file, String fileName) {
|
||||
UploadPretreatment uploadPretreatment = fileStorageService.of(file);
|
||||
if (StrUtil.isNotBlank(fileName)){
|
||||
uploadPretreatment.setOriginalFilename(fileName);
|
||||
public byte[] download(String attachName) {
|
||||
String ossFileUrl = this.getOssFileUrl(attachName);
|
||||
return HttpUtil.downloadBytes(ossFileUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据存储的文件对象下载
|
||||
*/
|
||||
public byte[] download(FileInfo fileInfo) {
|
||||
return HttpUtil.downloadBytes(this.getOssFileUrl(fileInfo.getUrl()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载, 首先判断文件是否存在, 用在严格的场景中
|
||||
*/
|
||||
public byte[] downloadAndCheck(String attachName) {
|
||||
FileInfo fileInfo = fileStorageService.getFileInfoByUrl(attachName);
|
||||
if (fileInfo == null){
|
||||
throw new DataNotExistException("文件不存在");
|
||||
}
|
||||
// 按年月日进行分目录
|
||||
uploadPretreatment.setPath(LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy/MM/dd/"));
|
||||
|
||||
FileInfo upload = uploadPretreatment.upload();
|
||||
return FileConvert.CONVERT.toResult(upload);
|
||||
return HttpUtil.downloadBytes(this.getOssFileUrl(attachName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件预览
|
||||
* TODO url需要使用URl
|
||||
* 获取直传上传参数
|
||||
*/
|
||||
@SneakyThrows
|
||||
public void preview(Long id, HttpServletResponse response) {
|
||||
FileInfo info = fileStorageService.getFileInfoByUrl(String.valueOf(id));
|
||||
if (info == null){
|
||||
log.warn("文件不存在");
|
||||
return;
|
||||
public FileUploadParamsResult getUploadParams(FileUploadRequestParams params) {
|
||||
String fileExtension = FileUtil.extName(params.getFileName());
|
||||
String attachName = IdUtil.fastSimpleUUID() + (StringUtils.isNotBlank(fileExtension) ? "." + fileExtension : "");
|
||||
GeneratePresignedUrlResult uploadResult = fileStorageService
|
||||
.generatePresignedUrl()
|
||||
.setFilename(attachName) // 设置保存的文件名
|
||||
.setMethod(Constant.GeneratePresignedUrl.Method.PUT) // 签名方法
|
||||
.setExpiration(DateUtil.offsetMinute(new Date(), 10)) // 过期时间 10 分钟
|
||||
.putHeaders(Constant.Metadata.CONTENT_TYPE, params.getMediaType())
|
||||
.putHeaders(Constant.Metadata.CONTENT_LENGTH, String.valueOf(params.getFileSize()))
|
||||
.generatePresignedUrl();
|
||||
FileUploadParamsResult result = new FileUploadParamsResult();
|
||||
result.setUrl(uploadResult.getUrl())
|
||||
.setAttachName(attachName)
|
||||
.setHeaders(uploadResult.getHeaders());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前端直传的文件信息
|
||||
*/
|
||||
public void saveFileInfo(UploadFileInfoParam param) {
|
||||
UploadFileInfo uploadFileInfo = FileConvert.CONVERT.convert(param);
|
||||
// 扩展名
|
||||
String fileExtension = FileUtil.extName(uploadFileInfo.getOriginalFilename());
|
||||
uploadFileInfo.setExt(fileExtension);
|
||||
// 平台
|
||||
String defaultPlatform = fileStorageService.getProperties()
|
||||
.getDefaultPlatform();
|
||||
uploadFileInfo.setPlatform(defaultPlatform);
|
||||
uploadFileManager.save(uploadFileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取oss直传文件下载链接
|
||||
*/
|
||||
public String getOssFileUrl(String attachName) {
|
||||
// 系统中旧数据存储的地址是/开头, 为了兼容旧数据使用oss生成预签名链接的时候需要去掉
|
||||
// 新数据存储格式就没有/开头
|
||||
attachName = StrUtil.removePrefix(attachName, "/");
|
||||
GeneratePresignedUrlResult downloadResult = fileStorageService
|
||||
.generatePresignedUrl()
|
||||
.setFilename(attachName) // 文件名
|
||||
.setMethod(Constant.GeneratePresignedUrl.Method.GET) // 签名方法
|
||||
.setExpiration(DateUtil.offsetMinute(new Date(), 10)) // 过期时间 10 分钟
|
||||
.putResponseHeaders(
|
||||
Constant.Metadata.CONTENT_DISPOSITION, "attachment;filename=" + attachName)
|
||||
.generatePresignedUrl();
|
||||
return downloadResult.getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端直传文件下载/预览
|
||||
*/
|
||||
public void ossDownload(HttpServletResponse httpServletResponse, String attachName) {
|
||||
try {
|
||||
httpServletResponse.sendRedirect(this.getOssFileUrl(attachName));
|
||||
} catch (IOException e) {
|
||||
log.error("下载文件失败", e);
|
||||
httpServletResponse.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
throw new BizException(e.getMessage());
|
||||
}
|
||||
byte[] bytes = fileStorageService.download(info).bytes();
|
||||
var is = new ByteArrayInputStream(bytes);
|
||||
// 获取响应输出流
|
||||
ServletOutputStream os = response.getOutputStream();
|
||||
IoUtil.copy(is, os);
|
||||
response.addHeader(HttpHeaders.CONTENT_DISPOSITION, info.getContentType());
|
||||
IoUtil.close(is);
|
||||
IoUtil.close(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载
|
||||
*/
|
||||
@SneakyThrows
|
||||
public ResponseEntity<byte[]> download(Long id) {
|
||||
FileInfo fileInfo = fileStorageService.getFileInfoByUrl(String.valueOf(id));
|
||||
byte[] bytes = fileStorageService.download(fileInfo).bytes();
|
||||
// 设置header信息
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
String fileName = fileInfo.getOriginalFilename();
|
||||
headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, StandardCharsets.UTF_8));
|
||||
return new ResponseEntity<>(bytes,headers,HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件访问转发地址(当前后端服务地址或被代理后的地址), 流量会经过后端服务的转发
|
||||
*/
|
||||
public String getServerFilePreviewUrlPrefix() {
|
||||
return this.getForwardServerUrl() + "/file/preview/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件访问转发地址(当前后端服务地址或被代理后的地址), 流量会经过后端服务的转发
|
||||
*/
|
||||
private String getForwardServerUrl() {
|
||||
return fileUploadProperties.getForwardServerUrl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package cn.bootx.platform.starter.file.service;
|
||||
|
||||
import cn.bootx.platform.starter.file.configuration.OssProperties;
|
||||
import cn.bootx.platform.starter.file.param.FileUploadRequestParams;
|
||||
import cn.bootx.platform.starter.file.result.FileUploadParamsResult;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dromara.x.file.storage.core.FileStorageService;
|
||||
import org.dromara.x.file.storage.core.constant.Constant;
|
||||
import org.dromara.x.file.storage.core.presigned.GeneratePresignedUrlResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author yinxucun
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OssService {
|
||||
|
||||
private final OssProperties ossProperties;
|
||||
|
||||
private final FileStorageService fileStorageService;
|
||||
|
||||
private static final Instant expirationTime = new Date().toInstant().atZone(ZoneId.of("Asia/Shanghai"))
|
||||
.plusMinutes(10).toInstant();
|
||||
|
||||
public OssService(OssProperties ossProperties, FileStorageService fileStorageService) {
|
||||
this.ossProperties = ossProperties;
|
||||
this.fileStorageService = fileStorageService;
|
||||
log.info("初始化OSS配置:{}", ossProperties);
|
||||
}
|
||||
|
||||
|
||||
public FileUploadParamsResult getUploadParams(FileUploadRequestParams params) {
|
||||
return this.createSignedUrlForStringPut(params);
|
||||
}
|
||||
|
||||
public void download(HttpServletResponse httpServletResponse, String attachName) {
|
||||
GeneratePresignedUrlResult downloadResult = fileStorageService
|
||||
.generatePresignedUrl()
|
||||
.setPath(ossProperties.getFilePath()) // 文件路径
|
||||
.setFilename(attachName) // 文件名,也可以换成缩略图的文件名
|
||||
.setMethod(Constant.GeneratePresignedUrl.Method.GET) // 签名方法
|
||||
.setExpiration(Date.from(expirationTime)) // 过期时间 10 分钟
|
||||
.putResponseHeaders(
|
||||
Constant.Metadata.CONTENT_DISPOSITION, "attachment;filename=" + attachName)
|
||||
.generatePresignedUrl();
|
||||
try {
|
||||
httpServletResponse.sendRedirect(downloadResult.getUrl());
|
||||
} catch (IOException e) {
|
||||
log.error("下载文件失败", e);
|
||||
httpServletResponse.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private FileUploadParamsResult createSignedUrlForStringPut(FileUploadRequestParams params) {
|
||||
String fileExtension = FileUtil.extName(params.getFileName());
|
||||
String attachName = IdUtil.fastSimpleUUID() + (StringUtils.isNotBlank(fileExtension) ? "." + fileExtension : "");
|
||||
Date expirationTime = new Date(System.currentTimeMillis() + 600 * 1000);
|
||||
GeneratePresignedUrlResult uploadResult = fileStorageService
|
||||
.generatePresignedUrl()
|
||||
.setPath(ossProperties.getFilePath()) // 设置路径
|
||||
.setFilename(attachName) // 设置保存的文件名
|
||||
.setMethod(Constant.GeneratePresignedUrl.Method.PUT) // 签名方法
|
||||
.setExpiration(expirationTime) // 设置过期时间 10 分钟
|
||||
.putHeaders(Constant.Metadata.CONTENT_TYPE, params.getMediaType())
|
||||
.putHeaders(Constant.Metadata.CONTENT_LENGTH, String.valueOf(params.getFileSize()))
|
||||
.generatePresignedUrl();
|
||||
log.info("expirationTime:{},attachName:{}", DateUtil.format(expirationTime, "yyyy-MM-dd HH:mm:ss"), attachName);
|
||||
log.info("生成上传预签名 URL 结果:{}", uploadResult);
|
||||
FileUploadParamsResult result = new FileUploadParamsResult();
|
||||
result.setUrl(uploadResult.getUrl());
|
||||
result.setHeaders(uploadResult.getHeaders());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.dromara.x.file.storage.core.platform;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||
import com.amazonaws.auth.BasicAWSCredentials;
|
||||
import com.amazonaws.client.builder.AwsClientBuilder;
|
||||
import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.dromara.x.file.storage.core.FileStorageProperties.AmazonS3Config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 重写 Amazon S3 存储平台的 Client 工厂, 支持 withPathStyleAccessEnabled 配置
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class AmazonS3FileStorageClientFactory implements FileStorageClientFactory<AmazonS3> {
|
||||
private String platform;
|
||||
private String accessKey;
|
||||
private String secretKey;
|
||||
private String region;
|
||||
private String endPoint;
|
||||
private Map<String, Object> attr;
|
||||
private volatile AmazonS3 client;
|
||||
|
||||
public AmazonS3FileStorageClientFactory(AmazonS3Config config) {
|
||||
platform = config.getPlatform();
|
||||
accessKey = config.getAccessKey();
|
||||
secretKey = config.getSecretKey();
|
||||
region = config.getRegion();
|
||||
endPoint = config.getEndPoint();
|
||||
attr = config.getAttr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AmazonS3 getClient() {
|
||||
if (client == null) {
|
||||
synchronized (this) {
|
||||
if (client == null) {
|
||||
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard()
|
||||
.withCredentials(
|
||||
new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)));
|
||||
if (StrUtil.isNotBlank(endPoint)) {
|
||||
builder.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, region));
|
||||
} else if (StrUtil.isNotBlank(region)) {
|
||||
builder.withRegion(region);
|
||||
}
|
||||
// 使用路径访问样式
|
||||
Boolean forcePathStyle = MapUtil.getBool(attr, "forcePathStyle", false);
|
||||
builder.withPathStyleAccessEnabled(forcePathStyle);
|
||||
client = builder.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (client != null) {
|
||||
client.shutdown();
|
||||
client = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform-starter</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>starter-quartz</artifactId>
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.4.3</version>
|
||||
<version>3.5.4</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>bootx-platform</artifactId>
|
||||
<version>3.0.0.beta5</version>
|
||||
<version>3.0.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<description>基础脚手架服务</description>
|
||||
|
||||
@@ -25,18 +25,18 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<bootx-platform.version>3.0.0.beta5</bootx-platform.version>
|
||||
<bootx-platform.version>3.0.0</bootx-platform.version>
|
||||
<!-- 再高的的新版本与会knife4j 4.5冲突, 目前使用三方的knife4j依赖 -->
|
||||
<springdoc.version>2.7.0</springdoc.version>
|
||||
<hutool.version>5.8.31</hutool.version>
|
||||
<hutool.version>5.8.39</hutool.version>
|
||||
<bouncycastle.version>1.78.1</bouncycastle.version>
|
||||
<knife4j.version>4.6.0</knife4j.version>
|
||||
<mybatis-plus.version>3.5.9</mybatis-plus.version>
|
||||
<mybatis-plus-join.version>1.4.13</mybatis-plus-join.version>
|
||||
<mybatis-plus.version>3.5.12</mybatis-plus.version>
|
||||
<mybatis-plus-join.version>1.5.4</mybatis-plus-join.version>
|
||||
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
||||
<lock4j.version>2.2.7</lock4j.version>
|
||||
<x-file-storage.version>2.2.1</x-file-storage.version>
|
||||
<minio.version>8.5.4</minio.version>
|
||||
<x-file-storage.version>2.3.0</x-file-storage.version>
|
||||
<aws-s3.version>1.12.429</aws-s3.version>
|
||||
<qcloud.version>5.6.137</qcloud.version>
|
||||
<sa-token.version>1.39.0</sa-token.version>
|
||||
<justauth.version>1.16.6</justauth.version>
|
||||
|
||||
Reference in New Issue
Block a user