Controller規范

要說Controller的規范,主要的內容是就是接口定義里面的內容,你只要遵循里面的規范,controller就問題不大,除了這些,還有另外的幾點:

1 所有函數返回統一的ResultBean/PageResultBean格式,原因見接口定義這個貼。沒有統一格式,AOP無法玩。
2 ResultBean/PageResultBean是controller專用的,不允許往后傳!
3 Controller做參數格式的轉換,不允許把json,map這類對象傳到services去,也不允許services返回json、map。

寫過代碼都知道,map,json這種格式靈活,但是可讀性差,如果放業務數據,每次閱讀起來都比較困難。定義一個bean看著工作量多了,但代碼清晰多了。

4 參數中一般情況不允許出現Request,Response這些對象。

主要是因為可讀性問題。

5 不需要打印日志

日志在AOP里面會打印,而且我的建議是大部分日志在Services這層打印。
規范里面大部分是不要做的項多,要做的比較少,落地比較容易。

ResultBean定義帶泛型,使用了lombok。

@Data
public class ResultBean<T> implements Serializable {

  private static final long serialVersionUID = 1L;

  public static final int NO_LOGIN = -1;

  public static final int SUCCESS = 0;

  public static final int FAIL = 1;

  public static final int NO_PERMISSION = 2;

  private String msg = "success";

  private int code = SUCCESS;

  private T data;

  public ResultBean() {
    super();
  }

  public ResultBean(T data) {
    super();
    this.data = data;
  }

  public ResultBean(Throwable e) {
    super();
    this.msg = e.toString();
    this.code = FAIL;
  }
}

AOP代碼,主要就是打印日志和捕獲異常,異常要區分已知異常和未知異常,其中未知的異常是我們重點關注的,可以做一些郵件通知啥的,已知異常可以再細分一下,可以不同的異常返回不同的返回碼:

/**
 * 處理和包裝異常
 */
public class ControllerAOP {
  private static final Logger logger = LoggerFactory.getLogger(ControllerAOP.class);

  public Object handlerControllerMethod(ProceedingJoinPoint pjp) {
    long startTime = System.currentTimeMillis();

    ResultBean<?> result;

    try {
      result = (ResultBean<?>) pjp.proceed();
      logger.info(pjp.getSignature() + "use time:" + (System.currentTimeMillis() - startTime));
    } catch (Throwable e) {
      result = handlerException(pjp, e);
    }

    return result;
  }

  private ResultBean<?> handlerException(ProceedingJoinPoint pjp, Throwable e) {
    ResultBean<?> result = new ResultBean();

    // 已知異常
    if (e instanceof CheckException) {
      result.setMsg(e.getLocalizedMessage());
      result.setCode(ResultBean.FAIL);
    } else if (e instanceof UnloginException) {
      result.setMsg("Unlogin");
      result.setCode(ResultBean.NO_LOGIN);
    } else {
      logger.error(pjp.getSignature() + " error ", e);
      //TODO 未知的異常,應該格外注意,可以發送郵件通知等
      result.setMsg(e.toString());
      result.setCode(ResultBean.FAIL);
    }

    return result;
  }
}

AOP配置:(關于用java代碼還是xml配置,這里我傾向于xml配置,因為這個會不定期改動)

<!-- aop -->
  <aop:aspectj-autoproxy />
  <beans:bean id="controllerAop" class="xxx.common.aop.ControllerAOP" />
  <aop:config>
    <aop:aspect id="myAop" ref="controllerAop">
      <aop:pointcut id="target"
        expression="execution(public xxx.common.beans.ResultBean *(..))" />
      <aop:around method="handlerControllerMethod" pointcut-ref="target" />
    </aop:aspect>
  </aop:config>

現在知道為什么要返回統一的一個ResultBean了:

  • 為了統一格式
  • 為了應用AOP
  • 為了包裝異常信息

分頁的PageResultBean大同小異,大家自己依葫蘆畫瓢自己完成就好了。

貼一個簡單的controller(左邊的箭頭表示AOP攔截了)。請對比 程序員你為什么這么累?里面原來的代碼查看,沒有對比就沒有傷害。

image.png

最后說一句,先有統一的接口定義規范,然后有AOP實現。先有思想再有技術。技術不是關鍵,AOP技術也很簡單,這個帖子的關鍵點不是技術,而是習慣和思想,不要撿了芝麻丟了西瓜。網絡上講技術的貼多,講習慣、風格的少,這些都是我工作多年的行之有效的經驗之談,望有緣人珍惜。

上一篇:《接口規范》
下一篇:《日志建議》

本文原著作者:曉風輕
原文鏈接:https://zhuanlan.zhihu.com/p/28705206
版權歸作者所有,轉載請注明出處

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,269評論 25 708
  • 工作中,少不了要定義各種接口,系統集成要定義接口,前后臺掉調用也要定義接口。接口定義一定程度上能反應程序員的編程功...
    justmilkrain閱讀 653評論 1 3
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 前言 最近接手了兩個 O2O 的老項目,其中的 Bug 也不言而喻,單看項目中的布局就有 n 種不同的方式,有用純...
    tingxins閱讀 6,120評論 14 37