16 Commits

Author SHA1 Message Date
AprilWind
32ad28c3dc update 优化通过角色ID查询用户逻辑 2024-09-06 14:24:06 +08:00
AprilWind
6886e9fd5b update 优化查询用户时多余重复判断以及去重 2024-09-06 14:14:15 +08:00
疯狂的狮子Li
f20130d3db fix 修复 commons-io 依赖冲突问题 2024-09-05 18:50:28 +08:00
疯狂的狮子Li
df9cc881f1 update 优化 连接SSE token过期导致的 Servlet异常 2024-09-05 18:50:00 +08:00
疯狂的狮子Li
4044988afa update 优化 代码生成菜单id匹配写法 2024-09-04 16:16:53 +08:00
疯狂的狮子Li
d3360e81b9 update sa-token 1.38.0 => 1.39.0 2024-09-03 13:52:50 +08:00
疯狂的狮子Li
df070b7d78 update 调整 xml 格式 2024-09-02 14:16:40 +08:00
疯狂的狮子Li
83dd98faf3 fix 修复 开启子部门 父部门未关联开启问题 2024-09-02 14:12:02 +08:00
疯狂的狮子Li
37f89f560f update 优化 更新sql关键字 2024-09-02 13:06:31 +08:00
疯狂的狮子Li
918ed0d6d0 update 优化 删除多余的引号 2024-08-31 23:30:50 +08:00
疯狂的狮子Li
a3c9edde78 fix 修复 升级依赖导致的依赖冲突 2024-08-29 20:53:39 +08:00
疯狂的狮子Li
cac0a4cd16 update 优化 RegexUtils#extractFromString 方法未匹配返回null不返回默认值问题 2024-08-29 14:12:07 +08:00
疯狂的狮子Li
581b6e03d5 update 优化 oss上传直接从请求头获取文件类型 2024-08-29 10:49:41 +08:00
疯狂的狮子Li
801cc584e5 update 优化 代码生成表名判断 使用开头判断避免误判 2024-08-29 10:41:45 +08:00
疯狂的狮子Li
b82ff8617e add 增加 同步租户字典功能 2024-08-26 17:56:19 +08:00
疯狂的狮子Li
c87016c1af update 优化 excel导入 适配异常结构 2024-08-26 15:38:48 +08:00
17 changed files with 208 additions and 39 deletions

View File

@@ -23,7 +23,7 @@
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<easyexcel.version>4.0.2</easyexcel.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.38.0</satoken.version>
<satoken.version>1.39.0</satoken.version>
<mybatis-plus.version>3.5.7</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.31</hutool.version>
@@ -329,9 +329,9 @@
</dependency>
<dependency>
<artifactId>commons-compress</artifactId>
<groupId>org.apache.commons</groupId>
<version>1.26.2</version>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>

View File

