1. 代码生成器在生成的时候可以手动选择是否是业务数据类代码(会自动继承基础业务类,合并字段,实现业务接口标记,这个标记会将右上角选择公司作为当前业务数据数据权限进行过滤,办理业务时,如果操作人归属同一个公司的多个部门,会前置校验后弹窗选择归属部门后才能正常办理业务)

2. 文件上传的地方做了一个改动,如果上传文件的 hash 和已存在的附件相同,不会重复上传,会复用相同hash 的附件(要加一个字段,加字段脚本提供两个版本的 patch 脚本 mysql:根目录/sql/mysql/patch.sql dm:根目录/sql/dm/patch.sql  )
This commit is contained in:
chenbowen
2025-07-16 17:19:08 +08:00
parent eaea76e955
commit 619c12bbba
20 changed files with 236 additions and 51 deletions

View File

@@ -34,7 +34,6 @@ import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserNickname;
import static cn.iocoder.yudao.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
@@ -125,21 +124,29 @@ public class CodegenController {
@Operation(summary = "预览生成代码")
@GetMapping("/preview")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@Parameters({
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024"),
@Parameter(name = "isBusiness", description = "是否业务基类", example = "false")
})
@PreAuthorize("@ss.hasPermission('infra:codegen:preview')")
public CommonResult<List<CodegenPreviewRespVO>> previewCodegen(@RequestParam("tableId") Long tableId) {
Map<String, String> codes = codegenService.generationCodes(tableId);
public CommonResult<List<CodegenPreviewRespVO>> previewCodegen(@RequestParam("tableId") Long tableId,
@RequestParam(value = "isBusiness", required = false, defaultValue = "false") Boolean isBusiness) {
Map<String, String> codes = codegenService.generationCodes(tableId, isBusiness);
return success(CodegenConvert.INSTANCE.convert(codes));
}
@Operation(summary = "下载生成代码")
@GetMapping("/download")
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@Parameters({
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024"),
@Parameter(name = "isBusiness", description = "是否业务基类", example = "false")
})
@PreAuthorize("@ss.hasPermission('infra:codegen:download')")
public void downloadCodegen(@RequestParam("tableId") Long tableId,
@RequestParam(value = "isBusiness", required = false, defaultValue = "false") Boolean isBusiness,
HttpServletResponse response) throws IOException {
// 生成代码
Map<String, String> codes = codegenService.generationCodes(tableId);
// 生成代码,传递 isBusiness
Map<String, String> codes = codegenService.generationCodes(tableId, isBusiness);
// 构建 zip 包
String[] paths = codes.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = codes.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);

View File

@@ -26,7 +26,7 @@ import lombok.*;
public class FileDO extends BaseDO {
/**
* 编号,数据库自增
* 编号
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
@@ -57,4 +57,9 @@ public class FileDO extends BaseDO {
*/
private Integer size;
/**
* 文件哈希值SHA-256
*/
private String hash;
}

View File

@@ -23,4 +23,14 @@ public interface FileMapper extends BaseMapperX<FileDO> {
.orderByDesc(FileDO::getId));
}
/**
* 根据哈希值查询文件
* @param hash 文件哈希值
* @return 文件DO若不存在返回null
*/
default FileDO selectByHash(String hash) {
return selectOne(new LambdaQueryWrapperX<FileDO>()
.eq(FileDO::getHash, hash));
}
}

View File

