基于 LangGraph 的生成式 AI 智能体设计模式实践:Gen AI Experience Concierge 全解析
2026/9/13 14:03:19
在传统的 Web 开发中,我们经常会在 Controller 层看到大量的重复代码:
// ❌ 糟糕的代码示范@GetMapping("/user")publicResultgetUser(){try{userService.doSomething();returnResult.success();}catch(BusinessExceptione){returnResult.error(e.getCode(),e.getMessage());}catch(Exceptione){log.error("未知错误",e);returnResult.error(500,"系统内部错误");}}这种写法有三个痛点:
try-catch。{"code": 500},有的返回{"status": "error"},前端处理起来非常痛苦。catch块中吞掉了异常且没有手动回滚,数据库事务可能提交脏数据。GlobalExceptionHandler的核心作用:
CommonResult)。@Transactional自动回滚,保证数据一致性。要实现全局异常处理,主要依赖两个注解:
@RestControllerAdvice@ControllerAdvice和@ResponseBody的组合注解。@ExceptionHandler(Exception.class)以下是一个标准的企业级异常处理器模板。
首先,我们需要一个标准的 JSON 包装类。
@DatapublicclassCommonResult<T>{privateIntegercode;privateStringmsg;privateTdata;publicstaticCommonResult<?>error(Integercode,Stringmsg){CommonResult<?>result=newCommonResult<>();result.code=code;result.msg=msg;returnresult;}}@Slf4j@RestControllerAdvicepublicclassGlobalExceptionHandler{// 忽略的错误信息(噪音过滤)publicstaticfinalSet<String>IGNORE_ERROR_MESSAGES=Set.of("无效的刷新令牌");/** * 1. 处理自定义业务异常 (ServiceException) * 场景:库存不足、账号密码错误 */@ExceptionHandler(ServiceException.class)publicCommonResult<?>handleServiceException(ServiceExceptionex){// 只有不在忽略名单里的错误,才打印日志,避免刷屏if(!IGNORE_ERROR_MESSAGES.contains(ex.getMessage())){log.warn("[业务异常] {}",ex.getMessage());}returnCommonResult.error(ex.getCode(),ex.getMessage());}/** * 2. 处理参数校验异常 (JSON 格式) * 场景:@RequestBody + @Valid 校验失败 */@ExceptionHandler(MethodArgumentNotValidException.class)publicCommonResult<?>handleMethodArgumentNotValidException(MethodArgumentNotValidExceptionex){// 从异常中提取第一个具体的错误提示StringerrorMessage=ex.getBindingResult().getFieldError().getDefaultMessage();log.warn("[参数校验异常] {}",errorMessage);returnCommonResult.error(400,String.format("请求参数不正确: %s",errorMessage));}/** * 3. 处理参数校验异常 (表单/URL 参数格式) * 场景:GET 请求 @Valid 校验失败 */@ExceptionHandler(BindException.class)publicCommonResult<?>handleBindException(BindExceptionex){StringerrorMessage=ex.getBindingResult().getFieldError().getDefaultMessage();log.warn("[参数绑定异常] {}",errorMessage);returnCommonResult.error(400,String.format("请求参数不正确: %s",errorMessage));}/** * 4. 处理必填参数缺失 * 场景:@RequestParam 没传 */@ExceptionHandler(MissingServletRequestParameterException.class)publicCommonResult<?>handleMissingServletRequestParameterException(MissingServletRequestParameterExceptionex){returnCommonResult.error(400,String.format("请求参数缺失: %s",ex.getParameterName()));}/** * 5. 兜底异常处理 (Exception) * 场景:空指针、数据库连接超时、代码 Bug */@ExceptionHandler(Exception.class)publicCommonResult<?>handleGlobalException(Exceptionex){// 这里必须打印 ERROR 级别的堆栈日志,方便排查 Buglog.error("[系统异常]",ex);returnCommonResult.error(500,"系统内部错误,请联系管理员");}}这是面试和实战中的高频考点。
问题:@RestControllerAdvice只能捕获Controller 层之后的异常。如果Filter(如 Token 认证过滤器)抛出异常,它是抓不到的。
解决方案:
在yudao架构中,通常会提供一个“手动分发器”方法。Filter 捕获异常后,手动调用这个方法。
代码片段:
// 在 GlobalExceptionHandler 中添加publicCommonResult<?>allExceptionHandler(HttpServletRequestrequest,Throwableex){if(exinstanceofServiceException){returnhandleServiceException((ServiceException)ex);}// ... 手动判断其他类型returnhandleGlobalException((Exception)ex);}// 在 Filter 中调用try{chain.doFilter(request,response);}catch(Exceptione){// 手动转交给全局异常处理器CommonResult<?>result=globalExceptionHandler.allExceptionHandler(request,e);ServletUtils.writeJSON(response,result);}GlobalExceptionHandler是 Spring Boot 工程化开发的基石。
它像一个污水净化器:
通过它,我们实现了后端代码的快速失败,Service 层只需关注业务逻辑,遇到问题直接抛异常,剩下的全交给它处理。