Java后端返回通用接口设计

本文介绍如何使用SpringBoot实现统一的API返回格式,包括自定义返回类、异常处理及ResponseBodyAdvice接口的应用。

我印象中,通用返回接口设计是有两种方式,第一种是自定义返回数据的通用类,另一种是springboot中实现ResponseBodyAdvice接口,实现返回数据格式的统一,如我说的有错,请大佬指出。本篇文章主要讲解通过springboot实现的方式。

一、自定义返回数据的通用类的方式

这里我推荐这篇文章

二、springboot实现ResponseBodyAdvice接口的方式

  1. Entity
/**
 * @author Cristianoxm
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private long id;
    private String name;
    private Integer age;
}
  1. 通用返回类
@Data
@AllArgsConstructor
@NoArgsConstructor
public final class CommonResult<T> {
    private int status = 1;
    private String code = "";
    private String msg = "";
    private T resultBody;
    public CommonResult(T resultBody) {
        this.resultBody = resultBody;
    }
    /**
     * 统一的成功返回方法
     * @param successCode
     * @param successMsg
     * @param resultBody
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> successResult(String successCode,String successMsg,T resultBody)
    {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.code = successCode;
        commonResult.msg = successMsg;
        commonResult.resultBody=resultBody;
        commonResult.status = 1;
        return commonResult;
    }
    /**
     * 统一处理异常的方法
     * @param errorCode
     * @param errorMsg
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> errorResult(String errorCode, String errorMsg){
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.code = errorCode;
        commonResult.msg = errorMsg;
        commonResult.status = -1;
        return commonResult;
    }
}
  1. 自定义处理业务异常类,注意继承自RuntimeException,用于手动控制抛出异常.
/**
 * @author Cristianoxm
 */
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public final class ResponseException extends RuntimeException {
    private String errorCode;
    private String errorMsg;
}
  1. 实现ResponseBodyAdvice接口
@EnableWebMvc
@Configuration
public class UnifiedReturnConfig {
    @RestControllerAdvice("com.commontest.demo.controller")
    static class CommonResultResponseAdvice implements ResponseBodyAdvice<Object> {
        /**
         * supports方法是来给定条件判断是否该调用beforeBodyWrite,MethodParameter里面有各种数据
         * @param methodParameter
         * @param aClass
         * @return
         */
        @Override
        public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
            boolean isIntercept = true;
            Method method = methodParameter.getMethod();
            assert method != null;
//          不拦截@NoResponseAdvice接口
            AnnotatedElement annotatedElement = methodParameter.getAnnotatedElement();
            NoResponseAdvice noResponseAdvice = AnnotationUtils.findAnnotation(annotatedElement, NoResponseAdvice.class);
            if(noResponseAdvice!=null){
                isIntercept = false;
            }
            return isIntercept;
        }

        /**
         * 定义自己返回的数据结构体
         * @param body 准备处理的返回数据
         * @param methodParameter 控制层返回的数据结构类型
         * @param mediaType 通过内容协商选择内容类型
         * @param aClass 选择要写入响应的转换器类型
         * @param serverHttpRequest 当前请求对象
         * @param serverHttpResponse 返回对象
         * @return 传入或修改(可能是新实例)的主体
         */
        @Override
        public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
            //若是CommonResult类型,直接返回,否则封装后再返回
            if (body instanceof CommonResult){
                return body;
            }
            return CommonResult.successResult(StatusAndMsg.SUCCESS.getCode(),StatusAndMsg.SUCCESS.getMsg(),body);
        }
    }
}
  1. 继承ResponseEntityExceptionHandler,封装异常(400,404,500)处理
@Slf4j
@ControllerAdvice
public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler {
    public RestResponseExceptionHandler() {
        super();
    }
    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception e, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        if (e instanceof MissingServletRequestParameterException) {
            return new ResponseEntity(CommonResult.errorResult("400", e.getMessage()), headers, status);
        }
        if (e instanceof NoHandlerFoundException) {
            return new ResponseEntity(CommonResult.errorResult("404", e.getMessage()), headers, status);
        }
        if(e instanceof HttpRequestMethodNotSupportedException){
            return new ResponseEntity(CommonResult.errorResult("405", e.getMessage()), headers, status);
        }
        return new ResponseEntity(CommonResult.errorResult("500", e.getMessage()), headers, status);
    }
}
  1. 捕获自定义的业务异常类
/**
 * @author Cristianoxm
 */
@RestControllerAdvice("com.commontest.demo.controller")
public class ResponseExceptionHandler{
    /**
     * 捕捉自定义异常类
     * @param responseException
     * @return
     */
    @ExceptionHandler(ResponseException.class)
    public CommonResult<Void> handleResponseException(ResponseException responseException){
        return CommonResult.errorResult(responseException.getErrorCode(), responseException.getErrorMsg());

    }
}
  1. 用于注解不经由ResponseAdvice处理的类方法
/**
 * @author Cristianoxm
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoResponseAdvice {
}
  1. 状态码信息枚举类
public enum StatusAndMsg {
    SUCCESS("1000", "SUCCESS"),
    METHODFAIL("2000", "ENCOUNTER AN ERROR WHEN EXECUTE METHOD"),
    UNKNOWEXCEPTION("3000", "THIS IS AN UNKNOW EXCEPTION");
    ERROR404("404","There was an unexpected error (type=Bad Request, status=400)"),
    ERROR500("500","There was an unexpected error (type=Internal Server Error, status=500)");
    private String code;
    private String msg;
    StatusAndMsg(String code, String msg){
        this.code = code;
        this.msg = msg;
    }
    public String getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
}
  1. 控制器类
@RequestMapping("/users")
@RestController
public class UserController {
    @GetMapping("/get")
    public List<User> getUserList(){
        List<User> userList =new ArrayList<>();
        userList.add(new User(1l,"messi",23));
        userList.add(new User(2l,"cristiano",23));
        return userList;
    }
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id){
        throw new ResponseException(StatusAndMsg.METHODFAIL.getCode(),StatusAndMsg.METHODFAIL.getMsg());
    }
    @GetMapping("/getStr")
    @NoResponseAdvice
    public String paramTest() {
        return "str";
    }
    @GetMapping("/testVoid")
    @NoResponseAdvice
    public void testVoid()
    {
        System.out.println("test void");
    }
}

注意,不要直接使用Exception捕捉全局异常,不然会导致虽然json返回了404状态码,但是http请求的状态码仍然是200。参考这篇文章

三、测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果有啥写的不好的,麻烦各位大佬指出。
参考文章
参考文章
参考文章
详细代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值