@@ -21,7 +21,8 @@ public final class RegexUtils extends ReUtil {
*/
public static String extractFromString(String input, String regex, String defaultInput) {
try {
return ReUtil.get(regex, input, 1);
String str = ReUtil.get(regex, input, 1);
return str == null ? defaultInput : str;
} catch (Exception e) {
return defaultInput;
}

View File

@@ -15,7 +15,7 @@ public class SqlUtil {
/**
* 定义常用的 sql关键字
*/
public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
public static String SQL_REGEX = "and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
/**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)

View File

@@ -25,11 +25,6 @@
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<artifactId>commons-compress</artifactId>
<groupId>org.apache.commons</groupId>
<version>1.26.2</version>
</dependency>
</dependencies>
</project>

View File

@@ -340,8 +340,8 @@ public class OssClient {
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult uploadSuffix(byte[] data, String suffix) {
return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), FileUtils.getMimeType(suffix));
public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {
return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), contentType);
}
/**
@@ -353,8 +353,8 @@ public class OssClient {
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) {
return upload(inputStream, getPath(properties.getPrefix(), suffix), length, FileUtils.getMimeType(suffix));
public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length, String contentType) {
return upload(inputStream, getPath(properties.getPrefix(), suffix), length, contentType);
}
/**

View File

@@ -2,6 +2,7 @@ package org.dromara.common.web.handler;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
@@ -10,6 +11,7 @@ import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
@@ -53,6 +55,22 @@ public class GlobalExceptionHandler {
return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
}
/**
* servlet异常
*/
@ExceptionHandler(ServletException.class)
public R<Void> handleServletException(ServletException e, HttpServletRequest request) {
if (StringUtils.contains(e.getMessage(), "NotLoginException")) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源");
} else {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestURI, e);
return R.fail(e.getMessage());
}
}
/**
* 业务异常
*/

View File

@@ -162,7 +162,7 @@ public class GenTable extends BaseEntity {
* 上级菜单ID字段
*/
@TableField(exist = false)
private String parentMenuId;
private Long parentMenuId;
/**
* 上级菜单名称字段

View File

@@ -137,7 +137,7 @@ public class GenTableServiceImpl implements IGenTableService {
}
// 过滤并转换表格数据
List<GenTable> tables = tablesMap.values().stream()
.filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE))
.filter(x -> !startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE))
.filter(x -> {
if (CollUtil.isEmpty(tableNames)) {
return true;
@@ -174,6 +174,16 @@ public class GenTableServiceImpl implements IGenTableService {
return TableDataInfo.build(page);
}
public static boolean startWithAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
// 判断是否是以指定字符串开头
for (CharSequence searchCharSequence : searchCharSequences) {
if (StringUtils.startsWithIgnoreCase(cs, searchCharSequence)) {
return true;
}
}
return false;
}
/**
* 查询据库列表
*
@@ -548,7 +558,7 @@ public class GenTableServiceImpl implements IGenTableService {
String treeCode = paramsObj.getStr(GenConstants.TREE_CODE);
String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE);
String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID);
Long parentMenuId = paramsObj.getLong(GenConstants.PARENT_MENU_ID);
String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME);
genTable.setTreeCode(treeCode);

View File

@@ -58,7 +58,7 @@ public class ${ClassName}Vo implements Serializable {
* ${column.columnComment}Url
*/
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
private String ${column.javaField}Url";
private String ${column.javaField}Url;
#end
#end
#end

View File

@@ -176,4 +176,18 @@ public class SysTenantController extends BaseController {
return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
}
/**
* 同步租户字典
*/
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@Log(title = "同步租户字典", businessType = BusinessType.INSERT)
@GetMapping("/syncTenantDict")
public R<Void> syncTenantDict() {
if (!TenantHelper.isEnable()) {
return R.fail("当前未开启租户模式");
}
tenantService.syncTenantDict();
return R.ok("同步租户字典成功");
}
}

View File

@@ -5,8 +5,11 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.excel.core.ExcelListener;
import org.dromara.common.excel.core.ExcelResult;
@@ -80,7 +83,11 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、账号 " + userVo.getUserName() + " 导入失败:";
failureMsg.append(msg).append(e.getMessage());
String message = e.getMessage();
if (e instanceof ConstraintViolationException cvException) {
message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
}
failureMsg.append(msg).append(message);
log.error(msg, e);
}
}

View File

@@ -79,4 +79,9 @@ public interface ISysTenantService {
* 同步租户套餐
*/
Boolean syncTenantPackage(String tenantId, Long packageId);
/**
* 同步租户字典
*/
void syncTenantDict();
}

View File

@@ -275,6 +275,8 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
dept.setAncestors(newAncestors);
updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
}
} else {
dept.setAncestors(oldDept.getAncestors());
}
int result = baseMapper.updateById(dept);
if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())

View File

@@ -195,7 +195,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
OssClient storage = OssFactory.instance();
UploadResult uploadResult;
try {
uploadResult = storage.uploadSuffix(file.getBytes(), suffix);
uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
} catch (IOException e) {
throw new ServiceException(e.getMessage());
}

View File

