docs: 添加商城信息重构和网站信息接口重新设计文档

- 新增《商城信息获取方法重构说明》文档,详细介绍了商城信息获取服务的独立和重构过程
- 新增《getSiteInfo 接口重新设计 - 彻底解决空值异常》文档,详细说明了网站信息接口的重新设计和改进
- 更新了《VO模式解决方案》、《最终修复完成-编译错误解决》和《重构总结-Service层架构》等文档
- 修改了 CmsMainController 的导入信息
This commit is contained in:
2025-08-13 14:20:55 +08:00
parent a5eed3e2bb
commit 14ceffe84f
15 changed files with 915 additions and 468 deletions

View File

@@ -1,11 +1,7 @@
package com.gxwebsoft.cms.controller;
import cn.hutool.core.util.ObjectUtil;
import com.gxwebsoft.cms.service.CmsWebsiteService;
import com.gxwebsoft.cms.vo.CmsVO;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

View File

@@ -1,341 +1,524 @@
package com.gxwebsoft.cms.controller;
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 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.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import java.util.*;
/**
* 网站信息记录表控制器
*
* @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;
import java.util.concurrent.TimeUnit;
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";
/**
* 网站信息记录表控制器
*
* @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;
@Operation(summary = "分页查询网站信息记录表")
@GetMapping("/page")
public ApiResult<PageResult<CmsWebsite>> page(CmsWebsiteParam param) {
// 使用关联查询
return success(cmsWebsiteService.pageRel(param));
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("/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("/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("创建失败");
}
@Operation(summary = "查询全部网站信息记录表")
@GetMapping()
public ApiResult<List<CmsWebsite>> list(CmsWebsiteParam param) {
// 使用关联查询
return success(cmsWebsiteService.listRel(param));
@PreAuthorize("hasAuthority('cms:website:update')")
@Operation(summary = "修改网站信息记录表")
@PutMapping()
public ApiResult<?> update(@RequestBody CmsWebsite cmsWebsite) {
if (cmsWebsiteService.updateById(cmsWebsite)) {
return success("修改成功");
}
return fail("修改失败");
}
@Operation(summary = "分页查询网站信息记录表")
@GetMapping("/pageAll")
public ApiResult<PageResult<CmsWebsite>> pageAll(CmsWebsiteParam param) {
return success(cmsWebsiteService.pageRelAll(param));
@PreAuthorize("hasAuthority('cms:website:update')")
@Operation(summary = "修改网站信息记录表")
@PutMapping("/updateAll")
public ApiResult<?> updateAll(@RequestBody CmsWebsite cmsWebsite) {
if (cmsWebsiteService.updateByIdAll(cmsWebsite)) {
return success("修改成功");
}
return fail("修改失败");
}
@Operation(summary = "根据id查询网站信息记录表")
@GetMapping("/{id}")
public ApiResult<CmsWebsite> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(cmsWebsiteService.getByIdRel(id));
@PreAuthorize("hasAuthority('cms:website:remove')")
@Operation(summary = "删除网站信息记录表")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (cmsWebsiteService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
@Operation(summary = "根据id查询网站信息记录表")
@GetMapping("/getAll/{id}")
public ApiResult<CmsWebsite> getAll(@PathVariable("id") Integer id) {
// 使用关联查询
return success(cmsWebsiteService.getByIdRelAll(id));
@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()
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("/batch")
public ApiResult<?> saveBatch(@RequestBody List<CmsWebsite> list) {
if (cmsWebsiteService.saveBatch(list)) {
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("/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("/updateAll")
public ApiResult<?> updateAll(@RequestBody CmsWebsite cmsWebsite) {
if (cmsWebsiteService.updateByIdAll(cmsWebsite)) {
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("/{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: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:remove')")
@Operation(summary = "批量删除网站信息记录表")
@DeleteMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
if (cmsWebsiteService.removeByIds(ids)) {
return success("删除成功");
}
return fail("删除失败");
}
@Operation(summary = "网站基本信息")
@GetMapping("/getSiteInfo")
public ApiResult<CmsWebsite> getSiteInfo() {
if (ObjectUtil.isEmpty(getTenantId())) {
return fail("参数不正确", null);
@Operation(summary = "网站基本信息")
@GetMapping("/getSiteInfo")
public ApiResult<CmsWebsite> getSiteInfo() {
try {
Integer tenantId = getTenantId();
if (ObjectUtil.isEmpty(tenantId)) {
return fail("租户ID不能为空", null);
}
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));
String key = SITE_INFO_KEY_PREFIX + tenantId;
// 尝试从缓存获取
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)) {
return success("请先创建站点...", null);
}
// 站点异常状态
setWebsiteStatus(website);
// 安全地构建网站信息
try {
buildSafeWebsiteInfo(website);
} catch (Exception e) {
log.error("构建网站信息失败: {}", e.getMessage(), e);
return fail("构建网站信息失败", null);
}
// 站点配置参数
HashMap<String, Object> config = buildWebsiteConfig(website);
website.setConfig(config);
// 缓存结果
try {
redisUtil.set(key, website, 1L, TimeUnit.DAYS);
} catch (Exception e) {
log.warn("缓存网站信息失败: {}", e.getMessage());
}
// 网站导航
setWebsiteNavigation(website);
// 网站设置信息
setWebsiteSetting(website);
// 服务器时间
HashMap<String, Object> serverTime = buildServerTime();
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.error("获取网站信息异常: {}", e.getMessage(), e);
return fail("获取网站信息失败: " + e.getMessage(), null);
}
}
/**
* 安全地构建网站信息
*/
private void buildSafeWebsiteInfo(CmsWebsite website) {
if (website == null) {
throw new IllegalArgumentException("网站对象不能为空");
}
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("违规关停");
}
// 1. 设置网站状态
try {
setWebsiteStatus(website);
} catch (Exception e) {
log.warn("设置网站状态失败: {}", e.getMessage());
website.setStatus(0); // 默认状态
website.setStatusText("状态未知");
}
// 2. 构建配置信息
try {
HashMap<String, Object> config = buildSafeWebsiteConfig(website);
website.setConfig(config);
} catch (Exception e) {
log.warn("构建网站配置失败: {}", e.getMessage());
website.setConfig(new HashMap<>());
}
// 3. 设置导航信息
try {
setSafeWebsiteNavigation(website);
} catch (Exception e) {
log.warn("设置网站导航失败: {}", e.getMessage());
website.setTopNavs(new ArrayList<>());
website.setBottomNavs(new ArrayList<>());
}
// 4. 设置网站设置信息
try {
setWebsiteSetting(website);
} catch (Exception e) {
log.warn("设置网站设置失败: {}", e.getMessage());
// 设置为null让前端知道没有设置信息
}
// 5. 构建服务器时间使用LocalDateTime
try {
HashMap<String, Object> serverTime = buildSafeServerTime();
website.setServerTime(serverTime);
} 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 HashMap<String, Object> buildWebsiteConfig(CmsWebsite website) {
HashMap<String, Object> config = new HashMap<>();
private HashMap<String, Object> buildWebsiteConfig(CmsWebsite website) {
return buildSafeWebsiteConfig(website);
}
private HashMap<String, Object> buildSafeWebsiteConfig(CmsWebsite website) {
HashMap<String, Object> config = new HashMap<>();
try {
// 获取网站字段配置
LambdaQueryWrapper<CmsWebsiteField> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CmsWebsiteField::getDeleted, 0);
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;
}
private String getSysDomain(CmsWebsite website) {
return StrUtil.isNotBlank(website.getWebsiteCode()) ? website.getWebsiteCode() + SYS_DOMAIN_SUFFIX : website.getTenantId() + SYS_DOMAIN_SUFFIX;
}
private String getDomain(CmsWebsite website) {
return StrUtil.isNotBlank(website.getDomain()) ? website.getDomain() : website.getWebsiteCode() + DOMAIN_SUFFIX;
}
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));
}
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);
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());
}
private HashMap<String, Object> buildServerTime() {
HashMap<String, Object> serverTime = new HashMap<>();
// 今天日期
DateTime date = DateUtil.date();
String today = DateUtil.today();
// 明天日期
final DateTime dateTime = DateUtil.tomorrow();
String tomorrow = DateUtil.format(dateTime, "yyyy-MM-dd");
// 后天日期
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);
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("清除成功");
// 安全地设置域名信息
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";
}
if (StrUtil.isNotBlank(website.getDomain())) {
return website.getDomain();
}
if (StrUtil.isNotBlank(website.getWebsiteCode())) {
return website.getWebsiteCode() + DOMAIN_SUFFIX;
}
return website.getTenantId() + DOMAIN_SUFFIX;
}
private void setWebsiteNavigation(CmsWebsite website) {
setSafeWebsiteNavigation(website);
}
private void setSafeWebsiteNavigation(CmsWebsite website) {
if (website == null) {
return;
}
// 设置顶部导航
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<>());
}
// 设置底部导航
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());
// 今天日期
serverTime.put("today", today.toString());
// 明天日期
java.time.LocalDate tomorrow = today.plusDays(1);
serverTime.put("tomorrow", tomorrow.toString());
// 后天日期
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);
// 下周同一天
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("清除成功");
}
}

