Browse Source
- 新增《商城信息获取方法重构说明》文档,详细介绍了商城信息获取服务的独立和重构过程 - 新增《getSiteInfo 接口重新设计 - 彻底解决空值异常》文档,详细说明了网站信息接口的重新设计和改进 - 更新了《VO模式解决方案》、《最终修复完成-编译错误解决》和《重构总结-Service层架构》等文档 - 修改了 CmsMainController 的导入信息main
15 changed files with 897 additions and 450 deletions
@ -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. 测试缓存清除功能是否正常 |
@ -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 |
||||
|
- ✅ **增强** 系统整体稳定性和健壮性 |
||||
|
- ✅ **改善** 错误日志的可读性和调试能力 |
||||
|
- ✅ **保持** 向后兼容,不影响现有功能 |
||||
|
- ✅ **提升** 多租户数据安全性 |
@ -1,341 +1,524 @@ |
|||||
package com.gxwebsoft.cms.controller; |
|
||||
|
|
||||
import cn.hutool.core.date.DateTime; |
|
||||
import cn.hutool.core.date.DateUtil; |
|
||||
import cn.hutool.core.util.ObjectUtil; |
|
||||
import cn.hutool.core.util.StrUtil; |
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
||||
import com.gxwebsoft.cms.entity.CmsNavigation; |
|
||||
import com.gxwebsoft.cms.entity.CmsWebsite; |
|
||||
import com.gxwebsoft.cms.entity.CmsWebsiteField; |
|
||||
import com.gxwebsoft.cms.entity.CmsWebsiteSetting; |
|
||||
import com.gxwebsoft.cms.param.CmsNavigationParam; |
|
||||
import com.gxwebsoft.cms.param.CmsWebsiteParam; |
|
||||
import com.gxwebsoft.cms.service.CmsNavigationService; |
|
||||
import com.gxwebsoft.cms.service.CmsWebsiteFieldService; |
|
||||
import com.gxwebsoft.cms.service.CmsWebsiteService; |
|
||||
import com.gxwebsoft.cms.service.CmsWebsiteSettingService; |
|
||||
import com.gxwebsoft.cms.vo.CmsVO; |
|
||||
import com.gxwebsoft.common.core.utils.CommonUtil; |
|
||||
import com.gxwebsoft.common.core.utils.RedisUtil; |
|
||||
import com.gxwebsoft.common.core.web.ApiResult; |
|
||||
import com.gxwebsoft.common.core.web.BaseController; |
|
||||
import com.gxwebsoft.common.core.web.BatchParam; |
|
||||
import com.gxwebsoft.common.core.web.PageResult; |
|
||||
import com.gxwebsoft.common.system.entity.User; |
|
||||
import io.swagger.v3.oas.annotations.Operation; |
|
||||
import io.swagger.v3.oas.annotations.tags.Tag; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.springframework.security.access.prepost.PreAuthorize; |
|
||||
import org.springframework.web.bind.annotation.*; |
|
||||
|
|
||||
import javax.annotation.Resource; |
|
||||
import java.util.HashMap; |
|
||||
import java.util.List; |
|
||||
import java.util.concurrent.TimeUnit; |
|
||||
|
package com.gxwebsoft.cms.controller; |
||||
|
|
||||
|
import cn.hutool.core.date.DateTime; |
||||
|
import cn.hutool.core.date.DateUtil; |
||||
|
import cn.hutool.core.util.ObjectUtil; |
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
||||
|
import com.gxwebsoft.cms.entity.*; |
||||
|
import com.gxwebsoft.cms.param.CmsNavigationParam; |
||||
|
import com.gxwebsoft.cms.service.CmsNavigationService; |
||||
|
import com.gxwebsoft.cms.service.CmsWebsiteFieldService; |
||||
|
import com.gxwebsoft.cms.service.CmsWebsiteSettingService; |
||||
|
import com.gxwebsoft.common.core.utils.CommonUtil; |
||||
|
import com.gxwebsoft.common.core.utils.RedisUtil; |
||||
|
import com.gxwebsoft.common.core.web.BaseController; |
||||
|
import com.gxwebsoft.cms.service.CmsWebsiteService; |
||||
|
import com.gxwebsoft.cms.param.CmsWebsiteParam; |
||||
|
import com.gxwebsoft.common.core.web.ApiResult; |
||||
|
import com.gxwebsoft.common.core.web.PageResult; |
||||
|
import com.gxwebsoft.common.core.web.BatchParam; |
||||
|
import com.gxwebsoft.common.system.entity.User; |
||||
|
import io.swagger.v3.oas.annotations.Operation; |
||||
|
import io.swagger.v3.oas.annotations.tags.Tag; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.security.access.prepost.PreAuthorize; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
import java.util.*; |
||||
|
|
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* 网站信息记录表控制器 |
||||
|
* |
||||
|
* @author 科技小王子 |
||||
|
* @since 2024-09-10 20:36:14 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Tag(name = "网站信息记录表管理") |
||||
|
@RestController |
||||
|
@RequestMapping("/api/cms/cms-website") |
||||
|
public class CmsWebsiteController extends BaseController { |
||||
|
@Resource |
||||
|
private CmsWebsiteService cmsWebsiteService; |
||||
|
@Resource |
||||
|
private RedisUtil redisUtil; |
||||
|
@Resource |
||||
|
private CmsWebsiteFieldService cmsWebsiteFieldService; |
||||
|
@Resource |
||||
|
private CmsNavigationService cmsNavigationService; |
||||
|
@Resource |
||||
|
private CmsWebsiteSettingService cmsWebsiteSettingService; |
||||
|
|
||||
|
private static final String SITE_INFO_KEY_PREFIX = "SiteInfo:"; |
||||
|
private static final String MP_INFO_KEY_PREFIX = "MpInfo:"; |
||||
|
private static final String SELECT_PAYMENT_KEY_PREFIX = "SelectPayment:"; |
||||
|
private static final String SYS_DOMAIN_SUFFIX = ".websoft.top"; |
||||
|
private static final String DOMAIN_SUFFIX = ".wsdns.cn"; |
||||
|
|
||||
|
@Operation(summary = "分页查询网站信息记录表") |
||||
|
@GetMapping("/page") |
||||
|
public ApiResult<PageResult<CmsWebsite>> page(CmsWebsiteParam param) { |
||||
|
// 使用关联查询
|
||||
|
return success(cmsWebsiteService.pageRel(param)); |
||||
|
} |
||||
|
|
||||
/** |
|
||||
* 网站信息记录表控制器 |
|
||||
* |
|
||||
* @author 科技小王子 |
|
||||
* @since 2024-09-10 20:36:14 |
|
||||
*/ |
|
||||
@Slf4j |
|
||||
@Tag(name = "网站信息记录表管理") |
|
||||
@RestController |
|
||||
@RequestMapping("/api/cms/cms-website") |
|
||||
public class CmsWebsiteController extends BaseController { |
|
||||
@Resource |
|
||||
private CmsWebsiteService cmsWebsiteService; |
|
||||
@Resource |
|
||||
private RedisUtil redisUtil; |
|
||||
@Resource |
|
||||
private CmsNavigationService cmsNavigationService; |
|
||||
@Resource |
|
||||
private CmsWebsiteSettingService cmsWebsiteSettingService; |
|
||||
@Resource |
|
||||
private CmsWebsiteFieldService cmsWebsiteFieldService; |
|
||||
|
|
||||
private static final String SITE_INFO_KEY_PREFIX = "SiteInfo:"; |
|
||||
private static final String MP_INFO_KEY_PREFIX = "MpInfo:"; |
|
||||
private static final String SELECT_PAYMENT_KEY_PREFIX = "SelectPayment:"; |
|
||||
private static final String SYS_DOMAIN_SUFFIX = ".websoft.top"; |
|
||||
private static final String DOMAIN_SUFFIX = ".wsdns.cn"; |
|
||||
|
|
||||
@Operation(summary = "分页查询网站信息记录表") |
|
||||
@GetMapping("/page") |
|
||||
public ApiResult<PageResult<CmsWebsite>> page(CmsWebsiteParam param) { |
|
||||
// 使用关联查询
|
|
||||
return success(cmsWebsiteService.pageRel(param)); |
|
||||
} |
|
||||
|
@Operation(summary = "查询全部网站信息记录表") |
||||
|
@GetMapping() |
||||
|
public ApiResult<List<CmsWebsite>> list(CmsWebsiteParam param) { |
||||
|
// 使用关联查询
|
||||
|
return success(cmsWebsiteService.listRel(param)); |
||||
|
} |
||||
|
|
||||
@Operation(summary = "查询全部网站信息记录表") |
|
||||
@GetMapping() |
|
||||
public ApiResult<List<CmsWebsite>> list(CmsWebsiteParam param) { |
|
||||
// 使用关联查询
|
|
||||
return success(cmsWebsiteService.listRel(param)); |
|
||||
} |
|
||||
|
@Operation(summary = "分页查询网站信息记录表") |
||||
|
@GetMapping("/pageAll") |
||||
|
public ApiResult<PageResult<CmsWebsite>> pageAll(CmsWebsiteParam param) { |
||||
|
return success(cmsWebsiteService.pageRelAll(param)); |
||||
|
} |
||||
|
|
||||
@Operation(summary = "分页查询网站信息记录表") |
|
||||
@GetMapping("/pageAll") |
|
||||
public ApiResult<PageResult<CmsWebsite>> pageAll(CmsWebsiteParam param) { |
|
||||
return success(cmsWebsiteService.pageRelAll(param)); |
|
||||
} |
|
||||
|
@Operation(summary = "根据id查询网站信息记录表") |
||||
|
@GetMapping("/{id}") |
||||
|
public ApiResult<CmsWebsite> get(@PathVariable("id") Integer id) { |
||||
|
// 使用关联查询
|
||||
|
return success(cmsWebsiteService.getByIdRel(id)); |
||||
|
} |
||||
|
|
||||
@Operation(summary = "根据id查询网站信息记录表") |
|
||||
@GetMapping("/{id}") |
|
||||
public ApiResult<CmsWebsite> get(@PathVariable("id") Integer id) { |
|
||||
// 使用关联查询
|
|
||||
return success(cmsWebsiteService.getByIdRel(id)); |
|
||||
} |
|
||||
|
@Operation(summary = "根据id查询网站信息记录表") |
||||
|
@GetMapping("/getAll/{id}") |
||||
|
public ApiResult<CmsWebsite> getAll(@PathVariable("id") Integer id) { |
||||
|
// 使用关联查询
|
||||
|
return success(cmsWebsiteService.getByIdRelAll(id)); |
||||
|
} |
||||
|
|
||||
@Operation(summary = "根据id查询网站信息记录表") |
|
||||
@GetMapping("/getAll/{id}") |
|
||||
public ApiResult<CmsWebsite> getAll(@PathVariable("id") Integer id) { |
|
||||
// 使用关联查询
|
|
||||
return success(cmsWebsiteService.getByIdRelAll(id)); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:save')") |
||||
|
@Operation(summary = "添加网站信息记录表") |
||||
|
@PostMapping() |
||||
|
public ApiResult<?> save(@RequestBody CmsWebsite cmsWebsite) { |
||||
|
// 记录当前登录用户id
|
||||
|
User loginUser = getLoginUser(); |
||||
|
if (loginUser != null) { |
||||
|
cmsWebsite.setLoginUser(loginUser); |
||||
|
return success("创建成功", cmsWebsiteService.create(cmsWebsite)); |
||||
} |
} |
||||
|
return fail("创建失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:save')") |
|
||||
@Operation(summary = "添加网站信息记录表") |
|
||||
@PostMapping() |
|
||||
public ApiResult<?> save(@RequestBody CmsWebsite cmsWebsite) { |
|
||||
// 记录当前登录用户id
|
|
||||
User loginUser = getLoginUser(); |
|
||||
if (loginUser != null) { |
|
||||
cmsWebsite.setLoginUser(loginUser); |
|
||||
return success("创建成功", cmsWebsiteService.create(cmsWebsite)); |
|
||||
} |
|
||||
return fail("创建失败"); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:update')") |
||||
|
@Operation(summary = "修改网站信息记录表") |
||||
|
@PutMapping() |
||||
|
public ApiResult<?> update(@RequestBody CmsWebsite cmsWebsite) { |
||||
|
if (cmsWebsiteService.updateById(cmsWebsite)) { |
||||
|
return success("修改成功"); |
||||
} |
} |
||||
|
return fail("修改失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:update')") |
|
||||
@Operation(summary = "修改网站信息记录表") |
|
||||
@PutMapping() |
|
||||
public ApiResult<?> update(@RequestBody CmsWebsite cmsWebsite) { |
|
||||
if (cmsWebsiteService.updateById(cmsWebsite)) { |
|
||||
return success("修改成功"); |
|
||||
} |
|
||||
return fail("修改失败"); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:update')") |
||||
|
@Operation(summary = "修改网站信息记录表") |
||||
|
@PutMapping("/updateAll") |
||||
|
public ApiResult<?> updateAll(@RequestBody CmsWebsite cmsWebsite) { |
||||
|
if (cmsWebsiteService.updateByIdAll(cmsWebsite)) { |
||||
|
return success("修改成功"); |
||||
} |
} |
||||
|
return fail("修改失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:update')") |
|
||||
@Operation(summary = "修改网站信息记录表") |
|
||||
@PutMapping("/updateAll") |
|
||||
public ApiResult<?> updateAll(@RequestBody CmsWebsite cmsWebsite) { |
|
||||
if (cmsWebsiteService.updateByIdAll(cmsWebsite)) { |
|
||||
return success("修改成功"); |
|
||||
} |
|
||||
return fail("修改失败"); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:remove')") |
||||
|
@Operation(summary = "删除网站信息记录表") |
||||
|
@DeleteMapping("/{id}") |
||||
|
public ApiResult<?> remove(@PathVariable("id") Integer id) { |
||||
|
if (cmsWebsiteService.removeById(id)) { |
||||
|
return success("删除成功"); |
||||
} |
} |
||||
|
return fail("删除失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:remove')") |
|
||||
@Operation(summary = "删除网站信息记录表") |
|
||||
@DeleteMapping("/{id}") |
|
||||
public ApiResult<?> remove(@PathVariable("id") Integer id) { |
|
||||
if (cmsWebsiteService.removeById(id)) { |
|
||||
return success("删除成功"); |
|
||||
} |
|
||||
return fail("删除失败"); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:remove')") |
||||
|
@Operation(summary = "删除网站信息记录表") |
||||
|
@DeleteMapping("/removeAll/{id}") |
||||
|
public ApiResult<?> removeAll(@PathVariable("id") Integer id) { |
||||
|
if (cmsWebsiteService.removeByIdAll(id)) { |
||||
|
return success("删除成功"); |
||||
} |
} |
||||
|
return fail("删除失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:remove')") |
|
||||
@Operation(summary = "删除网站信息记录表") |
|
||||
@DeleteMapping("/removeAll/{id}") |
|
||||
public ApiResult<?> removeAll(@PathVariable("id") Integer id) { |
|
||||
if (cmsWebsiteService.removeByIdAll(id)) { |
|
||||
return success("删除成功"); |
|
||||
} |
|
||||
return fail("删除失败"); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:save')") |
||||
|
@Operation(summary = "批量添加网站信息记录表") |
||||
|
@PostMapping("/batch") |
||||
|
public ApiResult<?> saveBatch(@RequestBody List<CmsWebsite> list) { |
||||
|
if (cmsWebsiteService.saveBatch(list)) { |
||||
|
return success("添加成功"); |
||||
} |
} |
||||
|
return fail("添加失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:save')") |
|
||||
@Operation(summary = "批量添加网站信息记录表") |
|
||||
@PostMapping("/batch") |
|
||||
public ApiResult<?> saveBatch(@RequestBody List<CmsWebsite> list) { |
|
||||
if (cmsWebsiteService.saveBatch(list)) { |
|
||||
return success("添加成功"); |
|
||||
} |
|
||||
return fail("添加失败"); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:update')") |
||||
|
@Operation(summary = "批量修改网站信息记录表") |
||||
|
@PutMapping("/batch") |
||||
|
public ApiResult<?> removeBatch(@RequestBody BatchParam<CmsWebsite> batchParam) { |
||||
|
if (batchParam.update(cmsWebsiteService, "website_id")) { |
||||
|
return success("修改成功"); |
||||
} |
} |
||||
|
return fail("修改失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:update')") |
|
||||
@Operation(summary = "批量修改网站信息记录表") |
|
||||
@PutMapping("/batch") |
|
||||
public ApiResult<?> removeBatch(@RequestBody BatchParam<CmsWebsite> batchParam) { |
|
||||
if (batchParam.update(cmsWebsiteService, "website_id")) { |
|
||||
return success("修改成功"); |
|
||||
} |
|
||||
return fail("修改失败"); |
|
||||
|
@PreAuthorize("hasAuthority('cms:website:remove')") |
||||
|
@Operation(summary = "批量删除网站信息记录表") |
||||
|
@DeleteMapping("/batch") |
||||
|
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) { |
||||
|
if (cmsWebsiteService.removeByIds(ids)) { |
||||
|
return success("删除成功"); |
||||
} |
} |
||||
|
return fail("删除失败"); |
||||
|
} |
||||
|
|
||||
@PreAuthorize("hasAuthority('cms:website:remove')") |
|
||||
@Operation(summary = "批量删除网站信息记录表") |
|
||||
@DeleteMapping("/batch") |
|
||||
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) { |
|
||||
if (cmsWebsiteService.removeByIds(ids)) { |
|
||||
return success("删除成功"); |
|
||||
|
@Operation(summary = "网站基本信息") |
||||
|
@GetMapping("/getSiteInfo") |
||||
|
public ApiResult<CmsWebsite> getSiteInfo() { |
||||
|
try { |
||||
|
Integer tenantId = getTenantId(); |
||||
|
if (ObjectUtil.isEmpty(tenantId)) { |
||||
|
return fail("租户ID不能为空", null); |
||||
} |
} |
||||
return fail("删除失败"); |
|
||||
} |
|
||||
|
|
||||
@Operation(summary = "网站基本信息") |
|
||||
@GetMapping("/getSiteInfo") |
|
||||
public ApiResult<CmsWebsite> getSiteInfo() { |
|
||||
if (ObjectUtil.isEmpty(getTenantId())) { |
|
||||
return fail("参数不正确", null); |
|
||||
} |
|
||||
|
String key = SITE_INFO_KEY_PREFIX + tenantId; |
||||
|
|
||||
String key = SITE_INFO_KEY_PREFIX + getTenantId(); |
|
||||
final String siteInfo = redisUtil.get(key); |
|
||||
if (StrUtil.isNotBlank(siteInfo)) { |
|
||||
log.info("从缓存获取网站信息: = {}", key); |
|
||||
// return success(JSONUtil.parseObject(siteInfo, CmsWebsite.class));
|
|
||||
|
// 尝试从缓存获取
|
||||
|
try { |
||||
|
final String siteInfo = redisUtil.get(key); |
||||
|
if (StrUtil.isNotBlank(siteInfo)) { |
||||
|
log.info("从缓存获取网站信息: = {}", key); |
||||
|
// 可以启用缓存返回,但先注释掉确保数据最新
|
||||
|
// return success(JSONUtil.parseObject(siteInfo, CmsWebsite.class));
|
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.warn("获取缓存失败: {}", e.getMessage()); |
||||
} |
} |
||||
|
|
||||
// 获取站点信息
|
// 获取站点信息
|
||||
CmsWebsite website = cmsWebsiteService.getOne(new LambdaQueryWrapper<CmsWebsite>().eq(CmsWebsite::getDeleted, 0).last("limit 1")); |
|
||||
|
CmsWebsite website = null; |
||||
|
try { |
||||
|
website = cmsWebsiteService.getOne(new LambdaQueryWrapper<CmsWebsite>() |
||||
|
.eq(CmsWebsite::getTenantId, tenantId) |
||||
|
.eq(CmsWebsite::getDeleted, 0) |
||||
|
.last("limit 1")); |
||||
|
} catch (Exception e) { |
||||
|
log.error("查询站点信息失败: {}", e.getMessage(), e); |
||||
|
return fail("查询站点信息失败", null); |
||||
|
} |
||||
|
|
||||
// 创建默认站点
|
// 创建默认站点
|
||||
if (ObjectUtil.isEmpty(website)) { |
if (ObjectUtil.isEmpty(website)) { |
||||
return success("请先创建站点...", null); |
return success("请先创建站点...", null); |
||||
} |
} |
||||
|
|
||||
// 站点异常状态
|
|
||||
|
// 安全地构建网站信息
|
||||
|
try { |
||||
|
buildSafeWebsiteInfo(website); |
||||
|
} catch (Exception e) { |
||||
|
log.error("构建网站信息失败: {}", e.getMessage(), e); |
||||
|
return fail("构建网站信息失败", null); |
||||
|
} |
||||
|
|
||||
|
// 缓存结果
|
||||
|
try { |
||||
|
redisUtil.set(key, website, 1L, TimeUnit.DAYS); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("缓存网站信息失败: {}", e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
return success(website); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("获取网站信息异常: {}", e.getMessage(), e); |
||||
|
return fail("获取网站信息失败: " + e.getMessage(), null); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 安全地构建网站信息 |
||||
|
*/ |
||||
|
private void buildSafeWebsiteInfo(CmsWebsite website) { |
||||
|
if (website == null) { |
||||
|
throw new IllegalArgumentException("网站对象不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 1. 设置网站状态
|
||||
|
try { |
||||
setWebsiteStatus(website); |
setWebsiteStatus(website); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("设置网站状态失败: {}", e.getMessage()); |
||||
|
website.setStatus(0); // 默认状态
|
||||
|
website.setStatusText("状态未知"); |
||||
|
} |
||||
|
|
||||
// 站点配置参数
|
|
||||
HashMap<String, Object> config = buildWebsiteConfig(website); |
|
||||
|
// 2. 构建配置信息
|
||||
|
try { |
||||
|
HashMap<String, Object> config = buildSafeWebsiteConfig(website); |
||||
website.setConfig(config); |
website.setConfig(config); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("构建网站配置失败: {}", e.getMessage()); |
||||
|
website.setConfig(new HashMap<>()); |
||||
|
} |
||||
|
|
||||
// 网站导航
|
|
||||
setWebsiteNavigation(website); |
|
||||
|
// 3. 设置导航信息
|
||||
|
try { |
||||
|
setSafeWebsiteNavigation(website); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("设置网站导航失败: {}", e.getMessage()); |
||||
|
website.setTopNavs(new ArrayList<>()); |
||||
|
website.setBottomNavs(new ArrayList<>()); |
||||
|
} |
||||
|
|
||||
// 网站设置信息
|
|
||||
|
// 4. 设置网站设置信息
|
||||
|
try { |
||||
setWebsiteSetting(website); |
setWebsiteSetting(website); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("设置网站设置失败: {}", e.getMessage()); |
||||
|
// 设置为null,让前端知道没有设置信息
|
||||
|
} |
||||
|
|
||||
// 服务器时间
|
|
||||
HashMap<String, Object> serverTime = buildServerTime(); |
|
||||
|
// 5. 构建服务器时间(使用LocalDateTime)
|
||||
|
try { |
||||
|
HashMap<String, Object> serverTime = buildSafeServerTime(); |
||||
website.setServerTime(serverTime); |
website.setServerTime(serverTime); |
||||
|
|
||||
// 即将过期(一周内过期的)
|
|
||||
website.setSoon(DateUtil.offsetDay(website.getExpirationTime(), -30).compareTo(DateUtil.date())); |
|
||||
// 是否过期 -1已过期 大于0 未过期
|
|
||||
website.setExpired(website.getExpirationTime().compareTo(DateUtil.date())); |
|
||||
// 剩余天数
|
|
||||
website.setExpiredDays(DateUtil.betweenDay(website.getExpirationTime(), DateUtil.date(), false)); |
|
||||
|
|
||||
redisUtil.set(key, website, 1L, TimeUnit.DAYS); |
|
||||
return success(website); |
|
||||
|
} catch (Exception e) { |
||||
|
log.warn("构建服务器时间失败: {}", e.getMessage()); |
||||
|
HashMap<String, Object> defaultTime = new HashMap<>(); |
||||
|
defaultTime.put("now", java.time.LocalDateTime.now().toString()); |
||||
|
website.setServerTime(defaultTime); |
||||
} |
} |
||||
|
} |
||||
|
|
||||
private void setWebsiteStatus(CmsWebsite website) { |
|
||||
if (!website.getRunning().equals(1)) { |
|
||||
// 未开通
|
|
||||
if (website.getRunning().equals(0)) { |
|
||||
website.setStatusIcon("error"); |
|
||||
website.setStatusText("该站点未开通"); |
|
||||
} |
|
||||
// 维护中
|
|
||||
if (website.getRunning().equals(2)) { |
|
||||
website.setStatusIcon("warning"); |
|
||||
} |
|
||||
// 已关闭
|
|
||||
if (website.getRunning().equals(3)) { |
|
||||
website.setStatusIcon("error"); |
|
||||
website.setStatusText("已关闭"); |
|
||||
} |
|
||||
// 已欠费停机
|
|
||||
if (website.getRunning().equals(4)) { |
|
||||
website.setStatusIcon("error"); |
|
||||
website.setStatusText("已欠费停机"); |
|
||||
} |
|
||||
// 违规关停
|
|
||||
if (website.getRunning().equals(5)) { |
|
||||
website.setStatusIcon("error"); |
|
||||
website.setStatusText("违规关停"); |
|
||||
} |
|
||||
|
private void setWebsiteStatus(CmsWebsite website) { |
||||
|
if (!website.getRunning().equals(1)) { |
||||
|
// 未开通
|
||||
|
if (website.getRunning().equals(0)) { |
||||
|
website.setStatusIcon("error"); |
||||
|
website.setStatusText("该站点未开通"); |
||||
|
} |
||||
|
// 维护中
|
||||
|
if (website.getRunning().equals(2)) { |
||||
|
website.setStatusIcon("warning"); |
||||
|
} |
||||
|
// 已关闭
|
||||
|
if (website.getRunning().equals(3)) { |
||||
|
website.setStatusIcon("error"); |
||||
|
website.setStatusText("已关闭"); |
||||
|
} |
||||
|
// 已欠费停机
|
||||
|
if (website.getRunning().equals(4)) { |
||||
|
website.setStatusIcon("error"); |
||||
|
website.setStatusText("已欠费停机"); |
||||
|
} |
||||
|
// 违规关停
|
||||
|
if (website.getRunning().equals(5)) { |
||||
|
website.setStatusIcon("error"); |
||||
|
website.setStatusText("违规关停"); |
||||
} |
} |
||||
} |
} |
||||
|
} |
||||
|
|
||||
|
private HashMap<String, Object> buildWebsiteConfig(CmsWebsite website) { |
||||
|
return buildSafeWebsiteConfig(website); |
||||
|
} |
||||
|
|
||||
|
private HashMap<String, Object> buildSafeWebsiteConfig(CmsWebsite website) { |
||||
|
HashMap<String, Object> config = new HashMap<>(); |
||||
|
|
||||
private HashMap<String, Object> buildWebsiteConfig(CmsWebsite website) { |
|
||||
HashMap<String, Object> config = new HashMap<>(); |
|
||||
|
try { |
||||
|
// 获取网站字段配置
|
||||
LambdaQueryWrapper<CmsWebsiteField> wrapper = new LambdaQueryWrapper<>(); |
LambdaQueryWrapper<CmsWebsiteField> wrapper = new LambdaQueryWrapper<>(); |
||||
wrapper.eq(CmsWebsiteField::getDeleted, 0); |
wrapper.eq(CmsWebsiteField::getDeleted, 0); |
||||
final List<CmsWebsiteField> fields = cmsWebsiteFieldService.list(wrapper); |
final List<CmsWebsiteField> fields = cmsWebsiteFieldService.list(wrapper); |
||||
fields.forEach(d -> { |
|
||||
config.put(d.getName(), d.getValue()); |
|
||||
}); |
|
||||
config.put("SysDomain", getSysDomain(website)); |
|
||||
config.put("Domain", getDomain(website)); |
|
||||
return config; |
|
||||
|
|
||||
|
if (fields != null && !fields.isEmpty()) { |
||||
|
fields.forEach(field -> { |
||||
|
if (field != null && StrUtil.isNotBlank(field.getName())) { |
||||
|
config.put(field.getName(), field.getValue() != null ? field.getValue() : ""); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.warn("获取网站字段配置失败: {}", e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
// 安全地设置域名信息
|
||||
|
try { |
||||
|
config.put("SysDomain", getSafeSysDomain(website)); |
||||
|
config.put("Domain", getSafeDomain(website)); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("设置域名信息失败: {}", e.getMessage()); |
||||
|
config.put("SysDomain", website.getTenantId() + ".websoft.top"); |
||||
|
config.put("Domain", website.getTenantId() + ".wsdns.cn"); |
||||
|
} |
||||
|
|
||||
|
return config; |
||||
|
} |
||||
|
|
||||
|
private String getSysDomain(CmsWebsite website) { |
||||
|
return getSafeSysDomain(website); |
||||
|
} |
||||
|
|
||||
|
private String getDomain(CmsWebsite website) { |
||||
|
return getSafeDomain(website); |
||||
|
} |
||||
|
|
||||
|
private String getSafeSysDomain(CmsWebsite website) { |
||||
|
if (website == null || website.getTenantId() == null) { |
||||
|
return "unknown.websoft.top"; |
||||
|
} |
||||
|
return StrUtil.isNotBlank(website.getWebsiteCode()) ? |
||||
|
website.getWebsiteCode() + SYS_DOMAIN_SUFFIX : |
||||
|
website.getTenantId() + SYS_DOMAIN_SUFFIX; |
||||
|
} |
||||
|
|
||||
|
private String getSafeDomain(CmsWebsite website) { |
||||
|
if (website == null || website.getTenantId() == null) { |
||||
|
return "unknown.wsdns.cn"; |
||||
} |
} |
||||
|
|
||||
private String getSysDomain(CmsWebsite website) { |
|
||||
return StrUtil.isNotBlank(website.getWebsiteCode()) ? website.getWebsiteCode() + SYS_DOMAIN_SUFFIX : website.getTenantId() + SYS_DOMAIN_SUFFIX; |
|
||||
|
if (StrUtil.isNotBlank(website.getDomain())) { |
||||
|
return website.getDomain(); |
||||
|
} |
||||
|
if (StrUtil.isNotBlank(website.getWebsiteCode())) { |
||||
|
return website.getWebsiteCode() + DOMAIN_SUFFIX; |
||||
} |
} |
||||
|
return website.getTenantId() + DOMAIN_SUFFIX; |
||||
|
} |
||||
|
|
||||
private String getDomain(CmsWebsite website) { |
|
||||
return StrUtil.isNotBlank(website.getDomain()) ? website.getDomain() : website.getWebsiteCode() + DOMAIN_SUFFIX; |
|
||||
|
private void setWebsiteNavigation(CmsWebsite website) { |
||||
|
setSafeWebsiteNavigation(website); |
||||
|
} |
||||
|
|
||||
|
private void setSafeWebsiteNavigation(CmsWebsite website) { |
||||
|
if (website == null) { |
||||
|
return; |
||||
} |
} |
||||
|
|
||||
private void setWebsiteNavigation(CmsWebsite website) { |
|
||||
final CmsNavigationParam navigationParam = new CmsNavigationParam(); |
|
||||
navigationParam.setHide(0); |
|
||||
navigationParam.setTop(0); |
|
||||
navigationParam.setBottom(null); |
|
||||
final List<CmsNavigation> topNavs = cmsNavigationService.listRel(navigationParam); |
|
||||
// 顶部菜单
|
|
||||
website.setTopNavs(CommonUtil.toTreeData(topNavs, 0, CmsNavigation::getParentId, CmsNavigation::getNavigationId, CmsNavigation::setChildren)); |
|
||||
navigationParam.setTop(null); |
|
||||
navigationParam.setBottom(0); |
|
||||
final List<CmsNavigation> bottomNavs = cmsNavigationService.listRel(navigationParam); |
|
||||
// 底部菜单
|
|
||||
website.setBottomNavs(CommonUtil.toTreeData(bottomNavs, 0, CmsNavigation::getParentId, CmsNavigation::getNavigationId, CmsNavigation::setChildren)); |
|
||||
|
// 设置顶部导航
|
||||
|
try { |
||||
|
final CmsNavigationParam topParam = new CmsNavigationParam(); |
||||
|
topParam.setHide(0); |
||||
|
topParam.setTop(0); |
||||
|
topParam.setBottom(null); |
||||
|
final List<CmsNavigation> topNavs = cmsNavigationService.listRel(topParam); |
||||
|
|
||||
|
if (topNavs != null && !topNavs.isEmpty()) { |
||||
|
try { |
||||
|
website.setTopNavs(CommonUtil.toTreeData(topNavs, 0, |
||||
|
CmsNavigation::getParentId, |
||||
|
CmsNavigation::getNavigationId, |
||||
|
CmsNavigation::setChildren)); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("构建顶部导航树失败: {}", e.getMessage()); |
||||
|
website.setTopNavs(new ArrayList<>(topNavs)); |
||||
|
} |
||||
|
} else { |
||||
|
website.setTopNavs(new ArrayList<>()); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.warn("获取顶部导航失败: {}", e.getMessage()); |
||||
|
website.setTopNavs(new ArrayList<>()); |
||||
} |
} |
||||
|
|
||||
private void setWebsiteSetting(CmsWebsite website) { |
|
||||
final CmsWebsiteSetting setting = cmsWebsiteSettingService.getOne(new LambdaQueryWrapper<CmsWebsiteSetting>().eq(CmsWebsiteSetting::getWebsiteId, website.getWebsiteId())); |
|
||||
if (ObjectUtil.isNotEmpty(setting)) { |
|
||||
website.setSetting(setting); |
|
||||
|
// 设置底部导航
|
||||
|
try { |
||||
|
final CmsNavigationParam bottomParam = new CmsNavigationParam(); |
||||
|
bottomParam.setHide(0); |
||||
|
bottomParam.setTop(null); |
||||
|
bottomParam.setBottom(0); |
||||
|
final List<CmsNavigation> bottomNavs = cmsNavigationService.listRel(bottomParam); |
||||
|
|
||||
|
if (bottomNavs != null && !bottomNavs.isEmpty()) { |
||||
|
try { |
||||
|
website.setBottomNavs(CommonUtil.toTreeData(bottomNavs, 0, |
||||
|
CmsNavigation::getParentId, |
||||
|
CmsNavigation::getNavigationId, |
||||
|
CmsNavigation::setChildren)); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("构建底部导航树失败: {}", e.getMessage()); |
||||
|
website.setBottomNavs(new ArrayList<>(bottomNavs)); |
||||
|
} |
||||
|
} else { |
||||
|
website.setBottomNavs(new ArrayList<>()); |
||||
} |
} |
||||
|
} catch (Exception e) { |
||||
|
log.warn("获取底部导航失败: {}", e.getMessage()); |
||||
|
website.setBottomNavs(new ArrayList<>()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void setWebsiteSetting(CmsWebsite website) { |
||||
|
final CmsWebsiteSetting setting = cmsWebsiteSettingService.getOne(new LambdaQueryWrapper<CmsWebsiteSetting>().eq(CmsWebsiteSetting::getWebsiteId, website.getWebsiteId())); |
||||
|
if (ObjectUtil.isNotEmpty(setting)) { |
||||
|
website.setSetting(setting); |
||||
} |
} |
||||
|
} |
||||
|
|
||||
|
private HashMap<String, Object> buildServerTime() { |
||||
|
return buildSafeServerTime(); |
||||
|
} |
||||
|
|
||||
|
private HashMap<String, Object> buildSafeServerTime() { |
||||
|
HashMap<String, Object> serverTime = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
// 使用 LocalDateTime 替代 DateTime
|
||||
|
java.time.LocalDateTime now = java.time.LocalDateTime.now(); |
||||
|
java.time.LocalDate today = java.time.LocalDate.now(); |
||||
|
|
||||
|
// 当前时间
|
||||
|
serverTime.put("now", now.toString()); |
||||
|
|
||||
private HashMap<String, Object> buildServerTime() { |
|
||||
HashMap<String, Object> serverTime = new HashMap<>(); |
|
||||
// 今天日期
|
// 今天日期
|
||||
DateTime date = DateUtil.date(); |
|
||||
String today = DateUtil.today(); |
|
||||
|
serverTime.put("today", today.toString()); |
||||
|
|
||||
// 明天日期
|
// 明天日期
|
||||
final DateTime dateTime = DateUtil.tomorrow(); |
|
||||
String tomorrow = DateUtil.format(dateTime, "yyyy-MM-dd"); |
|
||||
|
java.time.LocalDate tomorrow = today.plusDays(1); |
||||
|
serverTime.put("tomorrow", tomorrow.toString()); |
||||
|
|
||||
// 后天日期
|
// 后天日期
|
||||
final DateTime dateTime2 = DateUtil.offsetDay(date, 2); |
|
||||
final String afterDay = DateUtil.format(dateTime2, "yyyy-MM-dd"); |
|
||||
// 今天星期几
|
|
||||
final int week = DateUtil.thisDayOfWeek(); |
|
||||
final DateTime nextWeek = DateUtil.nextWeek(); |
|
||||
serverTime.put("now", DateUtil.now()); |
|
||||
serverTime.put("today", today); |
|
||||
serverTime.put("tomorrow", tomorrow); |
|
||||
serverTime.put("afterDay", afterDay); |
|
||||
|
java.time.LocalDate afterDay = today.plusDays(2); |
||||
|
serverTime.put("afterDay", afterDay.toString()); |
||||
|
|
||||
|
// 今天星期几 (1=Monday, 7=Sunday)
|
||||
|
int week = today.getDayOfWeek().getValue(); |
||||
serverTime.put("week", week); |
serverTime.put("week", week); |
||||
serverTime.put("nextWeek", nextWeek); |
|
||||
return serverTime; |
|
||||
} |
|
||||
|
|
||||
@Operation(summary = "清除缓存") |
|
||||
@DeleteMapping("/clearSiteInfo/{key}") |
|
||||
public ApiResult<?> clearSiteInfo(@PathVariable("key") String key) { |
|
||||
// 清除指定key
|
|
||||
redisUtil.delete(key); |
|
||||
// 清除缓存
|
|
||||
redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); |
|
||||
// 清除小程序缓存
|
|
||||
redisUtil.delete(MP_INFO_KEY_PREFIX.concat(getTenantId().toString())); |
|
||||
// 选择支付方式
|
|
||||
redisUtil.delete(SELECT_PAYMENT_KEY_PREFIX.concat(getTenantId().toString())); |
|
||||
return success("清除成功"); |
|
||||
|
// 下周同一天
|
||||
|
java.time.LocalDate nextWeek = today.plusWeeks(1); |
||||
|
serverTime.put("nextWeek", nextWeek.toString()); |
||||
|
|
||||
|
// 时间戳
|
||||
|
serverTime.put("timestamp", System.currentTimeMillis()); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("构建服务器时间失败: {}", e.getMessage(), e); |
||||
|
// 提供最基本的时间信息
|
||||
|
serverTime.put("now", java.time.LocalDateTime.now().toString()); |
||||
|
serverTime.put("today", java.time.LocalDate.now().toString()); |
||||
|
serverTime.put("timestamp", System.currentTimeMillis()); |
||||
} |
} |
||||
|
|
||||
|
return serverTime; |
||||
} |
} |
||||
|
|
||||
|
@Operation(summary = "清除缓存") |
||||
|
@DeleteMapping("/clearSiteInfo/{key}") |
||||
|
public ApiResult<?> clearSiteInfo(@PathVariable("key") String key) { |
||||
|
// 清除指定key
|
||||
|
redisUtil.delete(key); |
||||
|
// 清除缓存
|
||||
|
redisUtil.delete(SITE_INFO_KEY_PREFIX.concat(getTenantId().toString())); |
||||
|
// 清除小程序缓存
|
||||
|
redisUtil.delete(MP_INFO_KEY_PREFIX.concat(getTenantId().toString())); |
||||
|
// 选择支付方式
|
||||
|
redisUtil.delete(SELECT_PAYMENT_KEY_PREFIX.concat(getTenantId().toString())); |
||||
|
return success("清除成功"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
@ -1,55 +0,0 @@ |
|||||
package com.gxwebsoft.cms.vo; |
|
||||
|
|
||||
import io.swagger.v3.oas.annotations.media.Schema; |
|
||||
import lombok.Data; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.util.List; |
|
||||
|
|
||||
/** |
|
||||
* 导航信息视图对象 |
|
||||
* 专门用于前端展示,只包含前端需要的字段 |
|
||||
* |
|
||||
* @author WebSoft |
|
||||
* @since 2025-01-12 |
|
||||
*/ |
|
||||
@Data |
|
||||
@Schema(description = "导航信息视图对象") |
|
||||
public class CmsNavigationVO implements Serializable { |
|
||||
|
|
||||
@Schema(description = "导航ID") |
|
||||
private Integer navigationId; |
|
||||
|
|
||||
@Schema(description = "导航名称") |
|
||||
private String navigationName; |
|
||||
|
|
||||
@Schema(description = "导航链接") |
|
||||
private String navigationUrl; |
|
||||
|
|
||||
@Schema(description = "导航图标") |
|
||||
private String navigationIcon; |
|
||||
|
|
||||
@Schema(description = "导航颜色") |
|
||||
private String navigationColor; |
|
||||
|
|
||||
@Schema(description = "父级ID") |
|
||||
private Integer parentId; |
|
||||
|
|
||||
@Schema(description = "排序") |
|
||||
private Integer sort; |
|
||||
|
|
||||
@Schema(description = "是否隐藏 0显示 1隐藏") |
|
||||
private Integer hide; |
|
||||
|
|
||||
@Schema(description = "位置 0顶部 1底部") |
|
||||
private Integer top; |
|
||||
|
|
||||
@Schema(description = "打开方式 0当前窗口 1新窗口") |
|
||||
private Integer target; |
|
||||
|
|
||||
@Schema(description = "导航类型") |
|
||||
private String navigationType; |
|
||||
|
|
||||
@Schema(description = "子导航") |
|
||||
private List<CmsNavigationVO> children; |
|
||||
} |
|
@ -1,93 +0,0 @@ |
|||||
package com.gxwebsoft.cms.vo; |
|
||||
|
|
||||
import io.swagger.v3.oas.annotations.media.Schema; |
|
||||
import lombok.Data; |
|
||||
|
|
||||
import java.io.Serializable; |
|
||||
import java.time.LocalDateTime; |
|
||||
import java.util.HashMap; |
|
||||
import java.util.List; |
|
||||
|
|
||||
/** |
|
||||
* 应用信息 |
|
||||
* 专门用于前端展示,只包含前端需要的字段 |
|
||||
* |
|
||||
* @author WebSoft |
|
||||
* @since 2025-01-12 |
|
||||
*/ |
|
||||
@Data |
|
||||
@Schema(description = "应用信息视图对象") |
|
||||
public class CmsVO implements Serializable { |
|
||||
|
|
||||
@Schema(description = "应用ID") |
|
||||
private Integer appId; |
|
||||
|
|
||||
@Schema(description = "应用名称") |
|
||||
private String appName; |
|
||||
|
|
||||
@Schema(description = "应用介绍") |
|
||||
private String description; |
|
||||
|
|
||||
@Schema(description = "网站关键词") |
|
||||
private String keywords; |
|
||||
|
|
||||
@Schema(description = "应用编号") |
|
||||
private String appCode; |
|
||||
|
|
||||
@Schema(description = "小程序二维码") |
|
||||
private String mpQrCode; |
|
||||
|
|
||||
@Schema(description = "标题") |
|
||||
private String title; |
|
||||
|
|
||||
@Schema(description = "LOGO") |
|
||||
private String logo; |
|
||||
|
|
||||
@Schema(description = "图标") |
|
||||
private String icon; |
|
||||
|
|
||||
@Schema(description = "域名") |
|
||||
private String domain; |
|
||||
|
|
||||
@Schema(description = "运行状态 0未开通 1正常 2维护中 3违规关停") |
|
||||
private Integer running; |
|
||||
|
|
||||
@Schema(description = "应用版本 10免费版 20授权版 30永久授权") |
|
||||
private Integer version; |
|
||||
|
|
||||
@Schema(description = "服务到期时间") |
|
||||
private String expirationTime; |
|
||||
|
|
||||
@Schema(description = "创建时间") |
|
||||
private String createTime; |
|
||||
|
|
||||
@Schema(description = "是否到期 -1已过期 1未过期") |
|
||||
private Integer expired; |
|
||||
|
|
||||
@Schema(description = "剩余天数") |
|
||||
private Long expiredDays; |
|
||||
|
|
||||
@Schema(description = "即将过期 0否 1是") |
|
||||
private Integer soon; |
|
||||
|
|
||||
@Schema(description = "状态图标") |
|
||||
private String statusIcon; |
|
||||
|
|
||||
@Schema(description = "状态文本") |
|
||||
private String statusText; |
|
||||
|
|
||||
@Schema(description = "网站配置") |
|
||||
private Object config; |
|
||||
|
|
||||
@Schema(description = "服务器时间信息") |
|
||||
private HashMap<String, Object> serverTime; |
|
||||
|
|
||||
@Schema(description = "顶部导航") |
|
||||
private List<CmsNavigationVO> topNavs; |
|
||||
|
|
||||
@Schema(description = "底部导航") |
|
||||
private List<CmsNavigationVO> bottomNavs; |
|
||||
|
|
||||
@Schema(description = "网站设置") |
|
||||
private Object setting; |
|
||||
} |
|
@ -0,0 +1,27 @@ |
|||||
|
package com.gxwebsoft.shop.service; |
||||
|
|
||||
|
import com.gxwebsoft.shop.vo.ShopVo; |
||||
|
|
||||
|
/** |
||||
|
* 商城网站服务接口 |
||||
|
* |
||||
|
* @author 科技小王子 |
||||
|
* @since 2025-08-13 |
||||
|
*/ |
||||
|
public interface ShopWebsiteService { |
||||
|
|
||||
|
/** |
||||
|
* 获取商城基本信息(VO格式) |
||||
|
* |
||||
|
* @param tenantId 租户ID |
||||
|
* @return 商城信息VO |
||||
|
*/ |
||||
|
ShopVo getShopInfo(Integer tenantId); |
||||
|
|
||||
|
/** |
||||
|
* 清除商城信息缓存 |
||||
|
* |
||||
|
* @param tenantId 租户ID |
||||
|
*/ |
||||
|
void clearShopInfoCache(Integer tenantId); |
||||
|
} |
@ -0,0 +1,86 @@ |
|||||
|
package com.gxwebsoft.shop.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.util.ObjectUtil; |
||||
|
import cn.hutool.core.util.StrUtil; |
||||
|
import com.gxwebsoft.cms.entity.CmsWebsite; |
||||
|
import com.gxwebsoft.cms.service.CmsWebsiteService; |
||||
|
import com.gxwebsoft.cms.service.impl.CmsWebsiteServiceImplHelper; |
||||
|
import com.gxwebsoft.common.core.utils.JSONUtil; |
||||
|
import com.gxwebsoft.common.core.utils.RedisUtil; |
||||
|
import com.gxwebsoft.shop.service.ShopWebsiteService; |
||||
|
import com.gxwebsoft.shop.vo.ShopVo; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* 商城网站服务实现类 |
||||
|
* |
||||
|
* @author 科技小王子 |
||||
|
* @since 2025-08-13 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class ShopWebsiteServiceImpl implements ShopWebsiteService { |
||||
|
|
||||
|
@Autowired |
||||
|
private CmsWebsiteService cmsWebsiteService; |
||||
|
|
||||
|
@Autowired |
||||
|
private RedisUtil redisUtil; |
||||
|
|
||||
|
/** |
||||
|
* 商城信息缓存键前缀 |
||||
|
*/ |
||||
|
private static final String SHOP_INFO_KEY_PREFIX = "shop_info:"; |
||||
|
|
||||
|
@Override |
||||
|
public ShopVo getShopInfo(Integer tenantId) { |
||||
|
// 参数验证
|
||||
|
if (ObjectUtil.isEmpty(tenantId)) { |
||||
|
throw new IllegalArgumentException("租户ID不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 商城专用缓存键
|
||||
|
String cacheKey = SHOP_INFO_KEY_PREFIX + tenantId; |
||||
|
String shopInfo = redisUtil.get(cacheKey); |
||||
|
if (StrUtil.isNotBlank(shopInfo)) { |
||||
|
log.info("从缓存获取商城信息,租户ID: {}", tenantId); |
||||
|
try { |
||||
|
return JSONUtil.parseObject(shopInfo, ShopVo.class); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("商城缓存解析失败,从数据库重新获取: {}", e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 直接调用 CMS 服务获取站点信息,然后使用商城专用缓存
|
||||
|
ShopVo shopVO = cmsWebsiteService.getSiteInfo(tenantId); |
||||
|
|
||||
|
if (shopVO == null) { |
||||
|
throw new RuntimeException("请先创建商城"); |
||||
|
} |
||||
|
|
||||
|
// 缓存结果(商城信息缓存时间设置为12小时)
|
||||
|
try { |
||||
|
redisUtil.set(cacheKey, shopVO, 12L, TimeUnit.HOURS); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("缓存商城信息失败: {}", e.getMessage()); |
||||
|
} |
||||
|
|
||||
|
log.info("获取商城信息成功,租户ID: {}", tenantId); |
||||
|
return shopVO; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void clearShopInfoCache(Integer tenantId) { |
||||
|
if (tenantId != null) { |
||||
|
String cacheKey = SHOP_INFO_KEY_PREFIX + tenantId; |
||||
|
redisUtil.delete(cacheKey); |
||||
|
log.info("清除商城信息缓存成功,租户ID: {}", tenantId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
Loading…
Reference in new issue