小程序开发-服务端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

5.2 KiB

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)

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

// 使用 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. 时间处理现代化

// 旧方式 (可能有问题)
DateTime date = DateUtil.date();
String today = DateUtil.today();

// 新方式 (安全可靠)
LocalDateTime now = LocalDateTime.now();
LocalDate today = LocalDate.now();

2. 异常处理分层

// 接口层 - 捕获所有异常
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. 空值安全策略

// 确保返回值永远不为 null
if (topNavs != null && !topNavs.isEmpty()) {
    website.setTopNavs(CommonUtil.toTreeData(topNavs, ...));
} else {
    website.setTopNavs(new ArrayList<>());
}

测试建议

  1. 正常场景: 测试有完整站点数据的租户
  2. 异常场景: 测试没有站点数据的租户
  3. 边界场景: 测试站点数据不完整的情况
  4. 多租户场景: 测试不同租户之间的数据隔离
  5. 性能场景: 测试大量导航数据的处理
  6. 时间场景: 测试不同时区的时间处理

影响范围

  • 彻底解决 getSiteInfo 接口的空值异常
  • 现代化 时间处理方式,使用 LocalDateTime
  • 增强 系统整体稳定性和健壮性
  • 改善 错误日志的可读性和调试能力
  • 保持 向后兼容,不影响现有功能
  • 提升 多租户数据安全性