本文想法是在Controller最外层返回时封装一个结构,减少冗余代码。
本文涉及技术点:枚举,范型,重写框架ResponseBody返回代码 2020.1.2—1.0 初版 对于controller类返回统一封装 2020.1.2—1.1 对异常情况处理,利用aop切面实现
一、前提背景
1、Controller代码如下
@Controller
public class TestController {
@GetMapping("/test")
@ResponseBody //当类使用RestController可以不需要此标注
public String test() {
String text = "do something";
System.out.println(text);
return text;
}
}
2、此时postman测试调用后发现结果不美观
3、发生错误时,返回信息也没有进行封装。
二、设计思路
1、构建一个配置类实现InitializingBean接口,
2、在创建bean时修改HandlerMethodReturnValueHandler中RequestResponseBodyMethodProcessor代码
3、封装一个统一返回结果
4、封装一个自定义异常类,继承RuntimeException异常,结合返回枚举。
5、处理类利用@ControllerAdvice切面处理,方法使用@ExceptionHandler,@ResponseBody直接返回前台
三、代码演示
1、回参信息枚举类
package com.vvvv.util.returnHandler;
/**
* 返回信息枚举
*/
public enum ReturnInfoEnum {
SUCCESS(0,"success"),
ERROR(-1,"error"),
NET_ERROR(-9001,"network error."),
UNKNOWN_ERROR(-9999,"unknow error."),
;
private Integer code;
private String msg;
ReturnInfoEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
2、统一返回类方法封装
package com.vvvv.util.returnHandler;
import lombok.Data;
/**
* @ClassName Return
* @Description 返回类方法封装
* @Author vvvv
* @Date 2021/1/2 19:37
* @Version V1.0
*/
@Data
public class Return<T> {
private Integer code;
private String msg;
private T data;
private Return(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
private Return(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static <T> Return<T> success() {
return new Return<T>(ReturnInfoEnum.SUCCESS.getCode(),
ReturnInfoEnum.SUCCESS.getMsg());
}
public static <T> Return<T> success(T data) {
return new Return<>(ReturnInfoEnum.SUCCESS.getCode(),
ReturnInfoEnum.SUCCESS.getMsg(), data);
}
public static <T> Return<T> error(Integer code, String msg) {
return new Return<>(code, msg);
}
}
3、构建配置类 RenturnHandlerAdapter
/**
* @ClassName RenturnHandlerAdapter
* @Description 接口返回统一处理配置类
* @Author vvvv
* @Date 2021/1/2 19:41
* @Version V1.0
*/
@Configuration // 声明是spring配置,创建bean
@RequiredArgsConstructor // 构建有参构造函数
public class RenturnHandlerAdapter implements InitializingBean {
// 获取到RequestMappingHandlerAdapter的结果
private final RequestMappingHandlerAdapter handlerAdapter;
@Override
public void afterPropertiesSet() {
// 根据适配器拿到返回处理集合
List<HandlerMethodReturnValueHandler> returnValueHandlers =
handlerAdapter.getReturnValueHandlers();
List<HandlerMethodReturnValueHandler> newList = new ArrayList<>();
// RequestResponseBodyMethodProcessor
// 构建新类实现HandlerMethodReturnValueHandler接口
// 重写接口,完成
Objects.requireNonNull(returnValueHandlers).forEach(
t -> {
if (t instanceof RequestResponseBodyMethodProcessor)
newList.add(new ReturnHandlerAdaptProxy(t));
else newList.add(t);
}
);
// 将新处理集合放回适配器中
handlerAdapter.setReturnValueHandlers(newList);
}
}
4、接口返回统一处理类 ReturnHandlerAdaptProxy
/**
* @ClassName ReturnHandlerAdaptProxy
* @Description 接口返回统一处理类
* @Author vvvv
* @Date 2021/1/2 19:49
* @Version V1.0
*/
public class ReturnHandlerAdaptProxy implements HandlerMethodReturnValueHandler {
private final HandlerMethodReturnValueHandler proxyObject;
public ReturnHandlerAdaptProxy(HandlerMethodReturnValueHandler proxyObject) {
this.proxyObject = proxyObject;
}
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return proxyObject.supportsReturnType(returnType);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
Return result =
returnValue == null ? Return.success() : Return.success(returnValue);
// 此处对Object进行封装返回即可
proxyObject.handleReturnValue(result, returnType, mavContainer, webRequest);
}
}
5、自定义异常类
@Getter //lombok getter注解
//继承RuntimeException
public class VurxException extends RuntimeException {
//错误编码
private final Integer code;
public VurxException(ReturnInfoEnum resultEnum) {
// 调用父类构造方法,将错误信息写入
super(resultEnum.getMsg());
// 补充错误编码
this.code = resultEnum.getCode();
}
}
6、异常处理类
@ControllerAdvice // 环绕controller切面
@Slf4j // lombok注解
public class ExceptionHandle {
// !!!抛出异常自动进入该方法!!!
@ExceptionHandler(value = Exception.class)
@ResponseBody // 返回前台结果
public Return<Object> handle(Exception e) {
log.error("======ERROR=========================================================================", e);
// 异常类型属于自定义异常时封装返回前台
if (e instanceof VurxException) {
VurxException vurxException = (VurxException) e;
return Return.error(vurxException.getCode(), vurxException.getMessage());
}
// 其他异常抛出未知异常
return Return.error(ReturnInfoEnum.UNKNOWN_ERROR.getCode(), e.getMessage());
}
}
四、测试代码
1、统一返回测试
a、测试controller
@Controller
public class TestController {
@GetMapping("/test")
@ResponseBody //当类使用RestController可以不需要此标注
public String test() {
String text = "do something";
System.out.println(text);
return text;
}
}
b、成功结果
2、异常测试
a、Controller类
@Controller
public class TestController {
@GetMapping("/test")
@ResponseBody
public String test() {
String text = "do something";
if (text.startsWith("do")) {
throw new VurxException(ReturnInfoEnum.NET_ERROR);
} else {
return text;
}
}
}