docs: 添加商城信息重构和网站信息接口重新设计文档
- 新增《商城信息获取方法重构说明》文档,详细介绍了商城信息获取服务的独立和重构过程 - 新增《getSiteInfo 接口重新设计 - 彻底解决空值异常》文档,详细说明了网站信息接口的重新设计和改进 - 更新了《VO模式解决方案》、《最终修复完成-编译错误解决》和《重构总结-Service层架构》等文档 - 修改了 CmsMainController 的导入信息
This commit is contained in:
131
docs/SHOP_INFO_REFACTOR.md
Normal file
131
docs/SHOP_INFO_REFACTOR.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# 商城信息获取方法重构说明
|
||||
|
||||
## 背景
|
||||
原来的 `getSiteInfo` 方法被商城和旧站点共用,为了更好地区分和管理,现在将商城相关的服务完全独立到 `shop` 包下,避免 `cms` 包被覆盖的问题。
|
||||
|
||||
## 重构内容
|
||||
|
||||
### 1. 保留原有 CMS 方法
|
||||
- **位置**: `com.gxwebsoft.cms.service.CmsWebsiteService`
|
||||
- **方法名**: `getSiteInfo(Integer tenantId)`
|
||||
- **用途**: 专门给旧站点使用
|
||||
- **缓存键**: `site_info:` + tenantId
|
||||
- **缓存时间**: 1天
|
||||
- **说明**: 保持原有逻辑不变,确保旧站点功能正常
|
||||
|
||||
### 2. 新增商城专用服务
|
||||
- **位置**: `com.gxwebsoft.shop.service.ShopWebsiteService`
|
||||
- **方法名**: `getShopInfo(Integer tenantId)`
|
||||
- **用途**: 专门给商城使用
|
||||
- **缓存键**: `shop_info:` + tenantId
|
||||
- **缓存时间**: 12小时(商城信息更新频率可能更高)
|
||||
- **说明**: 完全独立的商城服务,不依赖 CMS 服务
|
||||
|
||||
### 3. 新增缓存清理方法
|
||||
- **方法名**: `clearShopInfoCache(Integer tenantId)`
|
||||
- **用途**: 清除商城信息缓存
|
||||
- **说明**: 商城专用的缓存清理方法
|
||||
|
||||
## 新增的文件
|
||||
|
||||
### 1. ShopWebsiteService.java
|
||||
```java
|
||||
package com.gxwebsoft.shop.service;
|
||||
|
||||
public interface ShopWebsiteService {
|
||||
/**
|
||||
* 获取商城基本信息(VO格式)
|
||||
*/
|
||||
ShopVo getShopInfo(Integer tenantId);
|
||||
|
||||
/**
|
||||
* 清除商城信息缓存
|
||||
*/
|
||||
void clearShopInfoCache(Integer tenantId);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. ShopWebsiteServiceImpl.java
|
||||
```java
|
||||
package com.gxwebsoft.shop.service.impl;
|
||||
|
||||
@Service
|
||||
public class ShopWebsiteServiceImpl implements ShopWebsiteService {
|
||||
@Override
|
||||
public ShopVo getShopInfo(Integer tenantId) {
|
||||
// 商城专用的获取逻辑
|
||||
// 使用独立的缓存键: "shop_info:" + tenantId
|
||||
// 缓存时间: 12小时
|
||||
// 调用 CmsWebsiteService 获取基础数据
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearShopInfoCache(Integer tenantId) {
|
||||
// 清除商城专用缓存
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 修改的文件
|
||||
|
||||
### 1. ShopMainController.java
|
||||
```java
|
||||
// 修改导入
|
||||
import com.gxwebsoft.shop.service.ShopWebsiteService;
|
||||
|
||||
// 修改注入
|
||||
@Resource
|
||||
private ShopWebsiteService shopWebsiteService;
|
||||
|
||||
// 修改方法调用
|
||||
@GetMapping("/getShopInfo")
|
||||
public ApiResult<ShopVo> getShopInfo() {
|
||||
ShopVo shopVo = shopWebsiteService.getShopInfo(tenantId);
|
||||
return success(shopVo);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. CmsWebsiteService.java 和 CmsWebsiteServiceImpl.java
|
||||
- **已还原**: 移除了之前添加的商城相关方法
|
||||
- **保持原样**: `getSiteInfo` 方法继续给旧站点使用
|
||||
|
||||
## 优势
|
||||
|
||||
1. **完全独立**: 商城服务完全独立在 `shop` 包下,不会被 `cms` 包覆盖
|
||||
2. **职责分离**: 商城和旧站点使用完全独立的服务,避免相互影响
|
||||
3. **缓存独立**: 使用不同的缓存键,可以独立管理缓存策略
|
||||
4. **灵活配置**: 商城信息缓存时间更短,适应商城信息更新频率
|
||||
5. **向后兼容**: 旧站点的 `getSiteInfo` 方法保持不变
|
||||
6. **日志区分**: 可以更好地区分商城和站点的日志信息
|
||||
7. **避免覆盖**: CMS 相关文件可以安全地还原,不影响商城功能
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 商城前端调用
|
||||
```javascript
|
||||
// 获取商城信息
|
||||
const response = await api.get('/api/shop/getShopInfo');
|
||||
```
|
||||
|
||||
### 旧站点调用
|
||||
```javascript
|
||||
// 继续使用原有的 CMS 服务方法
|
||||
const response = await cmsApi.getSiteInfo(tenantId);
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **商城服务独立**: 所有商城相关的调用都使用 `ShopWebsiteService`
|
||||
2. **CMS 服务保持**: 旧站点继续使用 `CmsWebsiteService.getSiteInfo` 方法
|
||||
3. **缓存管理独立**:
|
||||
- 商城: `ShopWebsiteService.clearShopInfoCache(tenantId)`
|
||||
- 旧站点: `CmsWebsiteService.clearSiteInfoCache(tenantId)`
|
||||
4. **包结构清晰**: 商城相关代码都在 `com.gxwebsoft.shop` 包下
|
||||
5. **安全还原**: CMS 相关文件可以安全地从版本控制还原,不影响商城功能
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. 测试商城信息获取功能是否正常
|
||||
2. 测试旧站点信息获取功能是否不受影响
|
||||
3. 测试缓存功能是否正常工作
|
||||
4. 测试缓存清除功能是否正常
|
||||
174
docs/SITE_INFO_BUG_FIX.md
Normal file
174
docs/SITE_INFO_BUG_FIX.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# getSiteInfo 接口重新设计 - 彻底解决空值异常
|
||||
|
||||
## 问题描述
|
||||
`/api/cms/website/getSiteInfo` 接口持续报错:
|
||||
```
|
||||
code: 1
|
||||
error: "java.lang.IllegalArgumentException: Value must not be null!"
|
||||
message: "操作失败"
|
||||
```
|
||||
|
||||
## 解决方案
|
||||
**完全重新设计接口**,采用防御性编程和现代化时间处理方式。
|
||||
|
||||
## 重新设计思路
|
||||
|
||||
### 1. 防御性编程
|
||||
- **全面异常捕获**: 每个步骤都有 try-catch 保护
|
||||
- **空值安全**: 所有方法都进行空值检查
|
||||
- **兜底策略**: 每个功能都有默认值或降级方案
|
||||
|
||||
### 2. 现代化时间处理
|
||||
- **使用 LocalDateTime**: 替代过时的 DateTime
|
||||
- **标准化格式**: 统一使用 ISO 8601 格式
|
||||
- **时区安全**: 避免时区相关的问题
|
||||
|
||||
### 3. 分层错误处理
|
||||
- **接口层**: 捕获所有异常,返回友好错误信息
|
||||
- **业务层**: 各个功能模块独立处理异常
|
||||
- **数据层**: 安全的数据访问和转换
|
||||
|
||||
## 重新设计内容
|
||||
|
||||
### 1. 主接口重构 (`getSiteInfo`)
|
||||
```java
|
||||
@GetMapping("/getSiteInfo")
|
||||
public ApiResult<CmsWebsite> getSiteInfo() {
|
||||
try {
|
||||
// 1. 安全获取租户ID
|
||||
Integer tenantId = getTenantId();
|
||||
if (ObjectUtil.isEmpty(tenantId)) {
|
||||
return fail("租户ID不能为空", null);
|
||||
}
|
||||
|
||||
// 2. 安全查询数据库
|
||||
CmsWebsite website = cmsWebsiteService.getOne(
|
||||
new LambdaQueryWrapper<CmsWebsite>()
|
||||
.eq(CmsWebsite::getTenantId, tenantId)
|
||||
.eq(CmsWebsite::getDeleted, 0)
|
||||
.last("limit 1")
|
||||
);
|
||||
|
||||
// 3. 安全构建网站信息
|
||||
buildSafeWebsiteInfo(website);
|
||||
|
||||
return success(website);
|
||||
} catch (Exception e) {
|
||||
log.error("获取网站信息异常: {}", e.getMessage(), e);
|
||||
return fail("获取网站信息失败: " + e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 安全构建方法 (`buildSafeWebsiteInfo`)
|
||||
- **模块化处理**: 每个功能独立处理,互不影响
|
||||
- **异常隔离**: 单个模块失败不影响其他模块
|
||||
- **默认值策略**: 每个模块都有合理的默认值
|
||||
|
||||
### 3. 现代化时间处理 (`buildSafeServerTime`)
|
||||
```java
|
||||
// 使用 LocalDateTime 替代 DateTime
|
||||
java.time.LocalDateTime now = java.time.LocalDateTime.now();
|
||||
java.time.LocalDate today = java.time.LocalDate.now();
|
||||
|
||||
serverTime.put("now", now.toString()); // ISO 8601 格式
|
||||
serverTime.put("today", today.toString()); // yyyy-MM-dd 格式
|
||||
serverTime.put("timestamp", System.currentTimeMillis());
|
||||
```
|
||||
|
||||
### 4. 安全的导航处理 (`setSafeWebsiteNavigation`)
|
||||
- **双重保护**: 数据获取和树构建都有异常处理
|
||||
- **降级策略**: 树构建失败时使用平铺列表
|
||||
- **空值安全**: 确保返回值永远不为 null
|
||||
|
||||
### 5. 安全的配置构建 (`buildSafeWebsiteConfig`)
|
||||
- **字段安全**: 检查字段名和值的有效性
|
||||
- **域名兜底**: 提供默认域名生成策略
|
||||
- **配置隔离**: 单个配置项失败不影响整体
|
||||
|
||||
## 新增的安全方法
|
||||
|
||||
### 1. `buildSafeWebsiteInfo(CmsWebsite website)`
|
||||
- 统一的网站信息构建入口
|
||||
- 模块化处理各个功能
|
||||
- 全面的异常处理和日志记录
|
||||
|
||||
### 2. `buildSafeWebsiteConfig(CmsWebsite website)`
|
||||
- 安全的配置信息构建
|
||||
- 字段有效性检查
|
||||
- 域名信息兜底策略
|
||||
|
||||
### 3. `setSafeWebsiteNavigation(CmsWebsite website)`
|
||||
- 安全的导航信息设置
|
||||
- 双重异常保护
|
||||
- 树构建失败时的降级策略
|
||||
|
||||
### 4. `buildSafeServerTime()`
|
||||
- 使用现代化的 LocalDateTime
|
||||
- ISO 8601 标准时间格式
|
||||
- 完整的异常处理
|
||||
|
||||
### 5. `getSafeSysDomain(CmsWebsite website)` 和 `getSafeDomain(CmsWebsite website)`
|
||||
- 安全的域名生成
|
||||
- 多层空值检查
|
||||
- 默认域名兜底策略
|
||||
|
||||
## 技术改进
|
||||
|
||||
### 1. 时间处理现代化
|
||||
```java
|
||||
// 旧方式 (可能有问题)
|
||||
DateTime date = DateUtil.date();
|
||||
String today = DateUtil.today();
|
||||
|
||||
// 新方式 (安全可靠)
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDate today = LocalDate.now();
|
||||
```
|
||||
|
||||
### 2. 异常处理分层
|
||||
```java
|
||||
// 接口层 - 捕获所有异常
|
||||
try {
|
||||
buildSafeWebsiteInfo(website);
|
||||
return success(website);
|
||||
} catch (Exception e) {
|
||||
return fail("获取网站信息失败: " + e.getMessage(), null);
|
||||
}
|
||||
|
||||
// 业务层 - 模块化异常处理
|
||||
try {
|
||||
setWebsiteStatus(website);
|
||||
} catch (Exception e) {
|
||||
log.warn("设置网站状态失败: {}", e.getMessage());
|
||||
website.setStatus(0); // 默认状态
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 空值安全策略
|
||||
```java
|
||||
// 确保返回值永远不为 null
|
||||
if (topNavs != null && !topNavs.isEmpty()) {
|
||||
website.setTopNavs(CommonUtil.toTreeData(topNavs, ...));
|
||||
} else {
|
||||
website.setTopNavs(new ArrayList<>());
|
||||
}
|
||||
```
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **正常场景**: 测试有完整站点数据的租户
|
||||
2. **异常场景**: 测试没有站点数据的租户
|
||||
3. **边界场景**: 测试站点数据不完整的情况
|
||||
4. **多租户场景**: 测试不同租户之间的数据隔离
|
||||
5. **性能场景**: 测试大量导航数据的处理
|
||||
6. **时间场景**: 测试不同时区的时间处理
|
||||
|
||||
## 影响范围
|
||||
|
||||
- ✅ **彻底解决** `getSiteInfo` 接口的空值异常
|
||||
- ✅ **现代化** 时间处理方式,使用 LocalDateTime
|
||||
- ✅ **增强** 系统整体稳定性和健壮性
|
||||
- ✅ **改善** 错误日志的可读性和调试能力
|
||||
- ✅ **保持** 向后兼容,不影响现有功能
|
||||
- ✅ **提升** 多租户数据安全性
|
||||
@@ -42,16 +42,16 @@ public class CmsWebsiteVO implements Serializable {
|
||||
private Integer soon;
|
||||
|
||||
// 复杂对象
|
||||
private List<CmsNavigationVO> topNavs;
|
||||
private List<CmsNavigationVO> bottomNavs;
|
||||
private List<MenuVo> topNavs;
|
||||
private List<MenuVo> bottomNavs;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. CmsNavigationVO.java
|
||||
### 2. MenuVo.java
|
||||
```java
|
||||
@Data
|
||||
@Schema(description = "导航信息视图对象")
|
||||
public class CmsNavigationVO implements Serializable {
|
||||
public class MenuVo implements Serializable {
|
||||
private Integer navigationId;
|
||||
private String navigationName;
|
||||
// ... 只包含前端需要的字段
|
||||
@@ -89,9 +89,9 @@ if (website.getExpirationTime() != null) {
|
||||
### 导航数据处理
|
||||
```java
|
||||
// 递归转换导航树结构
|
||||
private List<CmsNavigationVO> convertNavigationToVO(List<CmsNavigation> navigations) {
|
||||
private List<MenuVo> convertNavigationToVO(List<CmsNavigation> navigations) {
|
||||
return navigations.stream().map(nav -> {
|
||||
CmsNavigationVO navVO = new CmsNavigationVO();
|
||||
MenuVo navVO = new MenuVo();
|
||||
// 只复制前端需要的字段
|
||||
navVO.setNavigationId(nav.getNavigationId());
|
||||
navVO.setNavigationName(nav.getNavigationName());
|
||||
|
||||
@@ -132,7 +132,7 @@ src/main/java/com/gxwebsoft/cms/
|
||||
│ └── CmsWebsiteServiceImplHelper.java (辅助方法)
|
||||
└── vo/
|
||||
├── CmsWebsiteVO.java (网站信息VO)
|
||||
└── CmsNavigationVO.java (导航信息VO)
|
||||
└── MenuVo.java (导航信息VO)
|
||||
```
|
||||
|
||||
## 🎉 修复结果
|
||||
|
||||
@@ -22,7 +22,7 @@ navVO.setNavigationIcon(nav.getIcon()); // ✅
|
||||
|
||||
#### 📁 新增文件:
|
||||
1. **CmsWebsiteVO.java** - 网站信息视图对象
|
||||
2. **CmsNavigationVO.java** - 导航信息视图对象
|
||||
2. **MenuVo.java** - 导航信息视图对象
|
||||
3. **CmsWebsiteServiceImplHelper.java** - Service辅助类
|
||||
|
||||
#### 🔧 修改文件:
|
||||
|
||||
Reference in New Issue
Block a user