告别 if-else 地狱 —— JSR380 参数验证在 ionet 中的应用

你的 Action 方法长什么样?

很多开发者的业务方法,前一半都是在检查参数:

java 复制代码
// 不使用验证框架的写法
private void createRoom(CreateRoomMessage message) {
    if (message.roomName == null || message.roomName.isEmpty()) {
        throw new RuntimeException("房间名不能为空");
    }
    if (message.roomName.length() > 20) {
        throw new RuntimeException("房间名太长");
    }
    if (message.maxPlayers < 2 || message.maxPlayers > 10) {
        throw new RuntimeException("人数限制不合法");
    }
    if (message.gameMode < 0 || message.gameMode > 3) {
        throw new RuntimeException("游戏模式不合法");
    }
    // 终于可以写业务了...
}

可以看出参数验证不是业务,却写在了业务里面。


JSR380:声明式验证

ionet 支持 JSR380(Bean Validation)规范。你可以在协议类上用注解声明验证规则:

java 复制代码
@ProtobufClass
public class CreateRoomMessage {
    @NotNull(message = "房间名不能为空")
    @Size(min = 1, max = 20, message = "房间名长度需在1-20之间")
    public String roomName;

    @Min(value = 2, message = "至少2人")
    @Max(value = 10, message = "最多10人")
    public int maxPlayers;

    @Min(value = 0, message = "游戏模式不合法")
    @Max(value = 3, message = "游戏模式不合法")
    public int gameMode;
}

现在你的 Action 方法变成了:

java 复制代码
@ActionMethod(RoomCmd.create)
private RoomInfo createRoom(CreateRoomMessage message) {
    // 直接写业务逻辑!参数已经验证通过了
    Room room = roomService.create(message.roomName, message.maxPlayers);
    return room.toInfo();
}

验证失败时,框架自动将错误信息返回给客户端。 你的业务方法里不会出现任何参数检查代码。


常用验证注解

注解 作用 示例
@NotNull 不能为 null @NotNull(message = "不能为空")
@NotEmpty 不能为 null 且不为空字符串 适用于 String
@Size 字符串/集合长度范围 @Size(min=1, max=50)
@Min 最小值 @Min(1)
@Max 最大值 @Max(100)
@Positive 必须为正数 适用于数字类型
@Email 邮箱格式
@Pattern 正则表达式 @Pattern(regexp="[a-zA-Z]+")

与断言机制的配合

JSR380 负责格式层 的验证(数据类型、长度、范围),断言机制负责业务层的验证(用户是否存在、金币是否足够)。

两者配合使用,让你的代码分层更清晰:

java 复制代码
@ProtobufClass
public class BuyMessage {
    @Positive(message = "商品ID必须为正数")
    public int itemId;

    @Min(value = 1, message = "至少购买1个")
    @Max(value = 99, message = "最多购买99个")
    public int count;
}

@ActionMethod(ShopCmd.buy)
private void buyItem(FlowContext flowContext, BuyMessage message) {
    // JSR380 已经验证了 itemId > 0, 1 <= count <= 99

    Item item = itemService.getItem(message.itemId);
    ErrorCode.itemNotFound.assertTrue(item != null);        // 业务断言
    ErrorCode.itemOffSale.assertTrue(item.isOnSale());      // 业务断言
    ErrorCode.goldNotEnough.assertTrue(hasEnoughGold(item)); // 业务断言

    // 纯粹的业务逻辑
    doPurchase(flowContext.getUserId(), item, message.count);
}

格式验证 → 注解完成,业务验证 → 断言完成,剩下的就是纯业务逻辑。


小结

JSR380 + 断言机制的组合,让你的代码呈现出清晰的三层结构:

  1. 格式验证层@NotNull@Min...)→ 注解声明,零代码
  2. 业务验证层ErrorCode.xxx.assertTrue)→ 一行断言
  3. 业务逻辑层 → 你真正要写的代码

更多资源

下一篇预告开发神器:DebugInOut 插件与调用统计

相关推荐
橙淮1 天前
并发编程(六)
java·jvm
拽着尾巴的鱼儿1 天前
springboot openfeign 自定义feign 接口重试机制
java·spring boot·后端
搞科研的小刘选手1 天前
【中山大学主办】第六届计算机科学与区块链国际学术会议(CCSB 2026)
分布式·神经网络·计算机视觉·区块链·计算机科学·共识算法·自然语言
白露与泡影1 天前
2026大厂Java面试题大全!牛客网最新版
java·开发语言
lolo大魔王1 天前
Linux 文件系统超全面详解(原理、结构、挂载、分区、inode、日志、管理命令)
linux·运维·服务器
EntyIU1 天前
JVM内存与GC笔记
java·jvm·笔记
XS0301061 天前
并发编程 六
java·后端
小饼干在学嘎瓦1 天前
本地缓存和分布式缓存如何选择?
分布式·缓存
yaoxin5211231 天前
419. 现代 Java IO 最佳实践 - 写入文本文件
java·windows·python
雪宫街道1 天前
synchronized 锁的范围:对象锁、类锁与代码块锁
java·jvm·后端·面试