本汪作为一名资深的哈士奇
每天除了闲逛,拆家,就是啃博客了
作为不是在戏精,就是在戏精的路上的二哈
今天就来给大家说说前后端分离项目-,如何搭建灵活的统一响应模型吧
它将灵活应对各种响应需求
(1)BaseResponse 标准基本响应模块
(2)自定义注解@IgnoreResponseAdvice, 他是对BaseResponse的增强,用来应对非标准返回的需求
一、基本响应类型的定义
思维导图如下,建议大家结合着看
源码地址:https://github.com/HuskyYue/ConvenienceServices
这个本汪说下,这是本汪自己的一个开源项目Demo,专门提供给大家学习用,内部有RabbitMQ日志记录,邮件发送,基于Redis发布订阅的商户通知等,有需要可以看本汪相关博客
1.编写工具类,借助org.springframework.validation.BindingResult,进行前端传过来参数的统一校验
本汪建议:大家可以多了解一下java8的新特性
闭包,Stream流,可读性不一定好,但代码会有一些简化,推荐《java实战(第二版)》
public class ValidatorUtil {
//TODO:统一校验前端传递过来的参数
public static String checkResult(BindingResult result){
StringBuilder sb=new StringBuilder("");
if (result.hasErrors()){
//java8 steam api
result.getAllErrors().forEach(error -> sb.append(error.getDefaultMessage()).append("\n"));
}
return sb.toString();
}
}
2.创建状态码的维护实体类
code为状态码,msg为错误信息,可根据业务需要添加enum类型,设置响应的code,msg,
本汪说明下:此处配置的msg信息,在异常抛出时会被前端统一拦截,作为 提示内容反馈给用户,篇幅原因,就顺便写了几个examples
public enum StatusCode {
Success(200,"success"),
Fail(500,"false"),
InvalidParams(300,"非法的参数!"),
UserNameHasExist(301,"用户名已存在"),
UserEmailHasExist(302,"用户邮箱已存在")
;
private Integer code;
private String msg;
StatusCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public void setCode(Integer code) {
this.code = code;
}
3.创建基本响应类实体BaseResponse
因为是统一响应,所以她的data类型选用泛型,data就是我们平时方法调用,返回的数据
public class BaseResponse<T> implements Serializable {
private Integer code;
private String msg;
private T data;
public BaseResponse(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public BaseResponse(StatusCode statusCode) {
this.code = statusCode.getCode();
this.msg = statusCode.getMsg();
}
}
4.写个测试用的controller,测试看看吧
@RequestMapping("base")
public class BaseController {
private static final Logger log = LoggerFactory.getLogger(BaseController.class);
@RequestMapping("info")
public BaseResponse info(@RequestParam String name) {
if (StringUtils.isBlank(name)) {
return new BaseResponse(StatusCode.InvalidParams);
}
BaseResponse response = new BaseResponse(StatusCode.Success);
try {
//TODO 核心业务逻辑
if (StringUtil.isBlank(name)){
name = "李白最爱安琪拉";
}
response.setData(name);
} catch (Exception e) {
response = new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
}
看看postman测试结果:
5.再看个例子
如果插入操作有异常抛出,会直接报500,msg内容即是我们开始配置的 Fail(500,"false"),
public BaseResponse addUserVip(@RequestBody @Validated User user, BindingResult result) {
String checkRes = ValidatorUtil.checkResult(result);
if (StringUtil.isNotBlank(checkRes)) {
return new BaseResponse(StatusCode.InvalidParams.getCode(),checkRes);
}
BaseResponse response = new BaseResponse(StatusCode.Success);
try {
//TODO:写真正的核心业务逻辑
userMapper.insertSelective(user);
} catch (Exception e) {
response = new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
本汪说下,这个很简单,很容易看懂,想要整合到自己代码,可以自行查看源码
二、如何应对特殊需求返回类型
1、编写自定义注解@IgnoreResponseAdvice
/**
* 自定义忽略统一响应注解
* **
* Yuezejian Created in 2020/11/5 下午9:51
*/
@Target({
ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreResponseAdvice {
}
2、BaseResponseDataAdvice类,对返回数据的增强

/**
* 统一响应模型的增强(应对多变的特殊返回情况))
* **
* Yuezejian Created in 2020/11/5 下午9:55
*/
@RestControllerAdvice
public class BaseResponseDataAdvice implements ResponseBodyAdvice<Object> {
/**
* 判断是否需要对响应进行处理
* @param methodParameter 当前controller的声明方法
* @param aClass
* @return 返回 true 需要对响应进行处理
*/
@Override
@SuppressWarnings("all")
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
//TODO: if currency class marked the @IgnoreResponseAdvice, no handler
if (methodParameter.getDeclaringClass().isAnnotationPresent(
IgnoreResponseAdvice.class
)) {
return false;
}
//TODO: if currency method marked the @IgnoreResponseAdvice, no handler
if (methodParameter.getMethod().isAnnotationPresent(
IgnoreResponseAdvice.class
)) {
return false;
}
//TODO: 对响应进行处理,执行 beforeBodyWrite 方法
return true;
}
/**
* 如果 supports 返回 true
* 在 Body 写入响应流之前,进行处理
* @param o controller 的返回对象
* @param methodParameter controller 的声明方法
* @param mediaType
* @param aClass
* @param serverHttpRequest
* @param serverHttpResponse
* @return
*/
@Override
@SuppressWarnings("all")
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
//TODO: 定义最终的返回对象
BaseResponse<Object> response = new BaseResponse<>(
0,""
);
// if Object o is null, resopnse won't need to set data
if ( o == null ) {
return response;
// if Object o has been BaseResponse, no handler
} else if ( o instanceof BaseResponse) {
response = (BaseResponse<Object>) o;
} else {
// overthen , set Object o as the data of response
response.setData(o);
}
return response;
}
}