spring boot api 统一处理消息返回体
日常工作中经常会和前端对接,提供统一的接口返回格式,但是我们每个接口关注的业务都不一样,按以往的写法,每次返回的时候都要去构造一个统一的返回类型,很麻烦。可以使用 ResponseBodyAdvice 来统一处理。上代码。
/** * @author pengbenlei * @Description * @create 2022-11-16 15:00 */ public enum ReturnCode { RC100(100, "操作成功"), RC404(404, "找不到资源"), RC500(500, "系统异常,请稍后重试"), RC1002(1002, "登录已过期,请重新登录"); /** * 自定义状态码 **/ private final int code; /** * 自定义描述 **/ private final String message; ReturnCode(int code, String message) { this.code = code; this.message = message; } public int getCode() { return code; } public String getMessage() { return message; } }
import com.leenleda.data.synchronism.common.enums.ReturnCode; import lombok.Data; /** * @author pengbenlei * @Description * @create 2022-11-16 15:00 */ @Data public class ResultData<T> { private int status; private String message; private T data; private long timestamp ; public ResultData (){ this.timestamp = System.currentTimeMillis(); } public static <T> ResultData<T> success(T data) { ResultData<T> resultData = new ResultData<>(); resultData.setStatus(ReturnCode.RC100.getCode()); resultData.setMessage(ReturnCode.RC100.getMessage()); resultData.setData(data); return resultData; } public static <T> ResultData<T> success() { ResultData<T> resultData = new ResultData<>(); resultData.setStatus(ReturnCode.RC100.getCode()); resultData.setMessage(ReturnCode.RC100.getMessage()); return resultData; } public static <t> ResultData<t> fail(int code, String message) { ResultData<t> resultData = new ResultData<>(); resultData.setStatus(code); resultData.setMessage(message); return resultData; } }
import com.fasterxml.jackson.databind.ObjectMapper; import com.leenleda.data.synchronism.common.enums.ReturnCode; import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import java.util.Map; /** * @author pengbenlei * @Description * @create 2022-11-16 15:03 */ @RestControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice<Object> { @Autowired private ObjectMapper objectMapper; @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; } @SneakyThrows @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { if (o == null) { // 返回void return ResultData.success(); } if (o instanceof String) { return objectMapper.writeValueAsString(ResultData.success(o)); } if (o instanceof ResultData) { return o; } if (o instanceof Map) { if (((Map<?, ?>) o).get("status").equals(ReturnCode.RC404.getCode())) { return ResultData.fail(ReturnCode.RC404.getCode(), ReturnCode.RC404.getMessage()); }else if (((Map<?, ?>) o).get("status").equals(ReturnCode.RC500.getCode())) { return ResultData.fail(ReturnCode.RC500.getCode(), ReturnCode.RC500.getMessage()); } } return ResultData.success(o); } }
以上基本就能满足功能了,但是如果有异常的话,还是不能统一到咋们这个里面来,所以还需要加个,全局的异常拦截。
import lombok.Data; /** * @author pengbenlei * @Description * @create 2022-11-16 15:02 */ @Data public class BusinessException extends RuntimeException { private int code = 100; private String message; public BusinessException(int code, String msg) { this.code = code; this.message = msg; } }
import com.leenleda.data.synchronism.admin.dto.response.ResultData; import com.leenleda.data.synchronism.common.enums.ReturnCode; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.NoHandlerFoundException; import java.util.List; /** * @author pengbenlei * @Description * @create 2022-11-16 15:01 */ @Slf4j @RestControllerAdvice public class RestExceptionHandler { /** * 默认全局异常处理。 * * @param exception the exception * @return ResultData */ @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResultData<String> validException(MethodArgumentNotValidException exception) { BindingResult result = exception.getBindingResult(); String message = ""; if (result.hasErrors()) { List<ObjectError> errors = result.getAllErrors(); if (errors != null) { if (errors.size() > 0) { FieldError fieldError = (FieldError) errors.get(0); message = fieldError.getDefaultMessage(); } } } log.error("接口入参验证异常捕获 ex={}", message, exception); return ResultData.fail(ReturnCode.RC500.getCode(), message); } /** * 404 异常 * * @param e the e * @return ResultData */ @ExceptionHandler(NoHandlerFoundException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResultData<String> notFoundException(NoHandlerFoundException e) { log.error("全局404异常信息 ex={}", e.getMessage(), e); return ResultData.fail(ReturnCode.RC404.getCode(), e.getMessage()); } /** * 默认全局异常处理。 * * @param e the e * @return ResultData */ @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResultData<String> exception(Exception e) { log.error("全局异常信息 ex={}", e.getMessage(), e); return ResultData.fail(ReturnCode.RC500.getCode(), e.getMessage()); } /** * 业务异常处理。 * * @param e the e * @return ResultData */ @ExceptionHandler(BusinessException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResultData<String> businessException(BusinessException e) { log.error("业务异常信息 ex={}", e.getMessage(), e); return ResultData.fail(e.getCode(), e.getMessage()); } }
自此,就弄完了,在平时使用时,只需要关注方法本身的返回值,例如:
/*** * 数据源列表 * @param pageIndex * @param pageSize * @return */ @GetMapping("/list") public PageVo getList(@RequestParam("page-index") int pageIndex, @RequestParam("page-size") int pageSize) { return datasourceInfoService.list(pageIndex, pageSize); }
甘于平凡,做一个甘于平凡的人,菜米油盐,生老病死。