@@ -86,6 +86,17 @@ public interface CodegenService {
* @param tableId 表编号
* @return 生成结果。key 为文件路径value 为对应的代码内容
*/
/**
* 执行指定表的代码生成,支持业务基类继承
* @param tableId 表编号
* @param isBusiness 是否业务基类
* @return 生成结果
*/
Map<String, String> generationCodes(Long tableId, Boolean isBusiness);
/**
* 兼容原有接口,默认 isBusiness=false
*/
Map<String, String> generationCodes(Long tableId);
/**

View File

@@ -243,7 +243,10 @@ public class CodegenServiceImpl implements CodegenService {
}
@Override
public Map<String, String> generationCodes(Long tableId) {
/**
* 执行指定表的代码生成,支持业务基类继承
*/
public Map<String, String> generationCodes(Long tableId, Boolean isBusiness) {
// 校验是否已经存在
CodegenTableDO table = codegenTableMapper.selectById(tableId);
if (table == null) {
@@ -275,8 +278,16 @@ public class CodegenServiceImpl implements CodegenService {
}
}
// 执行生成
return codegenEngine.execute(table, columns, subTables, subColumnsList);
// 执行生成,传递 isBusiness
return codegenEngine.execute(table, columns, subTables, subColumnsList, isBusiness != null && isBusiness);
}
/**
* 兼容原有接口,默认 isBusiness=false
*/
@Override
public Map<String, String> generationCodes(Long tableId) {
return generationCodes(tableId, false);
}
@Override

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BusinessBaseDO;
import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
@@ -67,6 +68,7 @@ public class CodegenBuilder {
* {@link cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO} 的字段
*/
public static final Set<String> BASE_DO_FIELDS = new HashSet<>();
public static final Set<String> BUSINESS_BASE_DO_FIELDS = new HashSet<>();
/**
* 新增操作,不需要传递的字段
*/
@@ -87,12 +89,18 @@ public class CodegenBuilder {
static {
Arrays.stream(ReflectUtil.getFields(BaseDO.class)).forEach(field -> BASE_DO_FIELDS.add(field.getName()));
BASE_DO_FIELDS.add(TENANT_ID_FIELD);
Arrays.stream(ReflectUtil.getFields(BusinessBaseDO.class)).forEach(field -> BUSINESS_BASE_DO_FIELDS.add(field.getName()));
BUSINESS_BASE_DO_FIELDS.add(TENANT_ID_FIELD);
// 处理 OPERATION 相关的字段
CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
LIST_OPERATION_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
LIST_OPERATION_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是可能需要传递的
LIST_OPERATION_RESULT_EXCLUDE_COLUMN.addAll(BASE_DO_FIELDS);
CREATE_OPERATION_EXCLUDE_COLUMN.addAll(BUSINESS_BASE_DO_FIELDS);
UPDATE_OPERATION_EXCLUDE_COLUMN.addAll(BUSINESS_BASE_DO_FIELDS);
LIST_OPERATION_EXCLUDE_COLUMN.addAll(BUSINESS_BASE_DO_FIELDS);
LIST_OPERATION_RESULT_EXCLUDE_COLUMN.addAll(BUSINESS_BASE_DO_FIELDS);
LIST_OPERATION_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是可能需要传递的
LIST_OPERATION_RESULT_EXCLUDE_COLUMN.remove("createTime"); // 创建时间,还是需要返回的
}

View File

@@ -27,6 +27,7 @@ public interface FileService {
/**
* 保存文件,并返回文件的访问路径
*
* <p>会根据文件内容计算哈希值,若已存在相同哈希的文件,则直接复用,不重复上传。</p>
* @param content 文件内容
* @param name 文件名称,允许空
* @param directory 目录,允许空

View File

@@ -78,13 +78,22 @@ public class FileServiceImpl implements FileService {
}
private FileDO uploadFile(byte[] content, String name, String directory, String type) throws Exception {
// 1.1 处理 type 为空的情况
// 1.1 计算文件哈希
String hash = DigestUtil.sha256Hex(content);
// 1.2 查找是否已存在相同hash的文件存在则直接复用
FileDO exist = fileMapper.selectByHash(hash);
if (exist != null) {
return exist;
}
// 1.3 处理 type 为空的情况
if (StrUtil.isEmpty(type)) {
type = FileTypeUtils.getMineType(content, name);
}
// 1.2 处理 name 为空的情况
// 1.4 处理 name 为空的情况
if (StrUtil.isEmpty(name)) {
name = DigestUtil.sha256Hex(content);
name = hash;
}
if (StrUtil.isEmpty(FileUtil.extName(name))) {
// 如果 name 没有后缀 type则补充后缀
@@ -102,7 +111,8 @@ public class FileServiceImpl implements FileService {
String url = client.upload(content, path, type);
FileDO entity = new FileDO().setConfigId(client.getId())
.setName(name).setPath(path).setUrl(url)
.setType(type).setSize(content.length);
.setType(type).setSize(content.length)
.setHash(hash);
// 3. 保存到数据库
fileMapper.insert(entity);

View File

@@ -4,6 +4,9 @@ import org.springframework.web.bind.annotation.*;
import ${jakartaPackage}.annotation.Resource;
import org.springframework.validation.annotation.Validated;
#if ($sceneEnum.scene == 1)import org.springframework.security.access.prepost.PreAuthorize;#end
#if($isBusiness && $isBusiness == true)
import ${basePackage}.framework.business.interceptor.BusinessControllerMarker;
#end
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
@@ -39,7 +42,12 @@ import ${basePackage}.module.${table.moduleName}.service.${table.businessName}.$
##二级的 businessName 暂时不算在 HTTP 路径上,可以根据需要写
@RequestMapping("/${table.moduleName}/${simpleClassName_strikeCase}")
@Validated
## 支持业务基类标记isBusiness=true 时继承 BusinessControllerMarker
#if($isBusiness && $isBusiness == true)
public class ${sceneEnum.prefixClass}${table.className}Controller implements BusinessControllerMarker {
#else
public class ${sceneEnum.prefixClass}${table.className}Controller {
#end
@Resource
private ${table.className}Service ${classNameVar}Service;
@@ -129,7 +137,7 @@ public class ${sceneEnum.prefixClass}${table.className}Controller {
#if ($voType == 10)
return success(BeanUtils.toBean(list, ${respVOClass}.class));
#else
return success(list);
return success(list);
#end
}
@@ -256,15 +264,15 @@ public class ${sceneEnum.prefixClass}${table.className}Controller {
}
#end
@GetMapping("/${subSimpleClassName_strikeCase}/get")
@Operation(summary = "获得${subTable.classComment}")
@Parameter(name = "id", description = "编号", required = true)
@GetMapping("/${subSimpleClassName_strikeCase}/get")
@Operation(summary = "获得${subTable.classComment}")
@Parameter(name = "id", description = "编号", required = true)
#if ($sceneEnum.scene == 1)
@PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
#end
public CommonResult<${subTable.className}DO> get${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) {
return success(${classNameVar}Service.get${subSimpleClassName}(id));
}
public CommonResult<${subTable.className}DO> get${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) {
return success(${classNameVar}Service.get${subSimpleClassName}(id));
}
#end
#end

Some files were not shown because too many files have changed in this diff Show More