模版编制的相关实现
This commit is contained in:
@@ -52,6 +52,14 @@ public class TemplateInstanceDataController implements BusinessControllerMarker
|
||||
return success(templateInstanceDataService.createTemplateInstanceData(createReqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/create-batch")
|
||||
@Operation(summary = "批量创建实例字段值")
|
||||
@PreAuthorize("@ss.hasPermission('base:template-instance-data:create')")
|
||||
public CommonResult<List<TemplateInstanceDataRespVO>> createBatchTemplateInstanceData(@Valid @RequestBody List<TemplateInstanceDataSaveReqVO> createReqVOS) {
|
||||
return success(templateInstanceDataService.createBatchTemplateInstanceData(createReqVOS));
|
||||
}
|
||||
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新实例字段值")
|
||||
@PreAuthorize("@ss.hasPermission('base:template-instance-data:update')")
|
||||
|
||||
@@ -51,6 +51,13 @@ public class TemplateInstanceItemController implements BusinessControllerMarker
|
||||
return success(templateInstanceItemService.createTemplateInstanceItem(createReqVO));
|
||||
}
|
||||
|
||||
@PostMapping("/create-batch")
|
||||
@Operation(summary = "批量创建实例条款值")
|
||||
@PreAuthorize("@ss.hasPermission('base:template-instance-item:create')")
|
||||
public CommonResult<List<TemplateInstanceItemRespVO>> createBatchTemplateInstanceItem(@Valid @RequestBody List<TemplateInstanceItemSaveReqVO> createReqVOS) {
|
||||
return success(templateInstanceItemService.createBatchTemplateInstanceItem(createReqVOS));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新实例条款值")
|
||||
@PreAuthorize("@ss.hasPermission('base:template-instance-item:update')")
|
||||
|
||||
@@ -59,4 +59,10 @@ public class TmplTpFldController {
|
||||
PageResult<TmplTpFldDO> pageResult = tmplTpFldService.tmplTpFldPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, TmplFldRespVO.class));
|
||||
}
|
||||
@GetMapping("/getByClass")
|
||||
@Operation(summary = "获得类固定模板字段列表")
|
||||
@PreAuthorize("@ss.hasPermission('bse:tmpl-tp-fld:list')")
|
||||
public CommonResult<List<Map<String, Object>>> getTmplTpListByClass(String clazz) {
|
||||
return success(tmplTpFldService.getTmplTpListByClass(clazz));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class TemplateInstanceSaveReqVO {
|
||||
private String fileTp;
|
||||
|
||||
@Schema(description = "版本号;如v1.0", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "版本号;如v1.0不能为空")
|
||||
//@NotEmpty(message = "版本号;如v1.0不能为空")
|
||||
private String ver;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@@ -49,6 +49,6 @@ public class TemplateInstanceSaveReqVO {
|
||||
|
||||
@Schema(description = "使用部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@NotEmpty(message = "使用部门编号不能为空")
|
||||
private List<Long> deptIds;
|
||||
private List<String> deptIds;
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class TmplTpFldSaveReqVO {
|
||||
@Schema(description = "字段数据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "string")
|
||||
private String datTp;
|
||||
@Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码")
|
||||
private JSONObject fldDoc;
|
||||
private String fldDoc;
|
||||
@Schema(description = "字段备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码")
|
||||
private String rmk;
|
||||
@Schema(description = "是否必填", requiredMode = Schema.RequiredMode.REQUIRED, example = "Y or N")
|
||||
|
||||
@@ -27,7 +27,7 @@ public class DepartmentInstanceRelativityDO extends BusinessBaseDO {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.INPUT)
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
/**
|
||||
* 部门主键
|
||||
|
||||
@@ -27,7 +27,7 @@ public class TemplateInstanceItemDO extends BusinessBaseDO {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.INPUT)
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
/**
|
||||
* 关联实例主键
|
||||
|
||||
@@ -12,8 +12,8 @@ import java.time.LocalDateTime;
|
||||
*
|
||||
* @author 后台管理
|
||||
*/
|
||||
@TableName("BIZ_TMPL_TP_FLD")
|
||||
@KeySequence("BIZ_TMPL_TP_FLD_SEQ")
|
||||
@TableName("BSE_TMPL_TP_FLD")
|
||||
@KeySequence("BSE_TMPL_TP_FLD_SEQ")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@@ -68,4 +68,11 @@ public class TmplTpFldDO extends BusinessBaseDO { // 继承业务基类,自动
|
||||
*/
|
||||
@TableField("IS_MUST")
|
||||
private String isMust;
|
||||
|
||||
/**
|
||||
* 是否必填(对应表中 IS_MUST 字段,VARCHAR2(10) 类型,非空)
|
||||
* 建议值:Y(是)、N(否),需在业务层做枚举校验
|
||||
*/
|
||||
@TableField("ORGN_TP")
|
||||
private String orgnTp;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.module.base.controller.admin.templtp.vo.TemplateInstanceDataPageReqVO;
|
||||
import com.zt.plat.module.base.dal.dataobject.tmpltp.TemplateInstanceDataDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,5 +28,6 @@ public interface TemplateInstanceDataMapper extends BaseMapperX<TemplateInstance
|
||||
.betweenIfPresent(TemplateInstanceDataDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(TemplateInstanceDataDO::getId));
|
||||
}
|
||||
int deleteByTemplateInstanceId(@Param("templateInstanceId") Long templateInstanceId);
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.module.base.controller.admin.templtp.vo.TemplateInstanceItemPageReqVO;
|
||||
import com.zt.plat.module.base.dal.dataobject.tmpltp.TemplateInstanceItemDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
|
||||
/**
|
||||
@@ -28,4 +29,5 @@ public interface TemplateInstanceItemMapper extends BaseMapperX<TemplateInstance
|
||||
.orderByDesc(TemplateInstanceItemDO::getId));
|
||||
}
|
||||
|
||||
int deleteByTemplateInstanceId(@Param("templateInstanceId") Long templateInstanceId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.zt.plat.module.base.framework.util.config;
|
||||
|
||||
|
||||
import com.zt.plat.module.base.util.ClassInfoScanner;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class UtilConfig {
|
||||
|
||||
// 固定的包路径,直接写死在代码中
|
||||
private static final String BASE_PACKAGES = "com.zt.plat.module.base.controller.admin";
|
||||
|
||||
/**
|
||||
* 当Spring容器初始化该配置类后,自动执行初始化操作
|
||||
*/
|
||||
@PostConstruct
|
||||
public void initClassInfoScanner() {
|
||||
try {
|
||||
// 使用固定的包路径初始化类信息扫描工具
|
||||
ClassInfoScanner.init(BASE_PACKAGES);
|
||||
log.info("ClassInfoScanner初始化成功,扫描包路径:【{}】" , BASE_PACKAGES);
|
||||
} catch (Exception e) {
|
||||
log.error("ClassInfoScanner初始化失败:{}", e.getMessage());
|
||||
//throw new RuntimeException("类信息扫描工具初始化失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,4 +80,6 @@ public interface TemplateInstanceDataService {
|
||||
*/
|
||||
boolean clearTemplateInstanceData(String instanceId,List<Long> valIds);
|
||||
|
||||
List<TemplateInstanceDataRespVO> createBatchTemplateInstanceData(List<TemplateInstanceDataSaveReqVO> createReqVOS);
|
||||
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class TemplateInstanceDataServiceImpl implements TemplateInstanceDataServ
|
||||
if (CollUtil.isEmpty(pageReqVOS)) {
|
||||
throw exception(PARAMS_IS_NULL_OR_ERR);
|
||||
}
|
||||
return templateInstanceDataMapper.insertBatch(pageReqVOS);
|
||||
return templateInstanceDataMapper.updateBatch(pageReqVOS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,5 +119,15 @@ public class TemplateInstanceDataServiceImpl implements TemplateInstanceDataServ
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemplateInstanceDataRespVO> createBatchTemplateInstanceData(List<TemplateInstanceDataSaveReqVO> createReqVOS) {
|
||||
if (CollUtil.isEmpty(createReqVOS)) {
|
||||
throw exception(PARAMS_IS_NULL_OR_ERR);
|
||||
}
|
||||
List<TemplateInstanceDataDO> templateInstanceDataDOList = BeanUtils.toBean(createReqVOS, TemplateInstanceDataDO.class);
|
||||
templateInstanceDataMapper.insertBatch(templateInstanceDataDOList);
|
||||
return BeanUtils.toBean(templateInstanceDataDOList, TemplateInstanceDataRespVO.class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ public interface TemplateInstanceItemService {
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 实例条款值分页
|
||||
*/
|
||||
PageResult<TemplateInstanceItemDO> getTemplateInstanceItemPage(TemplateInstanceItemPageReqVO pageReqVO);
|
||||
PageResult<TemplateInstanceItemDO> getTemplateInstanceItemPage(@Valid TemplateInstanceItemPageReqVO pageReqVO);
|
||||
|
||||
List<TemplateInstanceItemRespVO> createBatchTemplateInstanceItem(@Valid List<TemplateInstanceItemSaveReqVO> createReqVOS);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.*;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.PARAMS_IS_NULL_OR_ERR;
|
||||
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.TEMPLATE_INSTANCE_ITEM_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
@@ -84,4 +85,14 @@ public class TemplateInstanceItemServiceImpl implements TemplateInstanceItemServ
|
||||
return templateInstanceItemMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemplateInstanceItemRespVO> createBatchTemplateInstanceItem(List<TemplateInstanceItemSaveReqVO> createReqVOS) {
|
||||
if (CollUtil.isEmpty(createReqVOS)) {
|
||||
throw exception(PARAMS_IS_NULL_OR_ERR);
|
||||
}
|
||||
List<TemplateInstanceItemDO> templateInstanceItemDOList = BeanUtils.toBean(createReqVOS, TemplateInstanceItemDO.class);
|
||||
templateInstanceItemMapper.insertBatch(templateInstanceItemDOList);
|
||||
return BeanUtils.toBean(templateInstanceItemDOList, TemplateInstanceItemRespVO.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,15 +9,21 @@ import com.zt.plat.module.base.controller.admin.templtp.vo.TemplateInstanceSaveR
|
||||
import com.zt.plat.module.base.dal.dataobject.tmpltp.DepartmentInstanceRelativityDO;
|
||||
import com.zt.plat.module.base.dal.dataobject.tmpltp.TemplateInstanceDO;
|
||||
import com.zt.plat.module.base.dal.mysql.tmpltp.DepartmentInstanceRelativityMapper;
|
||||
import com.zt.plat.module.base.dal.mysql.tmpltp.TemplateInstanceDataMapper;
|
||||
import com.zt.plat.module.base.dal.mysql.tmpltp.TemplateInstanceItemMapper;
|
||||
import com.zt.plat.module.base.dal.mysql.tmpltp.TemplateInstanceMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.STATUS_OPERATION_FAIL;
|
||||
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.TEMPLATE_INSTANCE_NOT_EXISTS;
|
||||
|
||||
|
||||
@@ -34,8 +40,14 @@ public class TemplateInstanceServiceImpl implements TemplateInstanceService {
|
||||
private TemplateInstanceMapper templateInstanceMapper;
|
||||
@Resource
|
||||
private DepartmentInstanceRelativityMapper departmentInstanceRelativityMapper;
|
||||
@Resource
|
||||
private TemplateInstanceDataMapper templateInstanceDataMapper;
|
||||
@Resource
|
||||
private TemplateInstanceItemMapper templateInstanceItemMapper;
|
||||
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile("^(.*?)([0-9]+(?:\\.[0-9]+)*)(.*)$");
|
||||
@Override
|
||||
@Transactional
|
||||
public TemplateInstanceRespVO createTemplateInstance(TemplateInstanceSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
TemplateInstanceDO templateInstance = BeanUtils.toBean(createReqVO, TemplateInstanceDO.class);
|
||||
@@ -46,7 +58,7 @@ public class TemplateInstanceServiceImpl implements TemplateInstanceService {
|
||||
createReqVO.getDeptIds().forEach(deptId ->{
|
||||
DepartmentInstanceRelativityDO departmentInstanceRelativityDO = new DepartmentInstanceRelativityDO();
|
||||
departmentInstanceRelativityDO.setTemplateInstanceId(String.valueOf(templateInstance.getId()));
|
||||
departmentInstanceRelativityDO.setCompanyId(deptId);
|
||||
departmentInstanceRelativityDO.setCompanyDepartmentId(deptId);
|
||||
departmentInstanceRelativityDOS.add(departmentInstanceRelativityDO);
|
||||
});
|
||||
departmentInstanceRelativityMapper.insertBatch(departmentInstanceRelativityDOS);
|
||||
@@ -58,20 +70,33 @@ public class TemplateInstanceServiceImpl implements TemplateInstanceService {
|
||||
public void updateTemplateInstance(TemplateInstanceSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateTemplateInstanceExists(updateReqVO.getId());
|
||||
// TemplateInstanceDO templateInstanceDO = templateInstanceMapper.selectById(updateReqVO.getId());
|
||||
// TemplateInstanceDO templateInstanceDO = templateInstanceMapper.selectById(updateReqVO.getId());
|
||||
// //获取保存旧文件内容防止被更新
|
||||
// String originalContent = templateInstanceDO.getOriginalContent();
|
||||
// 更新
|
||||
TemplateInstanceDO templateInstanceDO = templateInstanceMapper.selectById(updateReqVO.getId());
|
||||
String sts = templateInstanceDO.getSts();
|
||||
if (!sts.equals("DRF")) {
|
||||
throw exception(STATUS_OPERATION_FAIL);
|
||||
}
|
||||
|
||||
TemplateInstanceDO updateObj = BeanUtils.toBean(updateReqVO, TemplateInstanceDO.class);
|
||||
updateObj.setOrigCntt(null); //重新赋值,防止原始文件被更改
|
||||
updateObj.setVer(incrementVersion(templateInstanceDO.getVer()));
|
||||
templateInstanceMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteTemplateInstance(Long id) {
|
||||
// 校验存在
|
||||
validateTemplateInstanceExists(id);
|
||||
// 删除
|
||||
//删除对应的字段和条款关系
|
||||
//1、删除合同的与字段的关系
|
||||
templateInstanceDataMapper.deleteByTemplateInstanceId(id);
|
||||
//2、删除条款与和他的关系
|
||||
templateInstanceDataMapper.deleteByTemplateInstanceId(id);
|
||||
templateInstanceMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@@ -106,4 +131,62 @@ public class TemplateInstanceServiceImpl implements TemplateInstanceService {
|
||||
return templateInstanceMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
private String incrementVersion(String currentVersion) {
|
||||
// 处理空值或空字符串
|
||||
if (currentVersion == null || currentVersion.trim().isEmpty()) {
|
||||
return "v1.0";
|
||||
}
|
||||
|
||||
String version = currentVersion.trim();
|
||||
Matcher matcher = VERSION_PATTERN.matcher(version);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
// 没有找到数字部分,返回默认版本
|
||||
return version + "1.0";
|
||||
}
|
||||
|
||||
String prefix = matcher.group(1); // 前缀部分(如 "v", "version-" 等)
|
||||
String numberPart = matcher.group(2); // 数字部分(如 "1.2.3")
|
||||
String suffix = matcher.group(3); // 后缀部分
|
||||
|
||||
// 分割数字部分
|
||||
String[] segments = numberPart.split("\\.");
|
||||
|
||||
// 从最后一段开始处理进位
|
||||
boolean carry = true; // 初始需要加1
|
||||
|
||||
for (int i = segments.length - 1; i >= 0 && carry; i--) {
|
||||
try {
|
||||
int currentNumber = Integer.parseInt(segments[i]);
|
||||
currentNumber++; // 加1
|
||||
|
||||
if (currentNumber >= 10) {
|
||||
// 需要进位
|
||||
segments[i] = "0";
|
||||
carry = true; // 继续向前进位
|
||||
} else {
|
||||
// 不需要进位
|
||||
segments[i] = String.valueOf(currentNumber);
|
||||
carry = false; // 停止进位
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// 理论上不会发生,因为正则已经保证了是数字
|
||||
segments[i] = "1";
|
||||
carry = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果最高位也需要进位,在前面添加一段
|
||||
if (carry) {
|
||||
String[] newSegments = new String[segments.length + 1];
|
||||
newSegments[0] = "1";
|
||||
System.arraycopy(segments, 0, newSegments, 1, segments.length);
|
||||
segments = newSegments;
|
||||
}
|
||||
|
||||
// 重新组合版本号
|
||||
String newNumberPart = String.join(".", segments);
|
||||
return prefix + newNumberPart + suffix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,11 +10,13 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface TmplTpFldService extends IService<TmplTpFldDO> {
|
||||
TmplFldRespVO createTmplFld(@Valid TmplTpFldSaveReqVO tmplTpFldSaveReqVO);
|
||||
void updateTmplFld(@Valid TmplTpFldSaveReqVO tmplTpFldSaveReqVO);
|
||||
PageResult<TmplTpFldDO> tmplTpFldPage(@Valid TmplFldPageReqVO pageReqVO);
|
||||
PageResult<TmplTpFldDO> tmplTpFldPage(TmplFldPageReqVO pageReqVO);
|
||||
void deleteTmplTpByIds(List< Long> ids);
|
||||
List<Map<String, Object>>getTmplTpListByClass(String clazz);
|
||||
|
||||
}
|
||||
|
||||
@@ -13,14 +13,19 @@ import com.zt.plat.module.base.dal.mysql.tmpltp.TmplTpFldMapper;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.zt.plat.module.base.util.ClassInfoScanner;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.TMPL_FLD_CODE_EXISTS;
|
||||
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.TMPL_FLD_NOT_EXISTS;
|
||||
import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.*;
|
||||
|
||||
|
||||
@Service
|
||||
@@ -73,4 +78,9 @@ public class TmplTpFldServiceImpl extends ServiceImpl<TmplTpFldMapper, TmplTpFld
|
||||
validateTmplFldExists(ids);
|
||||
baseMapper.deleteByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getTmplTpListByClass(String clazz) {
|
||||
return ClassInfoScanner.getClassFieldInfo(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
package com.zt.plat.module.base.util;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* 类信息扫描工具类,用于通过简单类名获取类字段及Schema注解信息
|
||||
* 增强版:支持通配符包路径扫描
|
||||
*/
|
||||
@Slf4j
|
||||
public class ClassInfoScanner {
|
||||
|
||||
// 缓存简单类名到Class的映射,提高性能
|
||||
private static final Map<String, Class<?>> CLASS_CACHE = new HashMap<>();
|
||||
// 已初始化标识
|
||||
private static boolean initialized = false;
|
||||
|
||||
/**
|
||||
* 初始化扫描指定包路径下的所有类
|
||||
* @param basePackages 基础包路径,支持逗号分隔多个包,支持*和**通配符
|
||||
*/
|
||||
public static synchronized void init(String basePackages) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (basePackages == null || basePackages.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("基础包路径不能为空");
|
||||
}
|
||||
|
||||
String[] packages = basePackages.split("[,;\\s]+");
|
||||
for (String pkg : packages) {
|
||||
String trimmedPkg = pkg.trim();
|
||||
if (trimmedPkg.contains("**") || trimmedPkg.contains("*")) {
|
||||
// 处理通配符包路径
|
||||
scanPackageWithWildcard(trimmedPkg);
|
||||
log.info("已扫描通配符包路径:{}", trimmedPkg);
|
||||
} else {
|
||||
// 处理普通包路径
|
||||
scanPackage(trimmedPkg);
|
||||
log.info("已扫描普通包路径:{}", trimmedPkg);
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理包含通配符的包路径扫描
|
||||
*/
|
||||
private static void scanPackageWithWildcard(String wildcardPackage) {
|
||||
try {
|
||||
// 提取基础包路径(通配符之前的部分)
|
||||
String basePackage = extractBasePackage(wildcardPackage);
|
||||
String pattern = wildcardPackage.substring(basePackage.length());
|
||||
|
||||
// 扫描基础包路径
|
||||
String packageDirName = basePackage.replace('.', '/');
|
||||
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
|
||||
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
String protocol = url.getProtocol();
|
||||
|
||||
if ("file".equals(protocol)) {
|
||||
String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8);
|
||||
findClassesWithPattern(basePackage, filePath, pattern);
|
||||
} else if ("jar".equals(protocol)) {
|
||||
JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
processJarEntriesWithPattern(basePackage, entries, pattern);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("扫描通配符包时发生错误: " + wildcardPackage, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取基础包路径(通配符之前的部分)
|
||||
*/
|
||||
private static String extractBasePackage(String wildcardPackage) {
|
||||
int wildcardIndex = wildcardPackage.indexOf('*');
|
||||
if (wildcardIndex == -1) {
|
||||
return wildcardPackage;
|
||||
}
|
||||
|
||||
String beforeWildcard = wildcardPackage.substring(0, wildcardIndex);
|
||||
int lastDotIndex = beforeWildcard.lastIndexOf('.');
|
||||
if (lastDotIndex == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return beforeWildcard.substring(0, lastDotIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在文件系统中按模式查找类
|
||||
*/
|
||||
private static void findClassesWithPattern(String basePackage, String basePath, String pattern) {
|
||||
File baseDir = new File(basePath);
|
||||
if (!baseDir.exists() || !baseDir.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
findClassesRecursive(baseDir, basePackage, pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归查找匹配模式的类
|
||||
*/
|
||||
private static void findClassesRecursive(File dir, String packageName, String pattern) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
// 递归处理子目录
|
||||
String subPackageName = packageName + "." + file.getName();
|
||||
findClassesRecursive(file, subPackageName, pattern);
|
||||
} else if (file.getName().endsWith(".class")) {
|
||||
// 检查是否匹配模式
|
||||
String className = file.getName().substring(0, file.getName().length() - 6);
|
||||
String fullClassName = packageName + "." + className;
|
||||
|
||||
if (matchesPattern(fullClassName, pattern)) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(fullClassName);
|
||||
CLASS_CACHE.put(clazz.getSimpleName(), clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// 忽略无法加载的类
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在JAR包中按模式查找类
|
||||
*/
|
||||
private static void processJarEntriesWithPattern(String basePackage, Enumeration<JarEntry> entries, String pattern) {
|
||||
String basePackagePath = basePackage.replace('.', '/');
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String entryName = entry.getName();
|
||||
|
||||
if (entryName.charAt(0) == '/') {
|
||||
entryName = entryName.substring(1);
|
||||
}
|
||||
|
||||
if (entryName.startsWith(basePackagePath) && !entry.isDirectory() && entryName.endsWith(".class")) {
|
||||
String className = entryName.substring(0, entryName.length() - 6).replace('/', '.');
|
||||
|
||||
if (matchesPattern(className, pattern)) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(className);
|
||||
CLASS_CACHE.put(clazz.getSimpleName(), clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// 忽略无法加载的类
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查类名是否匹配通配符模式
|
||||
*/
|
||||
private static boolean matchesPattern(String className, String pattern) {
|
||||
if (pattern.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 简单的通配符匹配实现
|
||||
if (pattern.startsWith(".")) {
|
||||
pattern = pattern.substring(1);
|
||||
}
|
||||
|
||||
// 处理 **.vo 模式
|
||||
if (pattern.equals("**.vo")) {
|
||||
return className.endsWith(".vo") ||
|
||||
(className.contains(".") && className.substring(className.lastIndexOf('.') + 1).toLowerCase().contains("vo"));
|
||||
}
|
||||
|
||||
// 处理其他模式
|
||||
String[] patternParts = pattern.split("\\*\\*");
|
||||
if (patternParts.length == 2) {
|
||||
String prefix = patternParts[0];
|
||||
String suffix = patternParts[1];
|
||||
return className.contains(prefix) && className.endsWith(suffix);
|
||||
}
|
||||
|
||||
return className.contains(pattern.replace("*", ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过简单类名获取类的字段及Schema注解信息
|
||||
* @param simpleClassName 简单类名
|
||||
* @return 包含字段名和label的列表
|
||||
*/
|
||||
public static List<Map<String, Object>> getClassFieldInfo(String simpleClassName) {
|
||||
if (!initialized) {
|
||||
throw new IllegalStateException("工具类未初始化,请先调用init方法");
|
||||
}
|
||||
|
||||
if (simpleClassName == null || !simpleClassName.endsWith("VO")) {
|
||||
throw new IllegalArgumentException("参数为空或格式错误");
|
||||
}
|
||||
|
||||
Class<?> targetClass = CLASS_CACHE.get(simpleClassName);
|
||||
if (targetClass == null) {
|
||||
throw new RuntimeException("未找到类: " + simpleClassName);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
Field[] fields = targetClass.getDeclaredFields();
|
||||
|
||||
for (Field field : fields) {
|
||||
if (field.isAnnotationPresent(Schema.class)) {
|
||||
Schema schema = field.getAnnotation(Schema.class);
|
||||
Map<String, Object> fieldMap = new HashMap<>();
|
||||
fieldMap.put("fieldName", field.getName());
|
||||
fieldMap.put("label", schema.description().isEmpty() ?null:schema.description().split(";")[0]);
|
||||
fieldMap.put("required", schema.requiredMode() == Schema.RequiredMode.REQUIRED);
|
||||
fieldMap.put("example", schema.example());
|
||||
fieldMap.put("orgnType", "class");
|
||||
resultList.add(fieldMap);
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描指定包下的所有类(原有方法保持不变)
|
||||
*/
|
||||
private static void scanPackage(String basePackage) {
|
||||
try {
|
||||
String packageDirName = basePackage.replace('.', '/');
|
||||
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
|
||||
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
String protocol = url.getProtocol();
|
||||
|
||||
if ("file".equals(protocol)) {
|
||||
String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8.name());
|
||||
findAndAddClassesInPackageByFile(basePackage, filePath);
|
||||
} else if ("jar".equals(protocol)) {
|
||||
JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
processJarEntries(basePackage, entries);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("扫描包时发生错误: " + basePackage, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件系统中的类文件
|
||||
*/
|
||||
private static void findAndAddClassesInPackageByFile(String packageName, String packagePath) {
|
||||
File dir = new File(packagePath);
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File[] dirFiles = dir.listFiles(file ->
|
||||
(file.isDirectory()) || (file.getName().endsWith(".class"))
|
||||
);
|
||||
|
||||
if (dirFiles == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : dirFiles) {
|
||||
if (file.isDirectory()) {
|
||||
findAndAddClassesInPackageByFile(packageName + "." + file.getName(),
|
||||
file.getAbsolutePath());
|
||||
} else {
|
||||
String className = file.getName().substring(0, file.getName().length() - 6);
|
||||
try {
|
||||
Class<?> clazz = Class.forName(packageName + '.' + className);
|
||||
CLASS_CACHE.put(clazz.getSimpleName(), clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// 忽略无法加载的类
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理JAR包中的类
|
||||
*/
|
||||
private static void processJarEntries(String basePackage, Enumeration<JarEntry> entries) {
|
||||
String packageDirName = basePackage.replace('.', '/');
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
|
||||
if (name.charAt(0) == '/') {
|
||||
name = name.substring(1);
|
||||
}
|
||||
|
||||
if (name.startsWith(packageDirName) && !entry.isDirectory() && name.endsWith(".class")) {
|
||||
String className = name.substring(0, name.length() - 6).replace('/', '.');
|
||||
try {
|
||||
Class<?> clazz = Class.forName(className);
|
||||
CLASS_CACHE.put(clazz.getSimpleName(), clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// 忽略无法加载的类
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存,重新初始化时使用
|
||||
*/
|
||||
public static synchronized void clearCache() {
|
||||
CLASS_CACHE.clear();
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的类数量(用于调试)
|
||||
*/
|
||||
public static int getCachedClassCount() {
|
||||
return CLASS_CACHE.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有缓存的类名(用于调试)
|
||||
*/
|
||||
public static Set<String> getCachedClassNames() {
|
||||
return CLASS_CACHE.keySet();
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,8 @@
|
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||
-->
|
||||
|
||||
<update id="deleteByTemplateInstanceId" >
|
||||
update BSE_TMPL_INSC_DAT set deleted = 1
|
||||
WHERE INSC_ID = #{templateInstanceId}
|
||||
</update>
|
||||
</mapper>
|
||||
|
||||
@@ -9,4 +9,12 @@
|
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||
-->
|
||||
|
||||
<!-- <delete id="deleteByTemplateInstanceId">-->
|
||||
<!-- DELETE FROM bse_tmpl_insc_item-->
|
||||
<!-- WHERE INSC_ID = #{templateInstanceId}-->
|
||||
<!-- </delete>-->
|
||||
<update id="deleteByTemplateInstanceId" >
|
||||
update BSE_TMPL_INSC_ITM set deleted = 1
|
||||
WHERE INSC_ID = #{templateInstanceId}
|
||||
</update>
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user