SpringBoot 统一功能处理:
定义:指在SpringBoot应用中,通过一些统一的处理机制,对具有共性的功能进行集中管理,以提高代码的可维护性和开发效率。 应用范围:通常包括统一异常处理、统一数据返回格式、统一用户认证与授权等。
博主任认为,统一数据返回格式在项目中起到至关重要的作用,没有统一的返回格式,那么前端就很难有序、正确的接收到后端的响应。所以前端准确的接收响应,后端必须有一个统一的返回格式(通过各种类型转换实现)。
为确保数据格式规范统一,我们首先采用@ControllerAdvice注解配合ResponseBodyAdvice接口实现方案。其中@ControllerAdvice用于定义全局控制器增强类。
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
//false:不处理
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//如果返回体是String类型,使用objectMapper将其转换成JSON字符串,再使用Result.success()包装
if(body instanceof String){
return objectMapper.writeValueAsString(Result.success(body));
}
//如果返回体已经是Result类型,则直接返回
if(body instanceof Result){
return body;
}
//其他类型,直接使用Result.success()包装
return Result.success(body);
}
}supports方法是判断是否要执行beforeBodyWrite方法。true为执行,false不执行。通过该方法可以选择哪些类或者哪些方法的响应要进行统一格式处理,其他的不处理。 |
|---|
beforeBodyWrite用于在控制器方法返回结果之前对响应体进行统一处理。目的就说对返回的数据格式进行统一封装。 |
|---|
我们通过postman来测试一下,统一格式返回前后的区别:

转换后:

手动显示模式指的是在控制器方法中显式地返回统一结果对象,而不是依赖全局拦截器自动包装。它对于每个功能模块都有更强的掌控力,更加明确代码中的返回类型。
@Data
public class CommonResult<T> implements Serializable {//序列化实现的接口(标记”这个类的对象可以被序列化,便于网络传输和持久化存储)
/**
* 返回的错误码
*/
private Integer code;
/**
* 返回的泛型数据
*/
private T data;
/**
* 返回的错误描述
*/
private String message;
public static <T> CommonResult <T> success(T data) {
CommonResult<T> result=new CommonResult<>();
result.code= GlobalErrorCode.SUCCESS.getCode();
result.data=data;
result.message="";
return result;
}
public static <T> CommonResult <T> error(Integer code,String message) {
Assert.isTrue(!GlobalErrorCode.SUCCESS.getCode().equals(code),"不是错误的异常");
CommonResult<T> result=new CommonResult<>();
result.code= GlobalErrorCode.INTERNAL_SERVER_ERROR.getCode();
result.message= message;
return result;
}
public static <T> CommonResult <T> error(ErrorCode errorCode) {
return error(errorCode.getCode(),errorCode.getMessage());
}
}每个接口返回类型都**需要手动去包装响应,达到精细化处理响应效果。**同时你也可以去定义全局的错误或者异常,以便统一处理,这个我们后面再说。
注意: 在全局拦截自动包装模式中 ,返回结果为String类型。 SpringBoot开始选择消息转化器,
但是有自动全局拦截器,开始使用手动JSON序列化,(objectMapper将其转换成JSON字符串)最终响应输出一个JSON字符串(不是JSON对象)。 |
|---|
而手动显示封装模式先手动包装Spring类型,在CommontResult类下返回的是对象,
然后SpringBoot开始选择消息转化器,引入jackson包后,容器会把MappingJackson2HttpMessageConverter⾃动注册到messageConverters链的末尾被SpringBoot选中,进行Jackson自动序列化为JSON对象。 |
|---|
统⼀异常处理使⽤的是@ControllerAdvice + @ExceptionHandler来实现的,@ControllerAdvice 表⽰控制器通知类,@ExceptionHandler 是异常处理器,两个结合表⽰当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler
public Result handlerException(Exception e) {
return Result.fail(e.getMessage());
}
}注意:接口返回为数据时,需要@ResponseBody注解。 这个原因在学习@ResponseBody注解时介绍过:注解告诉Spring:方法的返回值应该直接写入HTTP响应体,而不是被解释为视图名称。
调用Result.fail(e.getMessage())方法返回错误信息,所有的异常都有统一的返回格式,
结果状态枚举类:ResultCodeEnum
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
public enum ResultCodeEnum {
SUCCESS(200), // 成功状态码
FAIL(-1); // 失败状态码
@Setter @Getter
private int code;
}统一结果封装类:Result
import com.zc.blog.enums.ResultCodeEnum;
import lombok.Data;
@Data
public class Result {
private ResultCodeEnum code; // 业务状态码(使用枚举)
private String errMsg; // 错误信息(成功时为null)
private Object data; // 响应数据(任意类型)
// 成功响应 - 带数据
public static Result success(Object data){
Result result = new Result();
result.setCode(ResultCodeEnum.SUCCESS);
result.setData(data);
return result;
}
// 失败响应 - 只有错误信息
public static Result fail(String errMsg){
Result result = new Result();
result.setCode(ResultCodeEnum.FAIL);
result.setErrMsg(errMsg);
return result;
}
// 失败响应 - 带错误信息和数据
public static Result fail(String errMsg, Object data){
Result result = new Result();
result.setCode(ResultCodeEnum.FAIL);
result.setErrMsg(errMsg);
result.setData(data);
return result;
}
}全局异常处理:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result handleBlogException(BlogException e) {
// 捕获业务异常,返回统一的失败结果
return Result.fail(e.getErrMsg());
}
}自定义异常类:Experience
import lombok.Data;
@Data
public class Exception extends RuntimeException{
private int code; // 异常状态码
private String errMsg; // 异常信息
// 构造方法 - 指定码和消息
public Exception(int code, String errMsg) {
this.code = code;
this.errMsg = errMsg;
}
// 构造方法 - 只指定消息(使用默认码)
public Exception(String errMsg) {
this.errMsg = errMsg;
}
}接口返回格式经过Spring 会使用消息转换器将对象转化为JSON
1. 能提供统一的API响应格式,方便前端更好的接收和解析后端数据 2. 降低前后端沟通成本 3. 有利于项目维护和扩展 4. 提供友好的报错信息