View File

@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.cms.entity.CmsWebsite;
import com.gxwebsoft.cms.param.CmsWebsiteParam;
import com.gxwebsoft.cms.vo.CmsVO;
import com.gxwebsoft.shop.vo.ShopVo;
import java.util.List;

View File

@@ -5,7 +5,6 @@ import com.gxwebsoft.cms.entity.*;
import com.gxwebsoft.cms.mapper.*;
import com.gxwebsoft.cms.param.*;
import com.gxwebsoft.cms.service.*;
import com.gxwebsoft.cms.vo.CmsVO;
import com.gxwebsoft.common.core.utils.JSONUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.web.PageParam;
@@ -326,7 +325,7 @@ public class CmsWebsiteServiceImpl extends ServiceImpl<CmsWebsiteMapper, CmsWebs
if (StrUtil.isNotBlank(siteInfo)) {
log.info("从缓存获取网站信息租户ID: {}", tenantId);
try {
return JSONUtil.parseObject(siteInfo, CmsVO.class);
return JSONUtil.parseObject(siteInfo, ShopVo.class);
} catch (Exception e) {
log.warn("缓存解析失败,从数据库重新获取: {}", e.getMessage());
}
@@ -346,7 +345,7 @@ public class CmsWebsiteServiceImpl extends ServiceImpl<CmsWebsiteMapper, CmsWebs
CmsWebsiteServiceImplHelper.processExpirationTime(website);
// 转换为VO对象
CmsVO websiteVO = CmsWebsiteServiceImplHelper.convertToVO(website);
ShopVo websiteVO = CmsWebsiteServiceImplHelper.convertToVO(website);
// 缓存结果
try {

View File

@@ -1,17 +1,15 @@
package com.gxwebsoft.cms.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.gxwebsoft.cms.entity.CmsNavigation;
import com.gxwebsoft.cms.entity.CmsWebsite;
import com.gxwebsoft.cms.vo.CmsNavigationVO;
import com.gxwebsoft.cms.vo.CmsVO;
import com.gxwebsoft.shop.vo.MenuVo;
import com.gxwebsoft.shop.vo.ShopVo;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -49,8 +47,8 @@ public class CmsWebsiteServiceImplHelper {
/**
* 将实体对象转换为VO对象
*/
public static CmsVO convertToVO(CmsWebsite website) {
CmsVO vo = new CmsVO();
public static ShopVo convertToVO(CmsWebsite website) {
ShopVo vo = new ShopVo();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 基本信息
@@ -122,13 +120,13 @@ public class CmsWebsiteServiceImplHelper {
/**
* 转换导航列表为VO
*/
public static List<CmsNavigationVO> convertNavigationToVO(List<CmsNavigation> navigations) {
public static List<MenuVo> convertNavigationToVO(List<CmsNavigation> navigations) {
if (navigations == null) {
return null;
}
return navigations.stream().map(nav -> {
CmsNavigationVO navVO = new CmsNavigationVO();
MenuVo navVO = new MenuVo();
navVO.setNavigationId(nav.getNavigationId());
navVO.setNavigationName(nav.getTitle()); // 修复:使用 title 字段
navVO.setNavigationUrl(nav.getPath()); // 修复:使用 path 字段

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -1,8 +1,9 @@
package com.gxwebsoft.shop.controller;
import cn.hutool.core.util.ObjectUtil;
import com.gxwebsoft.cms.entity.CmsWebsite;
import com.gxwebsoft.cms.service.CmsWebsiteService;
import com.gxwebsoft.cms.vo.CmsVO;
import com.gxwebsoft.shop.service.ShopWebsiteService;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.shop.vo.ShopVo;
@@ -27,11 +28,11 @@ import javax.annotation.Resource;
@RequestMapping("/api/shop")
public class ShopMainController extends BaseController {
@Resource
private CmsWebsiteService cmsWebsiteService;
private ShopWebsiteService shopWebsiteService;
@Operation(summary = "商城基本信息", description = "获取商城的基本信息,包括配置、导航、设置和过期状态等")
@GetMapping("/getShopInfo")
public ApiResult<ShopVo> getSiteInfo() {
public ApiResult<ShopVo> getShopInfo() {
Integer tenantId = getTenantId();
if (ObjectUtil.isEmpty(tenantId)) {
@@ -39,8 +40,9 @@ public class ShopMainController extends BaseController {
}
try {
ShopVo vo = cmsWebsiteService.getSiteInfo(tenantId);
return success(vo);
// 使用专门的商城信息获取方法
ShopVo shopVo = shopWebsiteService.getShopInfo(tenantId);
return success(shopVo);
} catch (IllegalArgumentException e) {
return fail(e.getMessage(), null);
} catch (RuntimeException e) {

View File

@@ -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);
}

View File

@@ -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);
}
}
}