日常工作中经常会和前端对接,提供统一的接口返回格式,但是我们每个接口关注的业务都不一样,按以往的写法,每次返回的时候都要去构造一个统一的返回类型,很麻烦。可以使用 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);
}