咖啡汪日志———搭建灵活的统一响应模型,应对各种响应情况

本汪作为一名资深的哈士奇
每天除了闲逛,拆家,就是啃博客了
作为不是在戏精,就是在戏精的路上的二哈
今天就来给大家说说前后端分离项目-,如何搭建灵活的统一响应模型吧
它将灵活应对各种响应需求
(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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖啡汪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值