Merge branch '1.0.x' into dev

# Conflicts:
#	README.md
This commit is contained in:
Charles7c 2023-04-03 21:34:42 +08:00
commit 6bb15d782e
22 changed files with 91 additions and 65 deletions

View File

@ -19,7 +19,7 @@
<img src="https://gitee.com/Charles7c/continew-admin/badge/fork.svg?theme=white" alt="Gitee forks" />
</a>
📚 <a href="https://doc.charles7c.top" target="_blank">在线文档</a> | ✨ <a href="https://doc.charles7c.top/require" target="_blank">提交需求</a> | 🚀 <a href="https://cnadmin.charles7c.top" target="_blank">演示地址</a>(账号/密码admin/admin123
📚 [在线文档](https://doc.charles7c.top) | ✨ [提交需求](https://doc.charles7c.top/require) | 🚀 [演示地址](https://cnadmin.charles7c.top)(账号/密码admin/admin123
## 简介
@ -54,8 +54,9 @@ ContiNew Admin 中后台管理框架/脚手架Continue New Admin持续以
**v2.0.0** :fire: 升级并适配 Spring Boot 3.x。
- [ ] 依赖升级:升级并适配 Spring Boot 3.x
- [ ] 依赖升级:其他依赖升级
- [x] 依赖升级:升级并适配 Spring Boot 3.x
- [x] 依赖升级:其他依赖升级
- [x] 适配 Java 8 => Java 17 新 API 及特性
- [ ] 计划对接 <a href="https://gitee.com/aizuda/flowlong" target="_blank">FlowLong</a> 纯国产工作流引擎
- [ ] 其他需求汇集中...

View File

@ -16,9 +16,8 @@
package top.charles7c.cnadmin.common.config.properties;
import lombok.Data;
import org.springframework.stereotype.Component;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import cn.hutool.extra.spring.SpringUtil;
@ -29,8 +28,7 @@ import cn.hutool.extra.spring.SpringUtil;
* @author Charles7c
* @since 2022/12/21 20:21
*/
@Data
@Component
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RsaProperties {
/** 私钥 */

View File

@ -20,11 +20,11 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@ -40,10 +40,9 @@ import top.charles7c.cnadmin.common.util.ExceptionUtils;
*/
@Slf4j
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(ThreadPoolProperties.class)
public class ThreadPoolConfiguration {
private final ThreadPoolProperties threadPoolProperties;
/** 核心(最小)线程数 = CPU 核心数 + 1 */
private final int corePoolSize = Runtime.getRuntime().availableProcessors() + 1;
@ -52,7 +51,7 @@ public class ThreadPoolConfiguration {
*/
@Bean
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心最小线程数
executor.setCorePoolSize(corePoolSize);

View File

@ -19,7 +19,6 @@ package top.charles7c.cnadmin.common.config.threadpool;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 线程池配置属性
@ -29,7 +28,6 @@ import org.springframework.stereotype.Component;
* @since 2022/12/23 23:06
*/
@Data
@Component
@ConfigurationProperties(prefix = "thread-pool")
public class ThreadPoolProperties {

View File

@ -45,6 +45,11 @@ public class StringConsts implements StrPool {
*/
public static final String ASTERISK = "*";
/**
* 问号
*/
public static final String QUESTION_MARK = "?";
/**
* 中文逗号
*/

View File

@ -25,6 +25,8 @@ import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import top.charles7c.cnadmin.common.constant.StringConsts;
/**
* 异常工具类
*
@ -99,7 +101,7 @@ public class ExceptionUtils {
* @return /
*/
public static String exToBlank(ExSupplier<String> exSupplier) {
return exToDefault(exSupplier, "");
return exToDefault(exSupplier, StringConsts.EMPTY);
}
/**

View File

@ -24,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.util.StrUtil;
import top.charles7c.cnadmin.common.constant.StringConsts;
import top.charles7c.cnadmin.common.exception.ServiceException;
/**
@ -52,8 +53,8 @@ public class CheckUtils extends Validator {
* 字段值
*/
public static void throwIfNotExists(Object obj, String entityName, String fieldName, Object fieldValue) {
String message =
String.format("%s 为 [%s] 的 %s 记录已不存在", fieldName, fieldValue, StrUtil.replace(entityName, "DO", ""));
String message = String.format("%s 为 [%s] 的 %s 记录已不存在", fieldName, fieldValue,
StrUtil.replace(entityName, "DO", StringConsts.EMPTY));
throwIfNull(obj, message, EXCEPTION_TYPE);
}

View File

@ -47,6 +47,7 @@ import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import top.charles7c.cnadmin.auth.model.request.LoginRequest;
import top.charles7c.cnadmin.common.constant.StringConsts;
import top.charles7c.cnadmin.common.constant.SysConsts;
import top.charles7c.cnadmin.common.model.dto.LogContext;
import top.charles7c.cnadmin.common.util.ExceptionUtils;
@ -170,7 +171,8 @@ public class LogInterceptor implements HandlerInterceptor {
// 本框架代码规范例如@Tag(name = "部门管理 API") -> 部门管理
if (classTag != null) {
String name = classTag.name();
logDO.setModule(StrUtil.isNotBlank(name) ? name.replace("API", "").trim() : "请在该接口类上指定所属模块");
logDO
.setModule(StrUtil.isNotBlank(name) ? name.replace("API", StringConsts.EMPTY).trim() : "请在该接口类上指定所属模块");
}
// 例如@Log(module = "部门管理") -> 部门管理
if (classLog != null && StrUtil.isNotBlank(classLog.module())) {
@ -213,7 +215,7 @@ public class LogInterceptor implements HandlerInterceptor {
*/
private void logRequest(LogDO logDO, HttpServletRequest request) {
logDO.setRequestUrl(StrUtil.isBlank(request.getQueryString()) ? request.getRequestURL().toString()
: request.getRequestURL().append("?").append(request.getQueryString()).toString());
: request.getRequestURL().append(StringConsts.QUESTION_MARK).append(request.getQueryString()).toString());
logDO.setRequestMethod(request.getMethod());
logDO.setRequestHeaders(this.desensitize(ServletUtil.getHeaderMap(request)));
String requestBody = this.getRequestBody(request);

View File

@ -28,6 +28,7 @@ import org.springdoc.api.annotations.ParameterObject;
import org.springframework.format.annotation.DateTimeFormat;
import top.charles7c.cnadmin.common.annotation.Query;
import top.charles7c.cnadmin.common.constant.StringConsts;
/**
* 登录日志查询条件
@ -54,6 +55,6 @@ public class LoginLogQuery implements Serializable {
*/
@Schema(description = "登录时间")
@Query(type = Query.Type.BETWEEN)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = StringConsts.NORM_DATE_TIME_PATTERN)
private List<Date> createTime;
}

View File

@ -28,6 +28,7 @@ import org.springdoc.api.annotations.ParameterObject;
import org.springframework.format.annotation.DateTimeFormat;
import top.charles7c.cnadmin.common.annotation.Query;
import top.charles7c.cnadmin.common.constant.StringConsts;
/**
* 操作日志查询条件
@ -61,7 +62,7 @@ public class OperationLogQuery implements Serializable {
*/
@Schema(description = "操作时间")
@Query(type = Query.Type.BETWEEN)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = StringConsts.NORM_DATE_TIME_PATTERN)
private List<Date> createTime;
/**

View File

@ -28,6 +28,7 @@ import org.springdoc.api.annotations.ParameterObject;
import org.springframework.format.annotation.DateTimeFormat;
import top.charles7c.cnadmin.common.annotation.Query;
import top.charles7c.cnadmin.common.constant.StringConsts;
/**
* 系统日志查询条件
@ -47,6 +48,6 @@ public class SystemLogQuery implements Serializable {
*/
@Schema(description = "创建时间")
@Query(type = Query.Type.BETWEEN)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = StringConsts.NORM_DATE_TIME_PATTERN)
private List<Date> createTime;
}

View File

@ -147,7 +147,7 @@ public class SaTokenRedisDaoImpl implements SaTokenDao {
@Override
public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
Collection<String> keys = RedisUtils.keys(prefix + "*" + keyword + "*");
Collection<String> keys = RedisUtils.keys(String.format("%s*%s*", prefix, keyword));
List<String> list = new ArrayList<>(keys);
return SaFoxUtil.searchList(list, start, size, sortType);
}

View File

@ -27,6 +27,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.format.annotation.DateTimeFormat;
import top.charles7c.cnadmin.common.constant.StringConsts;
/**
* 在线用户查询条件
*
@ -50,6 +52,6 @@ public class OnlineUserQuery implements Serializable {
* 登录时间
*/
@Schema(description = "登录时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = StringConsts.NORM_DATE_TIME_PATTERN)
private List<Date> loginTime;
}

View File

@ -28,6 +28,7 @@ import org.springdoc.api.annotations.ParameterObject;
import org.springframework.format.annotation.DateTimeFormat;
import top.charles7c.cnadmin.common.annotation.Query;
import top.charles7c.cnadmin.common.constant.StringConsts;
/**
* 用户查询条件
@ -61,7 +62,7 @@ public class UserQuery implements Serializable {
*/
@Schema(description = "创建时间")
@Query(type = Query.Type.BETWEEN)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = StringConsts.NORM_DATE_TIME_PATTERN)
private List<Date> createTime;
/**

View File

@ -38,13 +38,12 @@ public interface RoleDeptService {
boolean save(List<Long> deptIds, Long roleId);
/**
* 根据角色 ID 查询
* 根据角色 ID 删除
*
* @param roleId
* 角色 ID
* @return 部门 ID 列表
* @param roleIds
* 角色 ID 列表
*/
List<Long> listDeptIdByRoleId(Long roleId);
void deleteByRoleIds(List<Long> roleIds);
/**
* 根据部门 ID 删除
@ -55,10 +54,11 @@ public interface RoleDeptService {
void deleteByDeptIds(List<Long> deptIds);
/**
* 根据角色 ID 删除
* 根据角色 ID 查询
*
* @param roleIds
* 角色 ID 列表
* @param roleId
* 角色 ID
* @return 部门 ID 列表
*/
void deleteByRoleIds(List<Long> roleIds);
List<Long> listDeptIdByRoleId(Long roleId);
}

View File

@ -37,6 +37,14 @@ public interface RoleMenuService {
*/
boolean save(List<Long> menuIds, Long roleId);
/**
* 根据角色 ID 删除
*
* @param roleIds
* 角色 ID 列表
*/
void deleteByRoleIds(List<Long> roleIds);
/**
* 根据角色 ID 查询
*
@ -45,12 +53,4 @@ public interface RoleMenuService {
* @return 菜单 ID 列表
*/
List<Long> listMenuIdByRoleIds(List<Long> roleIds);
/**
* 根据角色 ID 删除
*
* @param roleIds
* 角色 ID 列表
*/
void deleteByRoleIds(List<Long> roleIds);
}

View File

@ -38,13 +38,12 @@ public interface UserRoleService {
boolean save(List<Long> roleIds, Long userId);
/**
* 根据角色 ID 列表查询
* 根据用户 ID 删除
*
* @param roleIds
* 角色 ID 列表
* @return 总记录数
* @param userIds
* 用户 ID 列表
*/
Long countByRoleIds(List<Long> roleIds);
void deleteByUserIds(List<Long> userIds);
/**
* 根据用户 ID 查询
@ -56,10 +55,11 @@ public interface UserRoleService {
List<Long> listRoleIdByUserId(Long userId);
/**
* 根据用户 ID 删除
* 根据角色 ID 列表查询
*
* @param userIds
* 用户 ID 列表
* @param roleIds
* 角色 ID 列表
* @return 总记录数
*/
void deleteByUserIds(List<Long> userIds);
Long countByRoleIds(List<Long> roleIds);
}

View File

@ -22,6 +22,7 @@ import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.collection.CollUtil;
@ -42,6 +43,7 @@ public class RoleDeptServiceImpl implements RoleDeptService {
private final RoleDeptMapper roleDeptMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean save(List<Long> deptIds, Long roleId) {
// 检查是否有变更
List<Long> oldDeptIdList = roleDeptMapper.lambdaQuery().select(RoleDeptDO::getDeptId)
@ -58,17 +60,19 @@ public class RoleDeptServiceImpl implements RoleDeptService {
}
@Override
public List<Long> listDeptIdByRoleId(Long roleId) {
return roleDeptMapper.selectDeptIdByRoleId(roleId);
@Transactional(rollbackFor = Exception.class)
public void deleteByRoleIds(List<Long> roleIds) {
roleDeptMapper.lambdaUpdate().in(RoleDeptDO::getRoleId, roleIds).remove();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByDeptIds(List<Long> deptIds) {
roleDeptMapper.lambdaUpdate().in(RoleDeptDO::getDeptId, deptIds).remove();
}
@Override
public void deleteByRoleIds(List<Long> roleIds) {
roleDeptMapper.lambdaUpdate().in(RoleDeptDO::getRoleId, roleIds).remove();
public List<Long> listDeptIdByRoleId(Long roleId) {
return roleDeptMapper.selectDeptIdByRoleId(roleId);
}
}

View File

@ -23,6 +23,7 @@ import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.collection.CollUtil;
@ -43,6 +44,7 @@ public class RoleMenuServiceImpl implements RoleMenuService {
private final RoleMenuMapper roleMenuMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean save(List<Long> menuIds, Long roleId) {
// 检查是否有变更
List<Long> oldMenuIdList = roleMenuMapper.lambdaQuery().select(RoleMenuDO::getMenuId)
@ -58,6 +60,12 @@ public class RoleMenuServiceImpl implements RoleMenuService {
return roleMenuMapper.insertBatch(roleMenuList);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteByRoleIds(List<Long> roleIds) {
roleMenuMapper.lambdaUpdate().in(RoleMenuDO::getRoleId, roleIds).remove();
}
@Override
public List<Long> listMenuIdByRoleIds(List<Long> roleIds) {
if (CollUtil.isEmpty(roleIds)) {
@ -65,9 +73,4 @@ public class RoleMenuServiceImpl implements RoleMenuService {
}
return roleMenuMapper.selectMenuIdByRoleIds(roleIds);
}
@Override
public void deleteByRoleIds(List<Long> roleIds) {
roleMenuMapper.lambdaUpdate().in(RoleMenuDO::getRoleId, roleIds).remove();
}
}

View File

@ -22,6 +22,7 @@ import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.collection.CollUtil;
@ -42,6 +43,7 @@ public class UserRoleServiceImpl implements UserRoleService {
private final UserRoleMapper userRoleMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean save(List<Long> roleIds, Long userId) {
// 检查是否有变更
List<Long> oldRoleIdList = userRoleMapper.lambdaQuery().select(UserRoleDO::getRoleId)
@ -58,8 +60,9 @@ public class UserRoleServiceImpl implements UserRoleService {
}
@Override
public Long countByRoleIds(List<Long> roleIds) {
return userRoleMapper.lambdaQuery().in(UserRoleDO::getRoleId, roleIds).count();
@Transactional(rollbackFor = Exception.class)
public void deleteByUserIds(List<Long> userIds) {
userRoleMapper.lambdaUpdate().in(UserRoleDO::getUserId, userIds).remove();
}
@Override
@ -68,7 +71,7 @@ public class UserRoleServiceImpl implements UserRoleService {
}
@Override
public void deleteByUserIds(List<Long> userIds) {
userRoleMapper.lambdaUpdate().in(UserRoleDO::getUserId, userIds).remove();
public Long countByRoleIds(List<Long> roleIds) {
return userRoleMapper.lambdaQuery().in(UserRoleDO::getRoleId, roleIds).count();
}
}

View File

@ -186,6 +186,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserVO,
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateBasicInfo(UpdateBasicInfoRequest request, Long id) {
super.getById(id);
baseMapper.lambdaUpdate().set(UserDO::getNickname, request.getNickname())
@ -219,6 +220,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserVO,
}
@Override
@Transactional(rollbackFor = Exception.class)
public void resetPassword(Long id) {
UserDO user = super.getById(id);
user.setPassword(SecureUtils.md5Salt(SysConsts.DEFAULT_PASSWORD, id.toString()));
@ -227,6 +229,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserVO,
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateRole(UpdateUserRoleRequest request, Long id) {
super.getById(id);
// 保存用户和角色关联

View File

@ -84,7 +84,8 @@ public class UserCenterController {
String rawNewPassword =
ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updatePasswordRequest.getNewPassword()));
ValidationUtils.throwIfBlank(rawNewPassword, "新密码解密失败");
ValidationUtils.throwIf(!ReUtil.isMatch(RegexConsts.PASSWORD, rawNewPassword), "密码长度 6 到 32 位,同时包含字母和数字");
ValidationUtils.throwIf(!ReUtil.isMatch(RegexConsts.PASSWORD, rawNewPassword),
"密码长度为 6 到 32 位,可以包含字母、数字、下划线,特殊字符,同时包含字母和数字");
// 修改密码
userService.updatePassword(rawOldPassword, rawNewPassword, LoginHelper.getUserId());