Merge branch 'dev' into 'test'

重写手动针对用户以及组织的单条同步逻辑

See merge request jygk/dsc!29
This commit is contained in:
朝锦 杨
2026-02-02 08:36:22 +00:00
8 changed files with 580 additions and 19 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@ import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import java.util.List; import java.util.List;
@@ -45,6 +46,7 @@ public class ZtDataPermissionAutoConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean
public MenuDataPermissionHandler menuDataPermissionHandler(MybatisPlusInterceptor interceptor) { public MenuDataPermissionHandler menuDataPermissionHandler(MybatisPlusInterceptor interceptor) {
// 创建菜单数据权限处理器 // 创建菜单数据权限处理器
MenuDataPermissionHandler handler = new MenuDataPermissionHandler(); MenuDataPermissionHandler handler = new MenuDataPermissionHandler();

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionIntercepto
import com.zt.plat.framework.datapermission.core.menudatapermission.handler.MenuDataPermissionHandler; import com.zt.plat.framework.datapermission.core.menudatapermission.handler.MenuDataPermissionHandler;
import com.zt.plat.framework.mybatis.core.util.MyBatisUtils; import com.zt.plat.framework.mybatis.core.util.MyBatisUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -20,6 +21,7 @@ public class MenuDataPermissionConfiguration {
@Bean @Bean
@ConditionalOnBean(MybatisPlusInterceptor.class) @ConditionalOnBean(MybatisPlusInterceptor.class)
@ConditionalOnMissingBean
public MenuDataPermissionHandler menuDataPermissionHandler(MybatisPlusInterceptor interceptor) { public MenuDataPermissionHandler menuDataPermissionHandler(MybatisPlusInterceptor interceptor) {
// 创建菜单数据权限处理器 // 创建菜单数据权限处理器
MenuDataPermissionHandler handler = new MenuDataPermissionHandler(); MenuDataPermissionHandler handler = new MenuDataPermissionHandler();

View File

@@ -96,7 +96,6 @@ public class DeptDataPermissionRule implements DataPermissionRule {
/** /**
* 基于用户的表字段配置 * 基于用户的表字段配置
* 一般情况下,每个表的部门编号字段是 dept_id通过该配置自定义。 * 一般情况下,每个表的部门编号字段是 dept_id通过该配置自定义。
* key表名
* value字段名 * value字段名
*/ */
private final Map<String, String> userColumns = new HashMap<>(); private final Map<String, String> userColumns = new HashMap<>();
@@ -262,7 +261,11 @@ public class DeptDataPermissionRule implements DataPermissionRule {
if (Boolean.FALSE.equals(self)) { if (Boolean.FALSE.equals(self)) {
return null; return null;
} }
String columnName = userColumns.get(tableName); String userColumnsKey = tableName;
if (StrUtil.isNotBlank(workCode)) {
userColumnsKey = userColumnsKey + "_work_code";
}
String columnName = userColumns.get(userColumnsKey);
if (StrUtil.isEmpty(columnName)) { if (StrUtil.isEmpty(columnName)) {
return null; return null;
} }

View File

@@ -77,7 +77,12 @@ public class DbSqlSessionFactory implements SessionFactory {
// 当前系统适配 dm,如果存在 schema 为空的情况,从 connection 获取 // 当前系统适配 dm,如果存在 schema 为空的情况,从 connection 获取
try { try {
if (getDatabaseSchema() == null || getDatabaseSchema().length() == 0){ if (getDatabaseSchema() == null || getDatabaseSchema().length() == 0){
setDatabaseSchema(dbSqlSession.getSqlSession().getConnection().getSchema()); String schemaFromUrl = extractSchemaFromJdbcUrl(dbSqlSession.getSqlSession().getConnection());
if (schemaFromUrl != null && schemaFromUrl.length() > 0) {
setDatabaseSchema(schemaFromUrl);
} else {
setDatabaseSchema(dbSqlSession.getSqlSession().getConnection().getSchema());
}
} }
dbSqlSession.getSqlSession().getConnection().getSchema(); dbSqlSession.getSqlSession().getConnection().getSchema();
} catch (SQLException e) { } catch (SQLException e) {
@@ -351,4 +356,39 @@ public class DbSqlSessionFactory implements SessionFactory {
public void setUsePrefixId(boolean usePrefixId) { public void setUsePrefixId(boolean usePrefixId) {
this.usePrefixId = usePrefixId; this.usePrefixId = usePrefixId;
} }
private String extractSchemaFromJdbcUrl(java.sql.Connection connection) {
if (connection == null) {
return null;
}
try {
String url = connection.getMetaData().getURL();
if (url == null || url.isEmpty()) {
return null;
}
int queryIndex = url.indexOf('?');
if (queryIndex < 0 || queryIndex == url.length() - 1) {
return null;
}
String query = url.substring(queryIndex + 1);
String[] parts = query.split("[&;]");
for (String part : parts) {
int eqIndex = part.indexOf('=');
if (eqIndex <= 0 || eqIndex == part.length() - 1) {
continue;
}
String key = part.substring(0, eqIndex).trim().toLowerCase(Locale.ROOT);
if ("schema".equals(key) || "currentschema".equals(key) || "current_schema".equals(key)) {
String value = part.substring(eqIndex + 1).trim();
if ((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'"))) {
value = value.substring(1, value.length() - 1);
}
return value;
}
}
} catch (SQLException ignored) {
return null;
}
return null;
}
} }

View File

@@ -31,6 +31,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import static com.zt.plat.framework.common.pojo.CommonResult.error;
import static com.zt.plat.framework.common.pojo.CommonResult.success; import static com.zt.plat.framework.common.pojo.CommonResult.success;
import static com.zt.plat.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static com.zt.plat.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static com.zt.plat.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; import static com.zt.plat.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
@@ -52,13 +53,13 @@ public class FileController {
private FileService fileService; private FileService fileService;
@GetMapping("/get") @GetMapping("/get")
@Operation(summary = "获取文件预览地址", description = "根据 fileId 返回文件预览 urlkkfile支持加密文件预览需要传递验证码 code加密文件预览地址默认5分钟内有效可在配置文件中添加zt.file.preview-expire-seconds配置") @Operation(summary = "获取文件预览地址", description = "根据 fileId 返回文件预览 urlkkfile支持加密文件预览加密文件预览地址默认5分钟内有效可在配置文件中添加zt.file.preview-expire-seconds配置有效时间")
public CommonResult<FileRespVO> getPreviewUrl(@RequestParam("fileId") Long fileId, public CommonResult<FileRespVO> getPreviewUrl(@RequestParam("fileId") Long fileId,
@RequestParam(value = "code", required = false) String code, @RequestParam(value = "code", required = false) String code,
HttpServletRequest request) throws Exception { HttpServletRequest request) throws Exception {
FileDO fileDO = fileService.getActiveFileById(fileId); FileDO fileDO = fileService.getActiveFileById(fileId);
if (fileDO == null) { if (fileDO == null) {
return CommonResult.error(HttpStatus.NOT_FOUND.value(), "文件不存在"); return error(HttpStatus.NOT_FOUND.value(), "文件不存在");
} }
// 统计下载次数 // 统计下载次数
@@ -68,26 +69,24 @@ public class FileController {
FileRespVO fileRespVO = BeanUtils.toBean(fileDO, FileRespVO.class); FileRespVO fileRespVO = BeanUtils.toBean(fileDO, FileRespVO.class);
// 加密文件:塞入“临时解密预览 URL” // 加密文件:塞入“临时解密预览 URL”
if (Boolean.TRUE.equals(fileRespVO.getIsEncrypted())) { // FileDO 通过 aesIv 判断加密 if (Boolean.TRUE.equals(fileRespVO.getIsEncrypted()) // FileDO 通过 aesIv 判断加密
&& cn.hutool.core.util.StrUtil.isNotBlank(code)) { // 预览文件会调用两次该接口只有code不为空时候才塞url
if (cn.hutool.core.util.StrUtil.isBlank(code)) { /*if (cn.hutool.core.util.StrUtil.isBlank(code)) {
return CommonResult.error(HttpStatus.BAD_REQUEST.value(), "加密文件预览需要验证码 code"); return CommonResult.error(HttpStatus.BAD_REQUEST.value(), "加密文件预览需要验证码 code");
} }*/
// 验证通过:发放给 kkfile 用的短期 tokenkkfile 不带登录态) // 验证通过:发放给 kkfile 用的短期 tokenkkfile 不带登录态)
Long userId = getLoginUserId(); Long userId = getLoginUserId();
boolean flag = fileService.verifyCode(fileId, userId, code); boolean flag = fileService.verifyCode(fileId, userId, code);
if(!flag){ if(!flag){
return CommonResult.customize(null, HttpStatus.INTERNAL_SERVER_ERROR.value(), "验证码错误"); return error(HttpStatus.BAD_REQUEST.value(), "验证码错误");
} }
String token = fileService.generatePreviewToken(fileId, userId); String token = fileService.generatePreviewToken(fileId, userId);
String baseUrl = buildPublicBaseUrl(request); // 见下方函数 String baseUrl = buildPublicBaseUrl(request); // 见下方函数
String fullfilename = java.net.URLEncoder String fullfilename = java.net.URLEncoder
.encode(fileDO.getName(), java.nio.charset.StandardCharsets.UTF_8) .encode(fileDO.getName(), java.nio.charset.StandardCharsets.UTF_8)
.replace("+", "%20"); .replace("+", "%20");
String decryptUrl = baseUrl + "/admin-api/infra/file/preview-decrypt" String decryptUrl = baseUrl + "/admin-api/infra/file/preview-decrypt"
+ "?fileId=" + fileId + "?fileId=" + fileId
+ "&token=" + token + "&token=" + token
@@ -215,14 +214,14 @@ public class FileController {
try { try {
sendTypeEnum = VerifyCodeSendType.valueOf(sendType.trim().toUpperCase()); sendTypeEnum = VerifyCodeSendType.valueOf(sendType.trim().toUpperCase());
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {
return CommonResult.error(HttpStatus.BAD_REQUEST.value(), return error(HttpStatus.BAD_REQUEST.value(),
"sendType 参数不合法可选SMS / E_OFFICE"); "sendType 参数不合法可选SMS / E_OFFICE");
} }
} }
FileDO activeFileById = fileService.getActiveFileById(fileId); FileDO activeFileById = fileService.getActiveFileById(fileId);
if (activeFileById == null) { if (activeFileById == null) {
return CommonResult.error(HttpStatus.NOT_FOUND.value(), "文件不存在"); return error(HttpStatus.NOT_FOUND.value(), "文件不存在");
} }
FileRespVO fileRespVO = BeanUtils.toBean(activeFileById, FileRespVO.class); FileRespVO fileRespVO = BeanUtils.toBean(activeFileById, FileRespVO.class);

View File

@@ -24,6 +24,7 @@ public class DataPermissionConfiguration {
rule.addDeptColumn(DeptDO.class, "id"); rule.addDeptColumn(DeptDO.class, "id");
// user // user
rule.addUserColumn(AdminUserDO.class, "id"); rule.addUserColumn(AdminUserDO.class, "id");
rule.addUserColumn("system_users_work_code", "workcode");
}; };
} }

View File

@@ -47,14 +47,14 @@ spring:
primary: master primary: master
datasource: datasource:
master: master:
url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO url: jdbc:dm://172.17.11.98:20870?schema=JYGK_TEST
username: SYSDBA username: SYSDBA
password: pgbsci6ddJ6Sqj@e password: P@ssword25
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度 lazy: true # 开启懒加载,保证启动速度
url: jdbc:dm://172.16.46.247:1050?schema=RUOYI-VUE-PRO url: jdbc:dm://172.17.11.98:20870?schema=JYGK_TEST
username: SYSDBA username: SYSDBA
password: pgbsci6ddJ6Sqj@e password: P@ssword25
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data: data: