如何向Grails异常处理器传递上下文参数以统一异常处理
当然可以!你完全可以通过自定义异常类携带上下文信息,再配合Grails的异常处理器来消除重复的catch块。下面是具体的实现步骤:
1. 扩展异常类,添加上下文存储能力
首先修改你的WhateverException,让它能够携带每个请求独有的上下文数据:
class WhateverException extends RuntimeException { // 用于存储请求上下文的Map Map<String, Object> context // 重载构造方法,支持传入上下文 WhateverException(String message, Throwable cause, Map<String, Object> context) { super(message, cause) this.context = context ?: [:] // 避免空值 } // 可选:添加其他构造方法适配不同场景 WhateverException(String message, Map<String, Object> context) { this(message, null, context) } }
2. 替换控制器中的catch块,改为抛出带上下文的异常
在原来的控制器动作里,去掉重复的catch逻辑,转而在异常发生时(或捕获到原始异常时)抛出携带当前请求上下文的WhateverException:
def someAction() { try { // 你的业务逻辑代码 riskyService.doSomething() } catch (OriginalBusinessException e) { // 假设原来捕获的是业务层异常 // 收集当前请求的上下文数据 def requestContext = [ foo: request.foo, bar: request.baz, userId: session.userId // 还可以添加会话等其他上下文 ] // 抛出带上下文的自定义异常 throw new WhateverException("A whatever error occurred", e, requestContext) } }
3. 实现统一的异常处理器
接下来创建一个异常处理器,统一处理所有WhateverException,负责设置响应状态、记录带上下文的日志:
选项A:控制器级处理器(仅处理当前控制器的异常)
如果只想让这个处理器处理当前控制器的异常,直接在控制器内添加:
import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.http.HttpStatus class YourController { def log // 处理当前控制器的WhateverException @ExceptionHandler(WhateverException) def handleWhateverException(WhateverException ex) { // 设置响应状态码 response.status = HttpStatus.PROPER_HTTP_STATUS.value() // 记录带上下文的日志(记得传入异常对象,方便追踪堆栈) log.info("A whatever error occurred. Context = ${ex.context}", ex) // 可选:返回错误视图或JSON响应 render([error: ex.message, context: ex.context] as JSON) } }
选项B:全局异常处理器(处理所有控制器的异常)
如果希望所有控制器的WhateverException都由同一个处理器处理,可以创建全局异常处理类:
import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import javax.servlet.http.HttpServletRequest @ControllerAdvice class GlobalExceptionHandler { def log @ExceptionHandler(WhateverException) ResponseEntity<Map> handleWhateverException(WhateverException ex, HttpServletRequest request) { log.info("A whatever error occurred. Context = ${ex.context}", ex) // 构建统一的响应体 def responseBody = [ timestamp: new Date().toString(), error: ex.message, context: ex.context, path: request.requestURI ] // 返回响应实体 new ResponseEntity<>(responseBody, HttpStatus.PROPER_HTTP_STATUS) } }
关键优势
- 消除了重复的catch块代码,符合DRY(Don't Repeat Yourself)原则
- 上下文数据和异常绑定,确保日志能准确反映每个请求的场景
- 异常处理逻辑集中管理,后续修改日志格式、响应状态等只需调整处理器
内容的提问来源于stack exchange,提问作者Raibaz
相关产品推荐
相关产品推荐

