SpringBoot 全局异常处理与日志记录——统一规范实战
📅 2026/7/7 15:13:14
👁️ 阅读次数
📝 编程学习
线上系统出问题不可怕,可怕的是出了问题找不到原因。统一的异常处理和规范的日志记录是任何生产系统必备的基础设施。
一、全局异常处理
1. 自定义业务异常
publicclassBusinessExceptionextendsRuntimeException{privateintcode;privateStringmessage;publicBusinessException(intcode,Stringmessage){super(message);this.code=code;this.message=message;}// 常用错误码publicstaticBusinessExceptionnotFound(Stringmsg){returnnewBusinessException(404,msg);}publicstaticBusinessExceptionbadRequest(Stringmsg){returnnewBusinessException(400,msg);}publicstaticBusinessExceptionunauthorized(Stringmsg){returnnewBusinessException(401,msg);}publicstaticBusinessExceptionforbidden(Stringmsg){returnnewBusinessException(403,msg);}}2. 全局异常处理器
@RestControllerAdvicepublicclassGlobalExceptionHandler{privatestaticfinalLoggerlog=LoggerFactory.getLogger(GlobalExceptionHandler.class);@ExceptionHandler(BusinessException.class)publicResultVO<?>handleBusiness(BusinessExceptione){log.warn("业务异常: code={}, msg={}",e.getCode(),e.getMessage());returnResultVO.error(e.getCode(),e.getMessage());}@ExceptionHandler(MethodArgumentNotValidException.class)publicResultVO<?>handleValidation(MethodArgumentNotValidExceptione){Stringmsg=e.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage).collect(Collectors.joining(";"));returnResultVO.error(400,msg);}@ExceptionHandler(ConstraintViolationException.class)publicResultVO<?>handleConstraint(ConstraintViolationExceptione){Stringmsg=e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));returnResultVO.error(400,msg);}@ExceptionHandler(NoHandlerFoundException.class)publicResultVO<?>handle404(NoHandlerFoundExceptione){returnResultVO.error(404,"接口不存在: "+e.getRequestURL());}@ExceptionHandler(Exception.class)publicResultVO<?>handleOther(Exceptione){log.error("系统异常",e);returnResultVO.error(500,"服务器繁忙,请稍后重试");}}二、统一日志记录
1. 请求日志拦截器
@ComponentpublicclassLogInterceptorimplementsHandlerInterceptor{privatestaticfinalLoggerlog=LoggerFactory.getLogger(LogInterceptor.class);@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){// 记录请求开始时间request.setAttribute("startTime",System.currentTimeMillis());returntrue;}@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex){longstart=(long)request.getAttribute("startTime");longduration=System.currentTimeMillis()-start;log.info("[{}] {} {} → {} ({}ms)",request.getMethod(),request.getRequestURI(),request.getQueryString()!=null?"?"+request.getQueryString():"",response.getStatus(),duration);}}2. 注册拦截器
@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@AutowiredprivateLogInterceptorlogInterceptor;@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(logInterceptor).addPathPatterns("/api/**");}}3. 日志级别配置
logging:level:root:INFOcom.zhang:DEBUGcom.zhang.seckill.mapper:TRACEfile:path:/var/log/appname:${logging.file.path}/app.loglogback:rolling policy:max-history:30max-file-size:100MB三、日志最佳实践
// ✅ 正确:带参数占位符log.info("用户 {} 创建订单 {}",userId,orderNo);// ❌ 错误:字符串拼接log.info("用户 "+userId+" 创建订单 "+orderNo);// ✅ 正确:包含上下文信息log.warn("支付失败: orderNo={}, amount={}, error={}",orderNo,amount,error);// ❌ 错误:没信息量的日志log.info("支付失败");💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。
编程学习
技术分享
实战经验