狂野飙车6鸿蒙版
471.84M · 2025-10-31
在企业级项目中,为了保证业务流程正常运行,需要对一些可能出现异常的代码做一些处理,但随着业务的发展,针对异常处理的代码将越来越庞大,就会出现以下弊端:
try-catch代码块,难以维护。Controller层直接将异常信息返回给前端,不够友好。为了解决上面的问题,我们需要配置全局异常处理,首先解耦业务代码与异常处理代码,让代码结构更清晰;其次,通过设置结构统一的异常响应信息,降低前端处理失败响应的难度;最后,自定义返回的提示信息,便于用户或前端理解。
@RestControllerAdvice:rest请求拦截器@RestControllerAdvice由@ControllerAdvice和@ResponseBody组成,这两者是Spring MVC框架提供的注解,前者是基于AOP的概念,只能标记在类上,可以将其理解为一个拦截器,它允许你对拦截的控制器追加处理逻辑,我们可以利用这一特点处理控制器所抛出的异常。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
@AliasFor(
annotation = ControllerAdvice.class
)
String name() default "";
/**
* 省略后续代码内容
**/
}
@ExceptionHandler:异常处理器@ExceptionHandler也是Spring MVC框架提供的注解,只能标记在方法上,注解的内部包含一个value属性,用来定义一个特定的异常类,当Controller控制器抛出了value中定义的异常,Spring MVC会从被标记了@RestControllerAdvice注解的类中找到这个被@ExceptionHandler所标记的异常处理方法,找到后,就会执行这个自定义的异常处理方法。
当我们定义了标记@RestControllerAdvice的全局异常处理类,并在类中创建了@ExceptionHandler标记的异常处理方法后,当用户发起API调用抛出异常,Spring MVC就会找到处理特定异常的方法,执行并返回自定义的异常信息给用户。
创建一个响应实体类Result,包含code、msg、data属性,编写success、errror方法,分别返回表示成功和失败的响应数据
package com.example.springexception.common;
import java.util.HashMap;
/**
* 消息体
*/
public class Result extends HashMap<String,Object> {
private static final long serialVersionUID = 1L;
private static final String CODE = "code"; //状态码
private static final String MSG = "msg"; //响应描述
private static final String DATA = "data"; //响应数据
public Result(){}
public Result(int code,String msg,Object data){
super.put(CODE,code);
super.put(MSG,msg);
super.put(DATA,data);
}
/**
* 请求成功返回数据
* @param msg
* @param data
* @return
*/
public static Result success(String msg,Object data){
return new Result(200,msg,data);
}
/**
* 请求成功返回提示
* @param msg
* @return
*/
public static Result success(String msg){
return success(msg,null);
}
/**
* 请求失败返回数据
* @param msg
* @param data
* @return
*/
public static Result error(String msg,Object data){
return new Result(500,msg,data);
}
/**
* 请求失败返回提示
* @param msg
* @return
*/
public static Result error(String msg){
return error(msg,null);
}
}
编写一个ServiceException异常类,表示业务异常,如果发生异常,交给后续定义的全局异常处理器处理这个异常。
/**
* 自定义业务异常
*/
@Data
public class ServiceException extends RuntimeException{
private static final long serialVersionUID = 1L;
/**
* 错误提示
*/
private String message;
public ServiceException(String message){
this.message = message;
}
}
自定义异常需要继承RuntimeException类,表示运行时异常,添加一个message属性用来测试返回异常信息。
在Controller中编写一个getRandom接口,表示一个获取1000以内随机数的接口,在接口中判断本次获取的随机数是否>=500,如果条件成立正常返回成功数据,否则抛出ServiceException异常。需要注意的是:这里只是为了测试,所以直接在 Controller 层抛出异常,在正常开发过程中,一般会在业务层抛出业务相关的异常。
@RestController
public class TestController {
/**
* 获取随机数接口
* @return
*/
@GetMapping("/random")
public Result getRandom(){
Random random = new Random();
int boundInt = random.nextInt(1000);
if(boundInt<500){
throw new ServiceException("随机数小于500,请重新生成"+boundInt);
}
return Result.success("获取随机数API",boundInt);
}
}
创建 GlobalExceptionHandler 类,在类上标注 @RestControllerAdvice注解让SpringMVC自动扫描拦截这个处理器,编写一个handlerServiceException方法并标记注解@ExceptionHandler(ServiceException.class),表示这个方法用来处理ServiceException类型的异常。
/**
* 全局异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class)
public Result handlerServiceException(ServiceException e){
return Result.error(e.getMessage());
}
}
{
"msg": "获取随机数API",
"code": 200,
"data": 891
}
{
"msg": "随机数小于500,请重新生成441",
"code": 500,
"data": null
}
到此,就完成了全局异常处理器的简单构建,以上内容是构建全局异常处理器的流程,可以在此基础上针对自己的业务对处理器或自定义异常进行功能细化。
SpringBoot全局异常处理的实现,是现代Web开发中不可或缺的一环。通过 @RestControllerAdvice 与 @ExceptionHandler 两个注解的组合,我们能够将分散的异常处理逻辑集中化管理,构建出一个清晰、健壮的后端异常处理体系。
核心步骤可归纳为:
遵循“已知异常明确提示,未知异常日志记录并友好兜底”的最佳实践,不仅能极大提升代码的可维护性,更能为前后端协作提供统一的接口契约,最终打造出用户体验更佳、稳定性更高的应用服务。