我印象中,通用返回接口设计是有两种方式,第一种是自定义返回数据的通用类,另一种是springboot中实现ResponseBodyAdvice接口,实现返回数据格式的统一,如我说的有错,请大佬指出。本篇文章主要讲解通过springboot实现的方式。
一、自定义返回数据的通用类的方式
二、springboot实现ResponseBodyAdvice接口的方式
- Entity
/**
* @author Cristianoxm
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private long id;
private String name;
private Integer age;
}
- 通用返回类
@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;
}
}
- 自定义处理业务异常类,注意
继承自RuntimeException,用于手动控制抛出异常.
/**
* @author Cristianoxm
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public final class ResponseException extends RuntimeException {
private String errorCode;
private String errorMsg;
}
- 实现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);
}
}
}
- 继承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);
}
}
- 捕获自定义的业务异常类
/**
* @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());
}
}
- 用于注解不经由ResponseAdvice处理的类方法
/**
* @author Cristianoxm
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoResponseAdvice {
}
- 状态码信息枚举类
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;
}
}
- 控制器类
@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。参考这篇文章
本文介绍如何使用SpringBoot实现统一的API返回格式,包括自定义返回类、异常处理及ResponseBodyAdvice接口的应用。




2300

被折叠的 条评论
为什么被折叠?