@@ -1,6 +1,7 @@
package org.dromara.system.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
@@ -14,9 +15,13 @@ import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.tenant.core.TenantEntity;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysTenantVo;
@@ -27,10 +32,7 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.*;
/**
* 租户Service业务层处理
@@ -369,4 +371,86 @@ public class SysTenantServiceImpl implements ISysTenantService {
}
return true;
}
/**
* 同步租户字典
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void syncTenantDict() {
// 查询超管 所有字典数据
List<SysDictType> dictTypeList = new ArrayList<>();
List<SysDictData> dictDataList = new ArrayList<>();
TenantHelper.ignore(() -> {
dictTypeList.addAll(dictTypeMapper.selectList());
dictDataList.addAll(dictDataMapper.selectList());
});
Map<String, List<SysDictType>> typeMap = StreamUtils.groupByKey(dictTypeList, TenantEntity::getTenantId);
Map<String, Map<String, List<SysDictData>>> typeDataMap = StreamUtils.groupBy2Key(
dictDataList, TenantEntity::getTenantId, SysDictData::getDictType);
// 管理租户字典数据
List<SysDictType> defaultTypeMap = typeMap.get(TenantConstants.DEFAULT_TENANT_ID);
Map<String, List<SysDictData>> defaultTypeDataMap = typeDataMap.get(TenantConstants.DEFAULT_TENANT_ID);
// 获取所有租户编号
List<String> tenantIds = baseMapper.selectObjs(
new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId)
.eq(SysTenant::getStatus, TenantConstants.NORMAL), x -> {return Convert.toStr(x);});
List<SysDictType> saveTypeList = new ArrayList<>();
List<SysDictData> saveDataList = new ArrayList<>();
Set<String> set = new HashSet<>();
for (String tenantId : tenantIds) {
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
continue;
}
for (SysDictType dictType : defaultTypeMap) {
List<String> typeList = StreamUtils.toList(typeMap.get(tenantId), SysDictType::getDictType);
List<SysDictData> dataList = defaultTypeDataMap.get(dictType.getDictType());
if (typeList.contains(dictType.getDictType())) {
List<SysDictData> dataListTenant = typeDataMap.get(tenantId).get(dictType.getDictType());
Map<String, SysDictData> map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue);
for (SysDictData dictData : dataList) {
if (!map.containsKey(dictData.getDictValue())) {
// 设置字典编码为 null
dictData.setDictCode(null);
dictData.setTenantId(tenantId);
dictData.setCreateTime(null);
dictData.setUpdateTime(null);
set.add(tenantId);
saveDataList.add(dictData);
}
}
} else {
dictType.setDictId(null);
dictType.setTenantId(tenantId);
dictType.setCreateTime(null);
dictType.setUpdateTime(null);
set.add(tenantId);
saveTypeList.add(dictType);
if (CollUtil.isNotEmpty(dataList)) {
// 筛选出 dictType 对应的 data
for (SysDictData dictData : dataList) {
// 设置字典编码为 null
dictData.setDictCode(null);
dictData.setTenantId(tenantId);
dictData.setCreateTime(null);
dictData.setUpdateTime(null);
set.add(tenantId);
}
saveDataList.addAll(dataList);
}
}
}
}
if (CollUtil.isNotEmpty(saveTypeList)) {
dictTypeMapper.insertBatch(saveTypeList);
}
if (CollUtil.isNotEmpty(saveDataList)) {
dictDataMapper.insertBatch(saveDataList);
}
for (String tenantId : set) {
TenantHelper.dynamic(tenantId, () -> CacheUtils.clear(CacheNames.SYS_DICT));
}
}
}

View File

@@ -42,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 用户 业务层处理
@@ -628,6 +629,12 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
return ObjectUtil.isNull(sysUser) ? null : sysUser.getEmail();
}
/**
* 通过用户ID查询用户列表
*
* @param userIds 用户ids
* @return 用户列表
*/
@Override
public List<UserDTO> selectListByIds(List<Long> userIds) {
if (CollUtil.isEmpty(userIds)) {
@@ -636,28 +643,54 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
.eq(SysUser::getStatus, UserConstants.USER_NORMAL)
.in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
.in(SysUser::getUserId, userIds));
return BeanUtil.copyToList(list, UserDTO.class);
}
/**
* 通过角色ID查询用户ID
*
* @param roleIds 角色ids
* @return 用户ids
*/
@Override
public List<Long> selectUserIdsByRoleIds(List<Long> roleIds) {
List<SysUserRole> userRoles = userRoleMapper.selectList(
new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
return StreamUtils.toList(userRoles, SysUserRole::getUserId);
}
@Override
public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
if (CollUtil.isEmpty(roleIds)) {
return List.of();
}
List<SysUserRole> userRoles = userRoleMapper.selectList(
new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
List<Long> userIds = StreamUtils.toList(userRoles, SysUserRole::getUserId);
return selectListByIds(userIds);
return StreamUtils.toList(userRoles, SysUserRole::getUserId);
}
/**
* 通过角色ID查询用户
*
* @param roleIds 角色ids
* @return 用户
*/
@Override
public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
if (CollUtil.isEmpty(roleIds)) {
return List.of();
}
// 通过角色ID获取用户角色信息
List<SysUserRole> userRoles = userRoleMapper.selectList(
new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
// 获取用户ID列表
Set<Long> userIds = StreamUtils.toSet(userRoles, SysUserRole::getUserId);
return selectListByIds(new ArrayList<>(userIds));
}
/**
* 通过部门ID查询用户
*
* @param deptIds 部门ids
* @return 用户
*/
@Override
public List<UserDTO> selectUsersByDeptIds(List<Long> deptIds) {
if (CollUtil.isEmpty(deptIds)) {
@@ -666,7 +699,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
.eq(SysUser::getStatus, UserConstants.USER_NORMAL)
.in(CollUtil.isNotEmpty(deptIds), SysUser::getDeptId, deptIds));
.in(SysUser::getDeptId, deptIds));
return BeanUtil.copyToList(list, UserDTO.class);
}
}