V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Morii
V2EX  ›  问与答

Spring Validation + 统一异常返回 疑问

  •  
  •   Morii · 2023-01-30 15:19:46 +08:00 · 788 次点击
    这是一个创建于 388 天前的主题,其中的信息可能已经有所发展或是发生改变。

    请问这篇文章中的这段效果怎么实现呢?

    http://unclechen.github.io/2018/12/15/SpringBoot%E8%87%AA%E5%AE%9A%E4%B9%89%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C/


    3.6 更加细致的返回码和消息 其实还有一种比较典型的自定义返回,就是错误码( code )和消息( message )是一一对应的,比如:

    51001:字符串长度过长 51002:参数取值过大 … 这种情况比较特殊,一般当参数错误的时候,会返回一个整体的参数错误的错误码,然后携带参数的错误信息。但有时,业务上就要不同的参数错误,既要错误码不同,错误信息也要不同。我想了下,有两种思路。

    第一种:通过 message 同时包含错误码和错误信息,在全局异常捕获方法中,再把它们拆开。 第二种:手动校验,抛出自定义的 Exception (里面带有 code 、message )。手动校验这里,如果每一个 Controller 都去写一遍,确实比较费劲,可以结合 AOP 来实现,或者抽出一个基类 BaseController 的方式。


    不知道有没有更好的方案,碰巧需要返回这种 code + msg 一一对应的效果

    6 条回复    2023-01-30 17:33:21 +08:00
    cslive
        1
    cslive  
       2023-01-30 16:39:24 +08:00
    @ExceptionHandler(value = {Exception.class})

    这里捕捉不同异常,抛出不同的错误码不就行了
    jackytsu
        2
    jackytsu  
       2023-01-30 16:43:18 +08:00
    比较多的做法是抛出自定义异常类
    然后异常的 code 是放在常量里或枚举里
    message 放在项目的资源文件里或读取外部配置
    方便部署时针对不同的业务需求返回不同的提示信息
    szzadkk
        3
    szzadkk  
       2023-01-30 16:46:29 +08:00
    1. 定义个异常信息的枚举,里面包含 code 和 message
    2. 自定义异常类,把这个枚举值作为属性
    3. 底层抛出自定义异常
    4. GlobalExceptionHandler 里面处理,将 code 、message 取出放到 response body 里面
    nothingistrue
        4
    nothingistrue  
       2023-01-30 17:06:21 +08:00
    首先纠正一点,这是 Spring 使用的 Bean Validation 规范下的 Hibernate Validation 实现,不是 Spring Validation 。然后,这个是验证 Java Bean 的字段的。对应到业务上,它只能验证方法参数的有效性,只能参与统一异常处理,不能替代,也不能侵入。

    另外关于错误码和消息的对应关系,你引用的文章的理解都是错误的。如果有了错误码,那么错误消息就只能是错误码的外部展示,它归属于错误码,而不是跟错误码同级别,并不存在一一对应关系。异常上是只需包含 code 的,整个异常处理过程,除了最后的对外显示外,都不需要考虑 message 。message 只需要最终显示时,通过资源文件根据 code 再获取即可,多语言环境下还可以同一个 code 针对不同的语言环境显示不同的 message 。
    nothingistrue
        5
    nothingistrue  
       2023-01-30 17:30:01 +08:00
    有一点是需要提醒的,错误码异常反馈方式,虽然是很常见的异常反馈方式,但却是很老,并且基本没啥卵用的异常反馈方式。Java 和 Spring 并没有采用这种体系。

    以前没异常体系,只能靠函数返回值来做错误返回,才不得不用错误码来反馈错误信息。而 Java 有了新的 try catch throw 异常处理机制,就提供了更丰富的错误反馈机制。Java 反馈的错误信息,是 java.lang.Throwable 的子类的实例。这是一个对象,必须包含类自身定义(完整类名)和抛出追踪栈(通过 printStackTrace 打印的东西),可选包含 messge 和 localized message 。然后更重要的,java.lang.Throwable 只是一个普通类,开发者可以根据需要任意扩展。

    Bean Validation 没有对原生异常体系做过多扩展,所以它也就只能定义 message 。但是,这个是 java.lang.Throwable 的 message ,不是你业务上的 message 。你可以,在定义 Bean Validation 注解的 message 时,定义成业务上的错误码,然后再统一异常处理器中,捕获 Bean Validation 的异常,通过 getMessage 方法提取出业务上的错误码,再做后续转换处理。
    nothingistrue
        6
    nothingistrue  
       2023-01-30 17:33:21 +08:00
    Bean Validation 只包含了参数检查,这在业务异常中只是极小的一部分,如果你要在整个错误反馈体系中加错误码,那么,不但需要定制一个额外包含 code 的异常类作为所有自定义异常的基类,还需要捕获所有 Java 自身异常和使用到的第三方框架的异常并将其转换成自定义异常。这是吃力不讨好的事。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5619 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 06:48 · PVG 14:48 · LAX 22:48 · JFK 01:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.