Files
contract-manager/docs/model/Inventory说明文档.md
songqq b03b5385a5 refactor(service): 修改IEntityService泛型为VO类型并优化缓存策略
重构所有注解@CacheConfig的Service类,将IEntityService泛型从实体类改为VO类
实现实体与VO之间的转换逻辑,使用VO替代实体进行缓存以避免序列化问题
更新相关依赖组件和测试用例,确保功能完整性和系统兼容性
优化Redis缓存配置,清理旧缓存数据并验证新缓存策略有效性
2025-09-28 18:19:00 +08:00

8.0 KiB
Raw Blame History

Inventory 实体类说明文档

1. 概述

Inventory 类是 Contract-Manager 项目中的核心实体类,代表存货物品清单,用于管理和存储各类存货物品的详细信息。该类位于 common 模块中,实现了 IdentityEntityBasedEntitySerializable 接口,支持数据持久化和对象序列化。

2. 类结构

@Getter
@Setter
@Entity
@Table(name = "INVENTORY", schema = "supplier_ms")
public class Inventory implements IdentityEntity, BasedEntity, Serializable {
    // 类实现内容
}

2.1 核心注解

  • @Getter@SetterLombok注解自动生成getter和setter方法
  • @EntityJPA注解表示该类是持久化实体
  • @Table:指定对应的数据库表名为 INVENTORY,模式为 supplier_ms

3. 字段说明

3.1 基本信息

  • id:主键,使用自增策略
  • code:存货编码
  • name:存货名称
  • specification:规格型号
  • specificationLock:规格型号是否锁定
  • nameLock:名称是否锁定
  • unit:单位
  • description:描述信息

3.2 价格信息(嵌入式)

使用 Price 嵌入式类存储采购和销售价格:

  • purchasePrice:采购价格(含税前价格、税后价格、税率)
  • salePrice:销售价格(含税前价格、税后价格、税率)

3.3 重量与尺寸信息

  • weight:产品重量
  • packagedWeight:包装重量
  • weightUnit重量单位默认kg
  • volumeUnit体积单位默认
  • sizeUnit尺寸单位默认mm

3.4 体积尺寸信息(嵌入式)

使用 VolumeSize 嵌入式类存储体积尺寸:

  • volumeSize:产品体积尺寸(长、宽、高、体积)
  • packagedVolumeSize:包装体积尺寸(长、宽、高、体积)

3.5 关联关系

  • catalog:所属分类,多对一关联 InventoryCatalog
  • creator:创建人,多对一关联 Employee
  • updater:更新人,多对一关联 Employee

3.6 时间信息

  • createTime创建时间LocalDate类型
  • updateDate更新时间LocalDateTime类型

4. 接口实现

4.1 IdentityEntity 接口

  • 实现了 getId()setId(Integer id) 方法
  • 重写了 equals(Object object) 方法基于ID进行比较

4.2 BasedEntity 接口

  • 实现了 toPrettyString() 方法,返回 "名称+规格" 格式的字符串

5. 关联实体类

5.1 InventoryCatalog

  • 表示存货分类
  • 与Inventory是一对多关系

5.2 Price

  • 嵌入式类,存储价格相关信息
  • 包含税率、税前价格、税后价格

5.3 VolumeSize

  • 嵌入式类,存储体积尺寸信息
  • 包含体积、长度、宽度、高度

5.4 Employee

  • 表示系统用户/员工
  • 与Inventory是多对一关系创建人和更新人

6. 数据访问层

InventoryRepository 接口提供了对Inventory实体的数据库访问功能

@Repository
public interface InventoryRepository extends JpaRepository<Inventory, Integer>, JpaSpecificationExecutor<Inventory> {
    Optional<Inventory> findByCode(String code);
}
  • 继承自 JpaRepository提供基本的CRUD操作
  • 继承自 JpaSpecificationExecutor,支持动态查询条件
  • 自定义方法 findByCode,通过编码查询存货

7. 服务层

7.1 Server模块

server 模块中的 InventoryService 实现了多个接口,提供完整的业务逻辑:

  • 实现了缓存机制,提高查询效率
  • 支持分页查询和动态条件搜索
  • 提供通过编码查询、保存、删除等操作
  • 实现了 createNewInstance() 方法用于创建新的Inventory实例并设置默认值
  • 实现了 updateByVo() 方法支持从VO对象更新实体

7.2 Client模块

