refactor(service): 修改IEntityService泛型为VO类型并优化缓存策略

重构所有注解@CacheConfig的Service类,将IEntityService泛型从实体类改为VO类
实现实体与VO之间的转换逻辑,使用VO替代实体进行缓存以避免序列化问题
更新相关依赖组件和测试用例,确保功能完整性和系统兼容性
优化Redis缓存配置,清理旧缓存数据并验证新缓存策略有效性
This commit is contained in:
2025-09-28 18:19:00 +08:00
parent df6188db40
commit b03b5385a5
75 changed files with 3144 additions and 1377 deletions

View File

@@ -0,0 +1,240 @@
# Inventory 实体类说明文档
## 1. 概述
`Inventory` 类是 Contract-Manager 项目中的核心实体类,代表**存货物品清单**,用于管理和存储各类存货物品的详细信息。该类位于 `common` 模块中,实现了 `IdentityEntity``BasedEntity``Serializable` 接口,支持数据持久化和对象序列化。
## 2. 类结构
```java
@Getter
@Setter
@Entity
@Table(name = "INVENTORY", schema = "supplier_ms")
public class Inventory implements IdentityEntity, BasedEntity, Serializable {
// 类实现内容
}
```
### 2.1 核心注解
- `@Getter``@Setter`Lombok注解自动生成getter和setter方法
- `@Entity`JPA注解表示该类是持久化实体
- `@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实体的数据库访问功能
```java
@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替代直接引用`catalogId``creatorId` 等)
## 9. 代码优化建议
### 9.1 数据一致性
- **问题**`InventoryService.createNewInstance()` 方法设置了默认的税率为13%,但没有自动计算税后价格
- **建议**
```java
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` 方法中添加基本的验证逻辑:
```java
@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` 方法中排序设置可能存在问题
- **建议**:优化排序逻辑:
```java
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. 输入输出示例
#### 输入输出示例
**创建新存货:**
```java
// 服务端创建新存货
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);
```
**根据编码查询存货:**
```java
// 服务端查询
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项目中用于管理存货信息的核心类通过与相关实体、服务和数据访问层的协作提供了完整的存货管理功能。该类设计合理包含了存货的各种属性信息并通过实现相关接口提供了标准的行为规范。通过实施建议的优化可以进一步提高代码的健壮性、一致性和性能。