1、定义通用的数据返回对象
@Data
@Accessors(chain = true)
public class GlobalResponse<T> implements Serializable {
private Integer code;
private String message;
private T data;
private final String timeStamp = DateUtils.localDateTimeToString(LocalDateTime.now());
public static final String SUCCESS = "成功";
public static final String FAILURE = "失败";
public GlobalResponse(int code, String message) {
this.code = code;
this.message = message;
}
public GlobalResponse(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static GlobalResponse<Object> success() {
return new GlobalResponse<Object>(200, SUCCESS);
}
public static GlobalResponse<Object> success(Object data) {
return new GlobalResponse<Object>(200, SUCCESS, data);
}
public static GlobalResponse<Object> failure() {
return new GlobalResponse<Object>(400, FAILURE);
}
public static GlobalResponse<Object> failure(Object data) {
return new GlobalResponse<Object>(400, FAILURE, data);
}
public static GlobalResponse<Object> failure(Object data, String sign) {
return new GlobalResponse<Object>(400, FAILURE, data);
}
}
GlobalResponse:这里我们定义通用的数据返回对象,并且提供一个正常数据返回/一个异常数据返回的快速设置方法。
/**
* 自定义异常
*/
public class GlobalException extends RuntimeException {
public GlobalException() {
}
public GlobalException(String message) {
super(message);
}
public GlobalException(String message, Throwable t) {
super(message, t);
}
}
设置注解
/**
* ResponseBody自定义注解,修饰在controller或者他的方法之上
* 如果修饰在controller之上,它所有的请求返回都需要组织自定义返回报文;
* 如果只修饰在方法上,该方法的请求返回都需要组织自定义返回报文;
* 如果没有修饰,则直接返回
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@ResponseBody
public @interface ResponseResultBody {
}
第二步:定义统一处理handler
异常拦截 implements ResponseBodyAdvice
import com.zsn.scheduler.annotation.ResponseResultBody;
import com.zsn.scheduler.exception.GlobalException;
import com.zsn.scheduler.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
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.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.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.annotation.Annotation;
import java.util.List;
/**
* 异常拦截
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler implements ResponseBodyAdvice<Object> {
private static final Class<? extends Annotation> ANNOTATION_TYPE = ResponseResultBody.class;
@ExceptionHandler(value = GlobalException.class)
public GlobalResponse<Object> globalException(GlobalException e) {
e.printStackTrace();
return GlobalResponse.failure(e.getMessage());
}
@ExceptionHandler(value = Exception.class)
public GlobalResponse<Object> exception(Exception e) {
e.printStackTrace();
return GlobalResponse.failure(e.getMessage());
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public GlobalResponse<Object> parameterExceptionHandler(MethodArgumentNotValidException e) {
e.printStackTrace();
BindingResult bindingResult = e.getBindingResult();
if (bindingResult.hasErrors()) {
List<ObjectError> errors = bindingResult.getAllErrors();
FieldError fieldError = (FieldError) errors.get(0);
log.warn("object name is " + fieldError.getObjectName());
log.warn("defaultMessage is " + fieldError.getDefaultMessage());
log.warn("field is" + fieldError.getField());
return GlobalResponse.failure(fieldError.getDefaultMessage());
} else {
return GlobalResponse.failure("参数绑定未知错误");
}
}
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return AnnotatedElementUtils.hasAnnotation(methodParameter.getContainingClass(), ANNOTATION_TYPE) || methodParameter.hasMethodAnnotation(ANNOTATION_TYPE);
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (o instanceof GlobalResponse) {
return o;
}
if (o instanceof String) {
//JsonUtils转换,使用的是ObjectMapperd对象,进行封装
//new ObjectMapper().writeValueAsString(GlobalResponse.success(o));
return JsonUtils.object2JsonString(GlobalResponse.success(o));
}
return GlobalResponse.success(o);
}
}
@RestControllerAdvice+@ExceptionHandler配合使用
首先,我们通过@RestControllerAdvice来定义一个controller增强处理器,可以通过配合使用@ExceptionHandler来进行异常的统一处理。
其次,通过实现ResponseBodyAdvice,对于数据的返回,进行进一步的处理,使得接口的返回值都是统一的对象。
supports方法是通过判断,是否执行beforeBodyWrite。supports返回ture表示执行,supports返回false表示不执行。
supports中的returnType可以获取到controller的类,参数和方法等。
通过方法名称可以看出该方法是在写body之前处理操作。可以根据这些参数判断是否需要改写body,以及改写成什么内容。