公司从大厂挖了一个资深工程师,他写的Controller代码同事都说漂亮! 下

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 公司从大厂挖了一个资深工程师,他写的Controller代码同事都说漂亮! 下

2. NOT统一响应

  • 不开启统一响应原因

开发小哥是开心了,可是其他系统就不开心了。举个例子:我们项目中集成了一个健康检测的功能,也就是这货

@RestController
public class HealthController {
    @GetMapping("/health")
    public String health() {
        return "success";
    }
}

公司部署了一套校验所有系统存活状态的工具,这工具就定时发送get请求给我们系统

  • “兄弟,你死了吗?”
  • “我没死,滚”
  • “兄弟,你死了吗?”
  • “我没死,滚”

是的,web项目的本质就是复读机。一旦发送的请求没响应,就会给负责人发信息(企业微信或者短信之类的),你的系统死啦!赶紧回来排查bug吧!让大家感受一下。每次看到我都射射发抖,早上6点!我tm!!!!!

好吧,没办法,人家是老大,人家要的返回不是

{
  "code": 1000,
  "msg": "请求成功",
  "data": "success"
}

人家要的返回只要一个success,人家定的标准不可能因为你一个系统改。俗话说的好,如果你改变不了环境,那你就只能我****

  • 新增不进行封装注解

因为百分之99的请求还是需要包装的,只有个别不需要,写在包装的过滤器吧?又不是很好维护,那就加个注解好了。所有不需要包装的就加上这个注解。

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotControllerResponseAdvice {
}

然后在我们的增强过滤方法上过滤包含这个注解的方法

@RestControllerAdvice(basePackages = {"com.bugpool.leilema"})
public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        // response是ResultVo类型,或者注释了NotControllerResponseAdvice都不进行包装
        return !(methodParameter.getParameterType().isAssignableFrom(ResultVo.class)
                || methodParameter.hasMethodAnnotation(NotControllerResponseAdvice.class));
    }
    ...

最后就在不需要包装的方法上加上注解

@RestController
public class HealthController {
    @GetMapping("/health")
    @NotControllerResponseAdvice
    public String health() {
        return "success";
    }
}

这时候就不会自动封装了,而其他没加注解的则依旧自动包装

image.png

五、统一异常

每个系统都会有自己的业务异常,比如库存不能小于0子类的,这种异常并非程序异常,而是业务操作引发的异常,我们也需要进行规范的编排业务异常状态码,并且写一个专门处理的异常类,最后通过刚刚学习过的异常拦截统一进行处理,以及打日志

1.异常状态码枚举,既然是状态码,那就肯定要实现我们的标准接口StatusCode

@Getter
public enum  AppCode implements StatusCode {
    APP_ERROR(2000, "业务异常"),
    PRICE_ERROR(2001, "价格异常");
    private int code;
    private String msg;
    AppCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

2.异常类,这里需要强调一下,code代表AppCode的异常状态码,也就是2000;msg代表业务异常,这只是一个大类,一般前端会放到弹窗title上;最后super(message);这才是抛出的详细信息,在前端显示在弹窗体中,在ResultVo则保存在data中

@Getter
public class APIException extends RuntimeException {
    private int code;
    private String msg;
    // 手动设置异常
    public APIException(StatusCode statusCode, String message) {
        // message用于用户设置抛出错误详情,例如:当前价格-5,小于0
        super(message);
        // 状态码
        this.code = statusCode.getCode();
        // 状态码配套的msg
        this.msg = statusCode.getMsg();
    }
    // 默认异常使用APP_ERROR状态码
    public APIException(String message) {
        super(message);
        this.code = AppCode.APP_ERROR.getCode();
        this.msg = AppCode.APP_ERROR.getMsg();
    }
}

3.最后进行统一异常的拦截,这样无论在service层还是controller层,开发人员只管抛出API异常,不需要关系怎么返回给前端,更不需要关心日志的打印

@RestControllerAdvice
public class ControllerExceptionAdvice {
    @ExceptionHandler({BindException.class})
    public ResultVo MethodArgumentNotValidExceptionHandler(BindException e) {
        // 从异常对象中拿到ObjectError对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        return new ResultVo(ResultCode.VALIDATE_ERROR, objectError.getDefaultMessage());
    }
    @ExceptionHandler(APIException.class)
    public ResultVo APIExceptionHandler(APIException e) {
        // log.error(e.getMessage(), e); 由于还没集成日志框架,暂且放着,写上TODO
        return new ResultVo(e.getCode(), e.getMsg(), e.getMessage());
    }
}

4.最后使用,我们的代码只需要这么写

if (null == orderMaster) {
  throw new APIException(AppCode.ORDER_NOT_EXIST, "订单号不存在:" + orderId);
}
{
  "code": 2003,
  "msg": "订单不存在",
  "data": "订单号不存在:1998"
}

就会自动抛出AppCode.ORDER_NOT_EXIST状态码的响应,并且带上异常详细信息订单号不存在:xxxx。后端小哥开发有效率,前端妹妹获取到2003状态码,调用对应警告弹窗,title写上订单不存在,body详细信息记载"订单号不存在:1998"。同时日志还自动打上去了!666!老哥们三连点个赞!



相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
运维 架构师 网络架构
公司架构师说不写代码,我直接怼他了!
公司架构师说不写代码,我直接怼他了!
68 2
|
运维 监控 数据可视化
当开发同事辞职,接手到垃圾代码怎么办?
当开发同事辞职,接手到垃圾代码怎么办?
|
消息中间件 JSON 前端开发
公司从大厂挖了一个资深工程师,他写的Controller代码同事都说漂亮! 上
公司从大厂挖了一个资深工程师,他写的Controller代码同事都说漂亮! 上
|
程序员 项目管理
程序员成长第十九篇:要不要转管理岗?
程序员成长第十九篇:要不要转管理岗?
264 0
程序员成长第十九篇:要不要转管理岗?
|
网络性能优化 双11
这位三个月就想辞职的阿里工程师,现在,真香!
他前段时间和剑桥大学教授 Frank Kelly 合作,设计了新一代高速网络拥塞控制协议 HPCC。
453 0
这位三个月就想辞职的阿里工程师,现在,真香!
|
Java 测试技术 项目管理
15 年经验资深测试经理的经验分享:测试人职场晋升“潜规则”
本文整理自霍格沃兹测试学院「测试开发在线沙龙」主题分享《测试人晋升指南:如何做好个人绩效管理》,略有删减。文末链接进阶学习。
15 年经验资深测试经理的经验分享:测试人职场晋升“潜规则”
|
前端开发
真香!阿里工程师的一段代码让我看饿了
阿里妹导读:打开盒马app,相信你跟阿里妹一样,很难抵抗各种美味的诱惑。颜值即正义,盒马的图片视频技术逼真地还原了食物细节,并在短短数秒内呈现出食物的最佳效果。今天,我们请来阿里高级无线开发工程师莱宁,解密盒马app里那些“美味”视频是如何生产的。
7013 0
|
安全 架构师 网络协议
Google 测试总监聊如何经营成功的测试职业生涯
​重温经典:本文是前 Google 测试总监 James A. Whittaker 的经典分享,成文已经快 10 年了,但经典却总是常读常新,推荐给各位测试行业的从业人员。:)