springboot如何统一响应格式以及统一异常处理呢,认识一下@RestControllerAdvice

ResponseBodyAdvice的作用:拦截Controller方法的返回值,统一处理返回值/响应体,一般用来统一返回格式,加解密,签名等等。
看下ResponseBodyAdvice的源码:

源码

public interface ResponseBodyAdvice<T> {
  /**
  * 是否支持advice功能
  * true 支持|false 不支持
  */
    boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2);

   /**
  * 处理返回的数据
  */
    @Nullable
    T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4, ServerHttpRequest var5, ServerHttpResponse var6);
}

统一封装返回结果

所以我们只需要创建一个实现类,实现ResponseBodyAdvice<Object>接口就可以了
首先创建一个统一结果响应体

/**
 * 通用返回结果
 * @author WangGuocai
 * @param <T>
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T>  {

    private boolean flag;
    private Integer code;
    private String msg;
    private T data;

    public static <T> Result<T> success(String msg,T data){
        Result<T> result = new Result<>();
        result.setFlag(true);
        result.setCode(20000);
        result.setMsg(msg);
        result.setData(data);
        return result;

    }

    public static <T> Result<T> fail(Integer code,String msg){
        Result<T> result = new Result<>();
        result.setFlag(false);
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

创建一个实现类,实现ResponseBodyAdvice<Object>接口

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (o instanceof String) {
            return objectMapper.writeValueAsString(Result.success("成功", o));
        return Result.success("成功", o);
    }
}

@RestControllerAdvice注解@RestControllerAdvice是@RestController注解的增强,可以实现三个方面的功能:
1.全局异常处理
2.全局数据绑定
3.全局数据预处理

注意:

if(o instanceof String){
  return objectMapper.writeValueAsString(ResultData.success(o));
} 

这段的作用是,防止controller直接返回String,如果不加的话是会直接返回String的,
在这里插入图片描述

所以我们要把他放进Result里面,变成Json;

好了,,到这里,,我们就不需要通过Result.success进行响应了,直接在Controller返回原始数据,Springboot就会完成实现类的包装;
在这里插入图片描述

统一的异常处理

#然后我们还可以利用他做到统一的异常处理
注意Exception.class为必须捕获的异常,否则一旦遇到没有处理的异常就会跳过直达,要么直接响应原始异常,要么被响应处理器捕获处理了又给你套上一层,还给你报异常依然显示成功。。。凎


/**
 * 全局异常处理
 */
@RestControllerAdvice
@Slf4j
public class RestExceptionHandler {

    @ExceptionHandler(ArithmeticException.class)
    public Result<String> arithmeticException(Exception e){
        log.error("全局异常信息 ex={}",e.getMessage(),e );
        return Result.fail(50000,e.getMessage());
    }
    @ExceptionHandler(UserNotFoundException.class)
    public Result<Object> userNotFoundException(Exception e){
        log.error("全局异常信息 ex={}",e.getMessage(),e );
        return Result.fail(50000,e.getMessage());
    }
    @ExceptionHandler(Exception.class)
    public Result<String> Exception(Exception e){
        log.error("全局异常信息 ex={}",e.getMessage(),e );
        return Result.fail(50000,"未知异常请联系管理员");
    }
}
注意上面捕获的异常必须和参数中的异常一直,或者参数必须是其超类,否则会抛出非法状态异常

这时候当异常发生的时候就可以自动对异常进行封装
在这里插入图片描述
总之呢。这个处理器可以在响应前对响应体做一些处理,
o:代表原响应体
objectMapper.writeValueAsString():可以对前端输出响应内容,
responsrequest上面也具备了;

增强处理器和上面的统一响应处理器是可以单独使用的,
如果单独使用这个处理器,没有什么问题,

例外:

但是一旦我们同时启用两个处理器,或者只启用响应处理器但是遇到报错的时候,就会出现一个问题
启用响应处理器

启用响应处理器和异常处理器
在这里插入图片描述
相应处理器会把异常处理过的Result或者springboot默认的响应体进行再次封装
所以我们需要加一段

if (o instanceof Result){
            return o;
        }

在响应处理器中,当结果已经是Result,表示已经被封装过了,那我们就直接响应(不必担心spring默认报错,因为已经被错误处理器拦截并处理了),其他处理器都是先行处理,最终都会到实现了这个接口的实现类的beforeBodyWrite方法来进行最终处理,这样就可以避免异常处理器处理过的Result被再次处理,同时也能避免我们哪次手滑了返回了封装后的Result,被再次封装,这样只要检测到是Result,就会直接返回
响应处理器完整代码

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (o instanceof String) {
            return objectMapper.writeValueAsString(Result.success("成功", o));
        }
        if (o instanceof Result){
            return o;
        }
        return Result.success("成功", o);
    }
}

响应:
在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值