在实际开发中,每个接口的返回格式是不一致的,对应前端接收和处理不方便。
而且抛出异常通过try
构造方法私有化,通过静态方法构建对应的返回对象
public class HttpResult<T> implements Serializable {
/** 是否响应成功 */
private Boolean success;
/** 响应状态码 */
private Integer code;
/** 响应数据 */
private T data;
/** 错误信息 */
private String message;
/**
* 无参构造器(构造器私有,外部不可以直接创建)
*/
private HttpResult() {
this.code = 200;
this.success = true;
}
/**
* 有参构造器
* @param obj
*/
private HttpResult(T obj) {
this.code = 200;
this.data = obj;
this.success = true;
}
/**
* 有参构造器
* @param resultCode
*/
private HttpResult(ResultCodeEnum resultCode) {
this.success = false;
this.code = resultCode.getCode();
this.message = resultCode.getMessage();
}
// 构造器结束
/**
* 通用返回成功(没有返回结果)
* @param
* @return
*/
public static<T> HttpResult<T> success(){
return new HttpResult();
}
/**
* 返回成功(有返回结果)
* @param data
* @param
* @return
*/
public static<T> HttpResult<T> success(T data){
return new HttpResult<T>(data);
}
/**
* 通用返回失败
* @param resultCode
* @param
* @return
*/
public static<T> HttpResult<T> failure(ResultCodeEnum resultCode){
return new HttpResult<T>(resultCode);
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "HttpResult{" +
"success=" + success +
", code=" + code +
", data=" + data +
", message='" + message + '\'' +
'}';
}
}
通过SpringBoot提供的ResponseBodyAdvice实现对全局的controller的响应结果进行处理。
ResponseBodyAdvice的作用:拦截Controller方法的返回值,统一处理返回值/响应体,一般用来统一返回格式,加解密,签名等等
@RestControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//TODO: 对响应进行处理,执行 beforeBodyWrite 方法\
return true;
}
/**
* @author: wujt
* @date: 2022/7/11
* @Title: beforeBodyWrite
* @Description : 对返回结果进行封装
* @param body
* @param returnType
* @param selectedContentType
* @param selectedConverterType
* @param request
* @param response
* @return java.lang.Object
*/
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if(body instanceof String){
return body;
}
return HttpResult.success(body);
}
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreResponseAdvice {
}
前面全局响应处理器中有support方法,只有为true时才进行处理。
通过反射,让方法或者类有有IgnoreResponseAdvice注解时,返回false,不进行处理。
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//当前类使用IgnoreResponseAdvice注解,不进行处理
if (returnType.getDeclaringClass().isAnnotationPresent(
IgnoreResponseAdvice.class
)) {
return false;
}
//当前方法使用IgnoreResponseAdvice注解,不进行处理
if (returnType.getMethod().isAnnotationPresent(
IgnoreResponseAdvice.class
)) {
return false;
}
//TODO: 对响应进行处理,执行 beforeBodyWrite 方法\
return true;
}
也是通过ResponseBodyAdvice实现对全局的controller的响应结果进行处理,不同的是,新增了**@ExceptionHandler**注解。
@ExceptionHandler:统一处理某一类异常,从而减少代码重复率和复杂度
打印日志内容,除了异常内容还加了getStackTrace(),如果只是单纯异常内容,无法定位是从那个方法那一行出现了问题,因为被全局异常处理器拦截,统一都在异常处理器这里打印了。
@RestControllerAdvice
@Slf4j
public class ExceptionHandler {
/**
* @author: wujt
* @date: 2022/7/11
* @Title: handlerException
* @Description : 对捕获的异常进行处理和封装返回结果
* @param e
* @return com.southgis.ibase.infosvr.common.other.constant.entity.HttpResult
*/
@ExceptionHandler(Exception.class)
public HttpResult handlerException(Exception e){
ResultCodeEnum resultCodeEnum = ResultCodeEnum.SERVER_ERROR;
resultCodeEnum.setMessage(e.getMessage());
log.error("common exception:{}",e.toString()+"\n"+ Arrays.asList(e.getStackTrace()).toString());
return HttpResult.failure(resultCodeEnum);
}
}
在上面通过捕获异常后进行封装,然后系统还会进行结果的封装,导致重复封装。
通过封装时,根据结果类型判断是否封装:
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//当结果已经是封装过的,不再进行二次封装(主要是处理异常封装导致重复封装)
if(body instanceof HttpResult){
//根据业务需求需要设计对应的响应码
if(!body.getSuccess()){
response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
}
return body;
}
if(body instanceof String){
return body;
}
return HttpResult.success(body);
}