springboot学习之十一(统一返回结果)

SpringBoot统一返回结果
在实际开发中,为了降低开发人员之间的沟通成本,一般返回结果会定义成一个统一格式,具体的格式根据实际开发业务不同有所区别,但至少包括三要素:

code状态码:由后端统一定义各种返回结果的状态码
message 描述:本次接口调用的结果描述
data 数据:本次返回的数据。

{
    "code": 200,
    "msg": "操作成功",
    "data": "Hello World,test123",
}

 

1 基础实现方式

1.1 定义状态码

public enum ReturnCode {

    SUCCESS(200, "操作成功"),
    NEED_LOGIN(401, "需要登录后操作"),
    NO_OPERATOR_AUTH(403, "无权限操作"),
    TOKEN_ILL(404,"token非法"),
    SYSTEM_ERROR(500, "出现错误"),
    USERNAME_EXIST(501, "用户名已经存在"),
    PHOMENUMBER_EXIST(502, "手机号已存在"),
    EMAIL_EXIST(503, "邮箱已存在"),
    REQUEST_USERNAME(504, "必须填写用户名"),
    LOGIN_ERROR(505, "用户名或密码错误");

    // 自定义状态码
    private final int code;

    // 自定义描述
    private final String msg;

    ReturnCode(int code, String errorMessage) {
        this.code = code;
        this.msg = errorMessage;
    }

    public int getCode() {
        return this.code;
    }

    public String getMsg() {
        return this.msg;
    }

}

1.2 定义返回对象

@Data
public class ResultData<T> {
    /**
     * 响应编码
     */
    private Integer code;
    /**
     * 响应信息
     */
    private String msg;
    /**
     * 响应数据
     */
    private T data;
    /**
     * 接口请求时间
     */
    private long timestamp ;

    public ResultData(){
        this.timestamp = System.currentTimeMillis();
    }

    public ResultData(Integer code, String msg){
        this.code=code;
        this.msg=msg;
    }

    public ResultData(Integer code, String msg, T data){
        this.code=code;
        this.msg=msg;
        this.data=data;
    }

    public static ResultData success(){
        return ResultData.success(ReturnCode.SUCCESS.getCode(),ReturnCode.SUCCESS.getMsg());
    }
    public static ResultData success(int code, String msg){
        ResultData<Object> resultData = new ResultData<>();
        resultData.setCode(code);
        resultData.setMsg(msg);
        return resultData;
    }

    public static ResultData success(Object data){
        ResultData<Object> resultData = new ResultData<>(ReturnCode.SUCCESS.getCode(),ReturnCode.SUCCESS.getMsg());
        if (Objects.nonNull(data)){
            resultData.setData(data);
        }
        return resultData;
    }

    public static ResultData error(int code, String msg){
        ResultData<Object> resultData = new ResultData<>(code,msg);
        return resultData;
    }

    public static ResultData error(ReturnCode returnCode){
        ResultData<Object> resultData = new ResultData<>(returnCode.getCode(), returnCode.getMsg());
        return resultData;
    }
}

1.3 统一返回格式

    @GetMapping("/getTest")
    public ResultData<String> getTest(){
        return ResultData.success("Hello world!");
    }

返回结果如下所示:

{
    "code": 200,
    "msg": "操作成功",
    "data": "Hello world!",
    "timestamp": 1639013414924
}

到这里,一个统一格式的返回结果已经实现,接口的返回类型为ResultData,但每写一个接口,就要调用ResultData.success()对结果进行包装,重复劳动,浪费体力,所以这个在实际工作中一般用的比较少。

 

2 高级实现方式

我们只需要借助SpringBoot 提供的ResponseBodyAdvice即可。

ResponseBodyAdvice可以在注解@ResponseBody将返回值处理成相应格式之前操作返回值。实现这个接口即可完成相应操作。可用于对response 数据的一些统一封装或者加密等操作

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

 所以@ResponseBodyAdvice只对@ResponseBody注解的方法有效,如果一个控制器没有加@ResponseBody那还是按正常的找view走。

2.1 ResponseBodyAdvice返回

@RestControllerAdvice(basePackages = "org.tesheng.controller")
public class ResponseAdvice implements ResponseBodyAdvice {

    @Autowired
    private ObjectMapper objectMapper;
    
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        
        if(body instanceof String){    // 如果Controller直接返回String的话,SpringBoot是直接返回,故我们需要手动转换成json。
            return objectMapper.writeValueAsString(ResultData.success(body));
        }
        if(body instanceof ResultData){    // 如果返回的结果是ResultData对象,直接返回即可。
            return body;
        }
        return ResultData.success(body);
    }
}

 

2.2 全局异常处理器

@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultData<String> exception(Exception e){
        log.error("全局异常信息 ex={}", e.getMessage(), e);
        return ResultData.fail(ReturnCode.SYSTEM_ERROR.getCode(), e.getMessage());
    }
}

@RestControllerAdvice,RestController的增强类,可用于实现全局异常处理器
@ExceptionHandler,统一处理某一类异常,从而减少代码重复率和复杂度,比如要获取自定义异常可以 @ExceptionHandler(BusinessException.class)
@ResponseStatus指定客户端收到的http状态码

2.3 体验效果

    @GetMapping("/wrong")
    public int error(){
        int i = 9/0;
        return i;
    }

返回结果如下:

{
    "code": 500,
    "msg": "/ by zero",
    "data": null,
    "timestamp": 1639014045820
}

 ---------------------

 处理自定义错误

1.自定义错误类:

public class BizException extends RuntimeException {
    public BizException(String msg, Throwable cause) {
        super(msg, cause);
    }

    public BizException(String msg) {
        super(msg);
    }
}

2.全局异常添加自定义类

@RestControllerAdvice
@Slf4j
public class GlobalException {

    @ExceptionHandler(value = {NullPointerException.class})
    public String nullPointerException(Model model,Exception e){
        model.addAttribute("msg",e.getMessage());
        log.info(e.getMessage());
        return "error2";
    }

    @ExceptionHandler(value = {ArithmeticException.class})
    public ResultData<String> arithmeticException(Exception e){
        log.info(e.getMessage());
        return ResultData.error(ReturnCode.SYSTEM_ERROR.getCode(), e.getMessage());
    }

    @ExceptionHandler(value = {BizException.class})
    public ResultData<String> bizException(Exception e){
        log.info(e.getMessage());
        return ResultData.error(ReturnCode.SYSTEM_ERROR.getCode(), e.getMessage());
    }

    @ExceptionHandler(value = {Exception.class})
    public ResultData<String> exception(Exception e){
        log.info(e.getMessage());
        return ResultData.error(ReturnCode.SYSTEM_ERROR.getCode(), e.getMessage());
    }

}

3.写错误

    @RequestMapping("index03")
    public String index03(){
        if(true){
            throw new BizException("业务忙");
        }

        return "index03";
    }

 

 

 


转:https://blog.csdn.net/asxyxxx/article/details/121806762

https://www.cnblogs.com/mxh-java/p/14319420.html

 

posted @ 2023-07-20 17:48  与f  阅读(518)  评论(0编辑  收藏  举报