Merge branch 'test' into test-dsc
* test: 修复BUG710,添加文件下载次数统计 修改私服地址,把 seata-dm 项目从 dsc挪过来 feat(gateway): 添加API客户端凭证加密功能支持 bmp 已挪到 ztcloud-dist 仓库 修改发布信息 增加快照仓库 恢复 erp 模块数据权限 从maven模块中移除 zt-server 修改版本号 feat:登陆用户的部门数据权限接口增加角色参数;获取当前用户可访问的顶级部门列表不校验数据权限 no message
This commit is contained in:
15
pom.xml
15
pom.xml
@@ -25,6 +25,7 @@
|
||||
<module>zt-module-databus</module>
|
||||
<!-- <module>zt-module-rule</module>-->
|
||||
<!-- <module>zt-module-html2pdf</module>-->
|
||||
<!-- <module>zt-server</module>-->
|
||||
</modules>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
@@ -32,7 +33,7 @@
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<revision>3.0.46</revision>
|
||||
<revision>3.0.47-SNAPSHOT</revision>
|
||||
<!-- Maven 相关 -->
|
||||
<java.version>17</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
@@ -203,7 +204,7 @@
|
||||
<repository>
|
||||
<id>ZT</id>
|
||||
<name>中铜 ZStack 私服</name>
|
||||
<url>http://172.16.46.63:30708/repository/test/</url>
|
||||
<url>http://172.16.46.63:30708/repository/zt-cloud/</url>
|
||||
<releases>
|
||||
<updatePolicy>always</updatePolicy>
|
||||
<checksumPolicy>warn</checksumPolicy>
|
||||
@@ -221,11 +222,11 @@
|
||||
<name>中铜 ZStack 私服</name>
|
||||
<url>http://172.16.46.63:30708/repository/test/</url>
|
||||
</repository>
|
||||
<!-- <snapshotRepository>-->
|
||||
<!-- <id>ZT</id>-->
|
||||
<!-- <name>中铜 ZStack 私服</name>-->
|
||||
<!-- <url>https://your-nexus.example.com/repository/maven-snapshots/</url>-->
|
||||
<!-- </snapshotRepository>-->
|
||||
<snapshotRepository>
|
||||
<id>ZT-snap</id>
|
||||
<name>中铜 ZStack 私服</name>
|
||||
<url>http://172.16.46.63:30708/repository/test-snap/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<profiles>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-- 为 API 客户端凭证表添加"是否启用加密"字段
|
||||
-- 2026-01-14
|
||||
|
||||
ALTER TABLE databus_api_client_credential
|
||||
ADD enable_encryption BIT DEFAULT '1' NOT NULL;
|
||||
|
||||
COMMENT ON COLUMN databus_api_client_credential.enable_encryption IS '是否启用加密传输';
|
||||
@@ -339,7 +339,8 @@ CREATE TABLE infra_file (
|
||||
create_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updater varchar(64) DEFAULT '' NULL,
|
||||
update_time datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
deleted bit DEFAULT '0' NOT NULL
|
||||
deleted bit DEFAULT '0' NOT NULL,
|
||||
DOWNLOAD_COUNT INT DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN infra_file.id IS '文件编号';
|
||||
@@ -356,6 +357,7 @@ COMMENT ON COLUMN infra_file.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN infra_file.updater IS '更新者';
|
||||
COMMENT ON COLUMN infra_file.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN infra_file.deleted IS '是否删除';
|
||||
COMMENT ON COLUMN INFRA_FILE.DOWNLOAD_COUNT IS '下载次数';
|
||||
COMMENT ON TABLE infra_file IS '文件表';
|
||||
|
||||
CREATE INDEX idx_infra_file_hash ON infra_file(hash);
|
||||
|
||||
5
sql/dm/添加文件下载次数统计字段.sql
Normal file
5
sql/dm/添加文件下载次数统计字段.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- 添加文件下载次数统计字段
|
||||
ALTER TABLE JYGK_TEST.INFRA_FILE
|
||||
ADD DOWNLOAD_COUNT INT DEFAULT 0 NOT NULL;
|
||||
|
||||
COMMENT ON COLUMN JYGK_TEST.INFRA_FILE.DOWNLOAD_COUNT IS '下载次数';
|
||||
@@ -10,11 +10,11 @@
|
||||
<name>中铜 ZStack 私服</name>
|
||||
<url>http://172.16.46.63:30708/repository/test/</url>
|
||||
</repository>
|
||||
<!-- <snapshotRepository>-->
|
||||
<!-- <id>ZT</id>-->
|
||||
<!-- <name>中铜 ZStack 私服</name>-->
|
||||
<!-- <url>https://your-nexus.example.com/repository/maven-snapshots/</url>-->
|
||||
<!-- </snapshotRepository>-->
|
||||
<snapshotRepository>
|
||||
<id>ZT-snap</id>
|
||||
<name>中铜 ZStack 私服</name>
|
||||
<url>http://172.16.46.63:30708/repository/test-snap/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-dependencies</artifactId>
|
||||
@@ -26,7 +26,7 @@
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<properties>
|
||||
<revision>3.0.46</revision>
|
||||
<revision>3.0.47-SNAPSHOT</revision>
|
||||
<flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
|
||||
<!-- 统一依赖管理 -->
|
||||
<spring.boot.version>3.4.5</spring.boot.version>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<module>zt-spring-boot-starter-job</module>
|
||||
<module>zt-spring-boot-starter-mq</module>
|
||||
<module>zt-spring-boot-starter-rpc</module>
|
||||
|
||||
<module>zt-spring-boot-starter-seata-dm</module>
|
||||
<module>zt-spring-boot-starter-excel</module>
|
||||
<module>zt-spring-boot-starter-test</module>
|
||||
|
||||
|
||||
@@ -40,4 +40,11 @@ public interface PermissionCommonApi {
|
||||
@Parameter(name = "userId", description = "用户编号", example = "2", required = true)
|
||||
CommonResult<DeptDataPermissionRespDTO> getDeptDataPermission(@RequestParam("userId") Long userId);
|
||||
|
||||
@GetMapping(PREFIX + "/get-dept-data-permission-with-roleCodes")
|
||||
@Operation(summary = "获得登陆用户的部门数据权限")
|
||||
@Parameters({
|
||||
@Parameter(name = "userId", description = "用户编号", example = "2", required = true),
|
||||
@Parameter(name = "roleCodes", description = "角色编码", example = "2", required = true)
|
||||
})
|
||||
CommonResult<DeptDataPermissionRespDTO> getDeptDataPermissionWithRoleCodes(@RequestParam("userId") Long userId, @RequestParam("roleCodes") String roleCodes);
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class BusinessDataPermissionEntityScanner {
|
||||
*/
|
||||
private static final Set<String> EXCLUDED_PACKAGE_PREFIXES = Set.of(
|
||||
"com.zt.plat.module.backendlogistics",
|
||||
"com.zt.plat.module.erp",
|
||||
// "com.zt.plat.module.erp",
|
||||
"com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO");
|
||||
|
||||
private final Set<String> basePackages;
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.zt.plat.framework.tenant.core.context;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 部门上下文 Holder,使用 {@link TransmittableThreadLocal} 支持在线程池/异步场景下的上下文传递。
|
||||
*
|
||||
@@ -15,6 +17,8 @@ public class DeptContextHolder {
|
||||
private static final ThreadLocal<Long> COMPANY_ID = new TransmittableThreadLocal<>();
|
||||
/** 是否忽略部门数据权限 */
|
||||
private static final ThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>();
|
||||
/** 角色编码列表 */
|
||||
private static final ThreadLocal<List<String>> ROLE_CODE_LIST = new TransmittableThreadLocal<>();
|
||||
|
||||
public static Long getDeptId() {
|
||||
return DEPT_ID.get();
|
||||
@@ -32,6 +36,12 @@ public class DeptContextHolder {
|
||||
COMPANY_ID.set(companyId);
|
||||
}
|
||||
|
||||
public static void setContext(Long deptId, Long companyId, List<String> roleCodeList) {
|
||||
DEPT_ID.set(deptId);
|
||||
COMPANY_ID.set(companyId);
|
||||
ROLE_CODE_LIST.set(roleCodeList);
|
||||
}
|
||||
|
||||
public static void setDeptId(Long deptId) {
|
||||
DEPT_ID.set(deptId);
|
||||
}
|
||||
@@ -53,9 +63,20 @@ public class DeptContextHolder {
|
||||
return Boolean.TRUE.equals(IGNORE.get());
|
||||
}
|
||||
|
||||
public static void setRoleCodeList(List<String> roleCodeList) {
|
||||
ROLE_CODE_LIST.set(roleCodeList);
|
||||
}
|
||||
public static List<String> getRoleCodeList() {
|
||||
return ROLE_CODE_LIST.get();
|
||||
}
|
||||
public static void clearRoleCodeList(){
|
||||
ROLE_CODE_LIST.remove();
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
DEPT_ID.remove();
|
||||
COMPANY_ID.remove();
|
||||
IGNORE.remove();
|
||||
ROLE_CODE_LIST.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ public class ApiClientCredentialRespVO {
|
||||
@Schema(description = "匿名访问固定用户昵称", example = "张三")
|
||||
private String anonymousUserNickname;
|
||||
|
||||
@Schema(description = "是否启用加密", example = "true")
|
||||
private Boolean enableEncryption;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
@@ -45,4 +45,8 @@ public class ApiClientCredentialSaveReqVO {
|
||||
@Schema(description = "匿名访问固定用户 ID", example = "1024")
|
||||
private Long anonymousUserId;
|
||||
|
||||
@Schema(description = "是否启用加密", example = "true")
|
||||
@NotNull(message = "启用加密标识不能为空")
|
||||
private Boolean enableEncryption;
|
||||
|
||||
}
|
||||
|
||||
@@ -38,4 +38,6 @@ public class ApiClientCredentialDO extends BaseDO {
|
||||
|
||||
private Long anonymousUserId;
|
||||
|
||||
private Boolean enableEncryption;
|
||||
|
||||
}
|
||||
|
||||
@@ -238,6 +238,11 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
private byte[] decryptRequestBody(byte[] originalBody,
|
||||
ApiClientCredentialDO credential,
|
||||
ApiGatewayProperties.Security security) {
|
||||
// 检查是否启用加密,如果未启用则直接返回原文
|
||||
if (credential != null && Boolean.FALSE.equals(credential.getEnableEncryption())) {
|
||||
return originalBody != null ? originalBody : new byte[0];
|
||||
}
|
||||
|
||||
if (originalBody == null || originalBody.length == 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
@@ -390,6 +395,11 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
private void encryptResponse(ContentCachingResponseWrapper responseWrapper,
|
||||
ApiClientCredentialDO credential,
|
||||
ApiGatewayProperties.Security security) throws IOException {
|
||||
// 检查是否启用加密,如果未启用则直接返回,不加密响应
|
||||
if (credential != null && Boolean.FALSE.equals(credential.getEnableEncryption())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!security.isEncryptResponse()) {
|
||||
return;
|
||||
}
|
||||
@@ -524,6 +534,10 @@ public class GatewaySecurityFilter extends OncePerRequestFilter {
|
||||
if (security == null || credential == null) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否启用加密,如果未启用则不加密错误响应
|
||||
if (Boolean.FALSE.equals(credential.getEnableEncryption())) {
|
||||
return false;
|
||||
}
|
||||
if (!security.isEncryptResponse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -34,4 +34,7 @@ public class FileRespDTO {
|
||||
@Schema(description = "文件内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private byte[] content;
|
||||
|
||||
@Schema(description = "文件下载次数")
|
||||
private Integer downloadCount;
|
||||
|
||||
}
|
||||
@@ -133,6 +133,10 @@ public class FileController {
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
return;
|
||||
}
|
||||
|
||||
// 统计下载次数
|
||||
fileService.incDownloadCount(configId,path);
|
||||
|
||||
writeAttachment(response, path, content);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,4 +99,7 @@ public class FileRespVO {
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "下载次数")
|
||||
private Integer downloadCount;
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,11 @@ public class FileDO extends BaseDO {
|
||||
*/
|
||||
private String aesIv;
|
||||
|
||||
/**
|
||||
* 文件下载次数统计
|
||||
*/
|
||||
private Integer downloadCount;
|
||||
|
||||
/**
|
||||
* 是否加密
|
||||
* <p>
|
||||
|
||||
@@ -6,6 +6,8 @@ import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.infra.controller.admin.file.vo.file.FilePageReqVO;
|
||||
import com.zt.plat.module.infra.dal.dataobject.file.FileDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
/**
|
||||
* 文件操作 Mapper
|
||||
@@ -32,4 +34,7 @@ public interface FileMapper extends BaseMapperX<FileDO> {
|
||||
return selectFirstOne(FileDO::getHash, hash);
|
||||
}
|
||||
|
||||
|
||||
@Update("UPDATE INFRA_FILE SET DOWNLOAD_COUNT = DOWNLOAD_COUNT + 1 WHERE CONFIG_ID = #{configId} AND PATH = #{path}")
|
||||
int incDownloadCount(@Param("configId") Long configId, @Param("path") String path);
|
||||
}
|
||||
|
||||
@@ -112,4 +112,11 @@ public interface FileService {
|
||||
FileDO getActiveFileById(Long fileId);
|
||||
|
||||
boolean verifyCode(Long fileId, Long userId, String code) throws Exception;
|
||||
|
||||
/**
|
||||
* 更新文件下载次数
|
||||
* @param configId
|
||||
* @param path
|
||||
*/
|
||||
void incDownloadCount(Long configId, String path);
|
||||
}
|
||||
|
||||
@@ -334,4 +334,9 @@ public class FileServiceImpl implements FileService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incDownloadCount(Long configId, String path) {
|
||||
fileMapper.incDownloadCount(configId, path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,4 +86,8 @@ public class PermissionApiImpl implements PermissionApi {
|
||||
return success(permissionService.getDeptDataPermission(userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<DeptDataPermissionRespDTO> getDeptDataPermissionWithRoleCodes(Long userId, String roleCodes) {
|
||||
return success(permissionService.getDeptDataPermissionWithRoleCodes(userId, roleCodes));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ public class DeptController {
|
||||
|
||||
@GetMapping("/top-level-list")
|
||||
@Operation(summary = "获取当前用户可访问的顶级部门列表", description = "用于懒加载,返回当前用户所属部门的最顶层祖先部门,如果用户没有关联任何部门则返回空列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
// @PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
public CommonResult<List<DeptRespVO>> getTopLevelDeptList() {
|
||||
List<DeptDO> list = deptService.getTopLevelDeptList();
|
||||
return success(BeanUtils.toBean(list, DeptRespVO.class));
|
||||
|
||||
@@ -143,6 +143,7 @@ public interface PermissionService {
|
||||
* @return 部门数据权限
|
||||
*/
|
||||
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
|
||||
DeptDataPermissionRespDTO getDeptDataPermissionWithRoleCodes(Long userId, String roleCodes);
|
||||
|
||||
/**
|
||||
* 获得用户的数据权限级别
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.zt.plat.module.system.service.permission;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -12,6 +13,7 @@ import com.zt.plat.framework.common.biz.system.permission.dto.DeptDataPermission
|
||||
import com.zt.plat.framework.common.enums.CommonStatusEnum;
|
||||
import com.zt.plat.framework.common.util.collection.CollectionUtils;
|
||||
import com.zt.plat.framework.datapermission.core.annotation.DataPermission;
|
||||
import com.zt.plat.framework.tenant.core.context.DeptContextHolder;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.permission.RoleMenuDO;
|
||||
@@ -347,6 +349,12 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
// 获得用户的角色
|
||||
List<RoleDO> roles = getEnableUserRoleListByUserIdFromCache(userId);
|
||||
|
||||
//使用上下文角色编码过滤
|
||||
List<String> contextRoleCodes = DeptContextHolder.getRoleCodeList();
|
||||
if(!CollectionUtil.isEmpty(contextRoleCodes)){
|
||||
roles = roles.stream().filter(role -> contextRoleCodes.contains(role.getCode())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询
|
||||
Supplier<Set<Long>> userDeptIds = Suppliers.memoize(() -> {
|
||||
List<UserDeptDO> validUserDeptListByUserId = userDeptService.getValidUserDeptListByUserIds(singleton(userId));
|
||||
@@ -414,6 +422,26 @@ public class PermissionServiceImpl implements PermissionService {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeptDataPermissionRespDTO getDeptDataPermissionWithRoleCodes(Long userId, String roleCodes) {
|
||||
// 获得用户的角色
|
||||
List<RoleDO> roles = getEnableUserRoleListByUserIdFromCache(userId);
|
||||
if(ObjectUtil.isEmpty(roleCodes))
|
||||
return getDeptDataPermission(userId);
|
||||
List<String> roleCodesList = Arrays.asList(roleCodes.split(","));
|
||||
if(CollectionUtil.isEmpty(roles))
|
||||
return getDeptDataPermission(userId);
|
||||
DeptContextHolder.setRoleCodeList(roleCodesList);
|
||||
try{
|
||||
return getDeptDataPermission(userId);
|
||||
}catch (Exception e){
|
||||
log.error("getDeptDataPermission-- error ", e);
|
||||
}finally {
|
||||
DeptContextHolder.clearRoleCodeList();
|
||||
}
|
||||
return getDeptDataPermission(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataPermission(enable = false)
|
||||
@TenantIgnore
|
||||
|
||||
@@ -43,11 +43,11 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-template-server</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>com.zt.plat</groupId>-->
|
||||
<!-- <artifactId>zt-module-template-server</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- 会员中心。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
|
||||
@@ -62,7 +62,8 @@ spring:
|
||||
host: 172.16.46.63 # 地址
|
||||
port: 30379 # 端口
|
||||
database: 0 # 数据库索引
|
||||
# password: 123456 # 密码,建议生产环境开启
|
||||
password: P@ssword25
|
||||
username: zt-redis
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
@@ -76,7 +77,7 @@ xxl:
|
||||
|
||||
# rocketmq 配置项,对应 RocketMQProperties 配置类
|
||||
rocketmq:
|
||||
name-server: 127.0.0.1:9876 # RocketMQ Namesrv
|
||||
name-server: 172.16.46.63:30876 # RocketMQ Namesrv
|
||||
|
||||
spring:
|
||||
# RabbitMQ 配置项,对应 RabbitProperties 配置类
|
||||
|
||||
Reference in New Issue
Block a user