fix: 优化鱼字典新增修改

This commit is contained in:
tangwei 2026-08-11 15:48:23 +08:00
parent 57403df980
commit cca46d159e
5 changed files with 116 additions and 22 deletions

View File

@ -20,10 +20,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -88,9 +85,14 @@ public class SdFishDictoryBController {
if (entity == null) {
return ResponseResult.error("数据不能为空");
}
entity.setId(IdUtil.simpleUUID());
entity.setId(IdUtil.fastUUID());
entity.setCode(entity.getId());
// 名称重名校验
if (sdFishDictoryBService.existsByName(entity.getName())) {
return ResponseResult.error("该鱼类名称已存在");
}
// 上传文件并设置附件ID到实体
applyUploadedFiles(entity, files);
@ -109,23 +111,35 @@ public class SdFishDictoryBController {
@RequestParam(value = "files", required = false) List<MultipartFile> files) {
try {
SdEngInfoBHOperateRequest request = objectMapper.readValue(dataStr, SdEngInfoBHOperateRequest.class);
SdFishDictoryB entity = request == null || request.getEngInfo() == null ? null
: objectMapper.convertValue(request.getEngInfo(), SdFishDictoryB.class);
if (entity == null || entity.getId() == null) {
Map<String, Object> engInfo = request == null ? null : request.getEngInfo();
if (engInfo == null || engInfo.get("id") == null) {
return ResponseResult.error("数据或ID不能为空");
}
// 名称重名校验仅当本次修改了名称时校验
Object newName = engInfo.get("name");
if (newName != null && StrUtil.isNotBlank(newName.toString())) {
String name = newName.toString();
if (sdFishDictoryBService.existsByNameExcludeId(name, (String) engInfo.get("id"))) {
return ResponseResult.error("该鱼类名称已存在");
}
}
// 获取修改前的实体用于后续清理旧文件
SdFishDictoryB before = sdFishDictoryBService.getById(entity.getId());
SdFishDictoryB before = sdFishDictoryBService.getById((String) engInfo.get("id"));
List<String> oldAttachmentIds = before != null ? collectAttachmentIds(before) : Collections.emptyList();
// 上传新文件并设置附件ID
applyUploadedFiles(entity, files);
SdFishDictoryB tempEntity = objectMapper.convertValue(engInfo, SdFishDictoryB.class);
applyUploadedFiles(tempEntity, files);
// 将文件处理后 inffile 合并回 patch map
engInfo.put("inffile", tempEntity.getInffile());
boolean result = sdFishDictoryBService.update(entity, request.getSource());
boolean result = sdFishDictoryBService.update(engInfo, request.getSource());
if (result) {
// 清理被替换的旧文件
deleteReplacedFiles(oldAttachmentIds, collectAttachmentIds(entity));
SdFishDictoryB after = sdFishDictoryBService.getById((String) engInfo.get("id"));
deleteReplacedFiles(oldAttachmentIds, collectAttachmentIds(after));
}
return result ? ResponseResult.success("修改成功") : ResponseResult.error("修改失败");
} catch (Exception e) {

View File

@ -21,7 +21,7 @@ public class SdFishDictoryB implements Serializable {
private static final long serialVersionUID = 1L;
/** 主键 */
@TableId(type = IdType.ASSIGN_UUID)
@TableId(type = IdType.INPUT)
@FieldChinese("主键")
private String id;
@ -105,6 +105,9 @@ public class SdFishDictoryB implements Serializable {
@FieldChinese("所属流域")
private String rvcd;
@TableField(exist = false)
private String rvcdName;
/** 洄游习性 */
@FieldChinese("洄游习性")
private String habitMigrat;

View File

@ -6,6 +6,7 @@ import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.qgc_base.domain.SdFishDictoryB;
import java.util.List;
import java.util.Map;
public interface ISdFishDictoryBService extends IService<SdFishDictoryB> {
@ -16,10 +17,21 @@ public interface ISdFishDictoryBService extends IService<SdFishDictoryB> {
boolean add(SdFishDictoryB entity, String source);
boolean update(SdFishDictoryB entity, String source);
boolean update(Map<String, Object> patchMap, String source) throws Exception;
boolean delete(List<String> ids, String source);
SdFishDictoryB getById(String id);
/**
* 检查名称是否已存在不过滤IS_DELETED因为唯一约束不区分软删除
*/
boolean existsByName(String name);
/**
* 检查名称是否已被其他记录占用排除指定ID
*/
boolean existsByNameExcludeId(String name, String excludeId);
List<SdFishDictoryB> findSimilarFish(String name, Integer limit);
}

View File

@ -49,6 +49,22 @@ public class PatchUpdateHelper {
@Resource
private DictCodeToNameConverter dictCodeToNameConverter;
/**
* 执行 patch 更新默认主键字段为 "stcd"
*
* @see #execute(IService, Map, String, String, Class, Set, List, String)
*/
public <T> boolean execute(
IService<T> service,
Map<String, Object> engInfoPatch,
String source,
String tableName,
Class<T> entityClass,
Set<String> transientFields,
List<CodeToNameMetadataBo> codeToNameMetaList) throws Exception {
return execute(service, engInfoPatch, source, tableName, entityClass, transientFields, codeToNameMetaList, "stcd");
}
/**
* 执行 patch 更新仅更新前端显式传入的字段包括 null 未传入的字段保持原值
*
@ -59,6 +75,7 @@ public class PatchUpdateHelper {
* @param entityClass 实体类
* @param transientFields 需跳过的瞬态字段集合 @TableField(exist=false)serialVersionUID
* @param codeToNameMetaList 字典代码转名称配置用于操作日志
* @param pkFieldName 主键 Java 字段名 "stcd""id"
* @param <T> 实体类型
* @return true=更新成功
* @throws Exception Jackson 类型转换异常等
@ -70,27 +87,29 @@ public class PatchUpdateHelper {
String tableName,
Class<T> entityClass,
Set<String> transientFields,
List<CodeToNameMetadataBo> codeToNameMetaList) throws Exception {
List<CodeToNameMetadataBo> codeToNameMetaList,
String pkFieldName) throws Exception {
String stcd = engInfoPatch == null ? null : (String) engInfoPatch.get("stcd");
if (StrUtil.isBlank(stcd)) {
throw new BizException("站点编码不能为空");
Object pkValue = engInfoPatch == null ? null : engInfoPatch.get(pkFieldName);
if (isEmptyPk(pkValue)) {
throw new BizException("主键不能为空");
}
T before = service.getById(stcd);
T before = service.getById((String) pkValue);
if (before == null) {
throw new BizException("测站不存在: " + stcd);
throw new BizException("记录不存在: " + pkValue);
}
T after = entityClass.getDeclaredConstructor().newInstance();
BeanUtil.copyProperties(before, after);
objectMapper.updateValue(after, engInfoPatch);
String pkColumn = StrUtil.toUnderlineCase(pkFieldName).toUpperCase();
UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("STCD", stcd);
updateWrapper.eq(pkColumn, pkValue);
boolean hasUpdate = false;
for (Field field : entityClass.getDeclaredFields()) {
String fieldName = field.getName();
if (transientFields.contains(fieldName) || "stcd".equals(fieldName)) {
if (transientFields.contains(fieldName) || pkFieldName.equals(fieldName)) {
continue;
}
if (!engInfoPatch.containsKey(fieldName)) {
@ -114,8 +133,14 @@ public class PatchUpdateHelper {
if (result) {
dictCodeToNameConverter.convertCodeToName(before, codeToNameMetaList);
dictCodeToNameConverter.convertCodeToName(after, codeToNameMetaList);
msOperationLogService.recordModifyDetailLog(stcd, tableName, before, after, source, codeToNameMetaList);
msOperationLogService.recordModifyDetailLog(String.valueOf(pkValue), tableName, before, after, source, codeToNameMetaList);
}
return result;
}
private boolean isEmptyPk(Object value) {
if (value == null) return true;
if (value instanceof String) return StrUtil.isBlank((String) value);
return false;
}
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.qgc_base.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -36,6 +37,14 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper,
@Resource
private DictCodeToNameConverter dictCodeToNameConverter;
@Resource
private PatchUpdateHelper patchUpdateHelper;
/** SdFishDictoryB 中 @TableField(exist = false) 的字段名 + serialVersionUID */
private static final Set<String> TRANSIENT_FIELDS = Set.of(
"typeName", "rareName", "specOriginName", "ptypeName",
"habitatName", "situationName", "resourceTypeName", "serialVersionUID"
);
/**
* 代码转名称元数据配置列表静态初始化
@ -95,6 +104,14 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper,
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean update(Map<String, Object> patchMap, String source) throws Exception {
return patchUpdateHelper.execute(
this, patchMap, source, TABLE_NAME, SdFishDictoryB.class,
TRANSIENT_FIELDS, CODE_TO_NAME_META_LIST, "id");
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean delete(List<String> ids, String source) {
@ -116,6 +133,29 @@ public class SdFishDictoryBServiceImpl extends ServiceImpl<SdFishDictoryBMapper,
return count > 0;
}
@Override
public boolean existsByName(String name) {
if (!StringUtils.hasText(name)) {
return false;
}
LambdaQueryWrapper<SdFishDictoryB> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFishDictoryB::getName, name);
return count(wrapper) > 0;
}
@Override
public boolean existsByNameExcludeId(String name, String excludeId) {
if (!StringUtils.hasText(name)) {
return false;
}
LambdaQueryWrapper<SdFishDictoryB> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SdFishDictoryB::getName, name);
if (StringUtils.hasText(excludeId)) {
wrapper.ne(SdFishDictoryB::getId, excludeId);
}
return count(wrapper) > 0;
}
@Override
public SdFishDictoryB getById(String id) {
LambdaQueryWrapper<SdFishDictoryB> wrapper = new LambdaQueryWrapper<>();