client 模块中的 InventoryService 主要提供客户端特定的业务逻辑:

  • 创建新的InventoryVo实例
  • 提供按编码和名称查询的方法
  • 包含待实现的 syncInventory() 方法

8. 数据传输对象

InventoryVo 类用于在不同层之间传输Inventory相关数据

  • 包含与Inventory实体对应的主要字段
  • 添加了 active 字段,表示状态
  • 使用关联实体的ID替代直接引用catalogIdcreatorId 等)

9. 代码优化建议

9.1 数据一致性

  • 问题InventoryService.createNewInstance() 方法设置了默认的税率为13%,但没有自动计算税后价格
  • 建议
public Inventory createNewInstance() {
    Inventory inventory = new Inventory();
    
    // 设置默认值
    inventory.setNameLock(false);
    inventory.setSpecificationLock(false);
    
    // 设置税率并自动计算税后价格
    float defaultTaxRate = 13;
    double defaultPrice = 0;
    
    Price purchasePrice = inventory.getPurchasePrice();
    purchasePrice.setTaxRate(defaultTaxRate);
    purchasePrice.setPreTaxPrice(defaultPrice);
    purchasePrice.setPostTaxPrice(defaultPrice * (1 + defaultTaxRate / 100));
    
    Price salePrice = inventory.getSalePrice();
    salePrice.setTaxRate(defaultTaxRate);
    salePrice.setPreTaxPrice(defaultPrice);
    salePrice.setPostTaxPrice(defaultPrice * (1 + defaultTaxRate / 100));
    
    // 其他默认值设置
    inventory.setWeightUnit("kg");
    inventory.setVolumeUnit("m³");
    inventory.setSizeUnit("mm");
    inventory.setCreateTime(LocalDate.now());
    
    return inventory;
}

9.2 时间类型一致性

  • 问题:创建时间使用 LocalDate 类型,更新时间使用 LocalDateTime 类型,类型不一致
  • 建议:统一使用 LocalDateTime 类型,以便更精确地记录时间信息

9.3 完整性验证

  • 问题:缺少对必填字段的完整性验证
  • 建议:在 save 方法中添加基本的验证逻辑:
@Caching(evict = {
        @CacheEvict(key = "#p0.id"),
        @CacheEvict(key = "'code-'+#p0.code"),
})public Inventory save(Inventory entity) {
    // 基本验证
    if (entity == null) {
        throw new IllegalArgumentException("Inventory entity cannot be null");
    }
    if (!StringUtils.hasText(entity.getName())) {
        throw new IllegalArgumentException("Inventory name is required");
    }
    
    // 更新时间戳
    entity.setUpdateDate(LocalDateTime.now());
    
    return inventoryRepository.save(entity);
}

9.4 性能优化

  • 问题search 方法中排序设置可能存在问题
  • 建议:优化排序逻辑:
public List<Inventory> search(String searchText) {
    Pageable pageable = PageRequest.of(0, getSearchPageSize(), Sort.by(Sort.Direction.DESC, "id"));
    Specification<Inventory> specification = getSpecification(searchText);
    return inventoryRepository.findAll(specification, pageable).getContent();
}

10. 输入输出示例

输入输出示例

创建新存货:

// 服务端创建新存货
Inventory inventory = inventoryService.createNewInstance();
inventory.setName("笔记本电脑");
inventory.setCode("NB-001");
inventory.setSpecification("ThinkPad X1 Carbon");
inventory.setUnit("台");

// 设置价格信息
Price salePrice = inventory.getSalePrice();
salePrice.setPreTaxPrice(9999.00);
salePrice.setPostTaxPrice(9999.00 * 1.13);

// 保存
inventory = inventoryService.save(inventory);

根据编码查询存货:

// 服务端查询
Inventory inventory = inventoryService.findByCode("NB-001");
System.out.println("存货名称:" + inventory.toPrettyString()); // 输出:笔记本电脑 ThinkPad X1 Carbon

// 客户端查询
InventoryVo inventoryVo = clientInventoryService.findByCode("NB-001");
System.out.println("存货ID" + inventoryVo.getId() + ", 名称:" + inventoryVo.getName());

11. 总结

Inventory 实体类是Contract-Manager项目中用于管理存货信息的核心类通过与相关实体、服务和数据访问层的协作提供了完整的存货管理功能。该类设计合理包含了存货的各种属性信息并通过实现相关接口提供了标准的行为规范。通过实施建议的优化可以进一步提高代码的健壮性、一致性和性能。