基于spring-boot的快速業(yè)務(wù)開發(fā)框架

我們想要的(Fast-Clean-Robust)

  • Fast
    代碼風(fēng)格需要統(tǒng)一淆衷,方便團(tuán)隊(duì)共同作戰(zhàn)
    所有的中間件,配置即可用渤弛。
    統(tǒng)一返回結(jié)果數(shù)據(jù)結(jié)構(gòu)祝拯,方便代碼重用和前端邏輯抽象
    根據(jù)業(yè)務(wù)設(shè)計(jì)數(shù)據(jù)庫表結(jié)構(gòu)后,能自動生成相應(yīng)的Entity和相應(yīng)的基礎(chǔ)Mapper(單表簡單的DML語句)
  • Clean
    • 屏蔽各種數(shù)據(jù)傳遞對象的getter和setter方法暮芭,以及Buidler的各種方法
    • 緩存幾乎遍布所有項(xiàng)目鹿驼,最好能有配置即可用的緩存Template和注解緩存
    • 統(tǒng)一管理和簡化接口所有的邏輯分支
    • 能通過注解進(jìn)行業(yè)務(wù)接口的參數(shù)前置校驗(yàn)
  • Robust
    • 掌握代碼的每個流程分支(未掌控的分支邏輯,其實(shí)就是BUG)

現(xiàn)實(shí)卻是(Not-fast辕宏,But-dirty)

  • 舉個例子---擼段代碼
    @RequestMapping(value = "/app/userother/orderList")
    public Object orderList(@RequestParam("aopsID") String aopsID,
    @RequestParam(value = "orderType", required = false) String orderType,
    @RequestParam("orderStatus") String orderStatus,
    @RequestParam(value = "orderSource", required = false) String orderSource) {
    log.info("orderList============aopsID: " + aopsID);
    log.info("orderList============orderType: " + orderType);
    log.info("orderList============orderStatus: " + orderStatus);
    log.info("orderList============orderSource:" + orderSource);
    if (StringUtil.isEmpty(aopsID) || StringUtil.isEmpty(orderStatus)) {
    log.info("網(wǎng)絡(luò)請求參數(shù)錯誤畜晰,缺少參數(shù)");
    ErrorBean result = ResultCode.getErrorBean(ResultCode.ERROR_PARAMETERERROR);
    return result;
    }
    List<OrderDTO> list = null;
    HashMap<String, Object> resultStr = new HashMap<String, Object>();
    try {
    list = orderService.initOrder(aopsID, orderType, orderStatus, orderSource);
    /** json list 串null對象處理 **/
    List<Object> listObj = JsonNullToStringUtil.JsonToStringList(list);

          resultStr.put("resultStr", listObj);
       } catch (Exception e) {
          log.error("系統(tǒng)異常,方法orderList異常:", e);
          ErrorBean result = ResultCode.getErrorBean(ResultCode.ERROR_SYSTEM);
          return result;
       } catch (Throwable e) {
          log.error("業(yè)務(wù)異常瑞筐,方法orderList異常:", e);
          ErrorBean result = ResultCode.getErrorBean(ResultCode.ERROR_BISNUESSEXCEPTION);
          return result;
       }
    
       return resultStr;
    }
    
  • 華麗大變身
    @GetMapping(value = "/app/userother/orderList")
    public ResultVo orderList(@NotBlank String aopsID,
    @NotBlank String orderType,
    @NotBlank String orderStatus,
    String orderSource) throws Exception{

        List<OrderDTO> list = orderService.initOrder(aopsID, orderType, 
                                                     orderStatus,orderSource);
        return wrap(list);
    }
    

快上車凄鼻,讓micro-template帶你飛

  • 如何飛
    • 當(dāng)你需要新建項(xiàng)目,你只需要fork一下
    • 修改本來屬于你項(xiàng)目特有的東西即可
  • 背后的支撐
    • mybatis-spring-boot-starter

      1. application.yml配置即可用的mybatis插件聚假,讓Mybatis通過注解@MybatisMapper識別業(yè)務(wù)Mapper
        mybatis:
        datasource:
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://10.20.129.109:5056/aopsms?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&connectTimeout=200&autoReconnect=true&socketTimeout=8000
        username: deployop
        password: paic1234
        initialSize: 10
        minIdle: 6
        maxActive: 10
        maxWait: 500
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
    • automapper-spring-boot-starter

      1. 通過BaseMapper接口為業(yè)務(wù)Mapper進(jìn)行賦能(單表的CRUD)
        @MybatisMapper
        public interface AlertSendKpiMapper extends BaseMapper<AlertSendKpi> {

            void updateAlertSend(@Param("project") String project);
        }
        
      2. 設(shè)計(jì)數(shù)據(jù)庫表結(jié)構(gòu)后块蚌,能自動生成相應(yīng)的Entity和相應(yīng)的業(yè)務(wù)Mapper
        Entity:
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        @Table(name = "alert_send_kpi")
        public class AlertSendKpi {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;

            /**
             * 告警project名
             */
            private String project;
        
            /**
             * 告警源
             */
            @Column(name = "alert_source")
            private String alertSource;
        
            /**
             * 告警類型(耗時;業(yè)務(wù)成功率;QPS;錯誤率)
             */
            @Column(name = "alert_type")
            private String alertType;
        
            /**
             * 告警數(shù)值
             */
            @Column(name = "threshold_value")
            private Integer thresholdValue;
        }
        業(yè)務(wù)Mapper:
        

        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
        <mapper namespace="com.paic.insurance.root.micro.template.mapper.AlertSendKpiMapper" >
        <resultMap id="BaseResultMap" type="com.paic.insurance.root.micro.template.mapper.po.AlertSendKpi" >

        <id column="id" property="id" jdbcType="BIGINT" />
        <result column="project" property="project" jdbcType="VARCHAR" />
        <result column="alert_source" property="alertSource" jdbcType="VARCHAR" />
        <result column="alert_type" property="alertType" jdbcType="VARCHAR" />
        <result column="threshold_value" property="thresholdValue" jdbcType="INTEGER" />
        <result column="wave_value" property="waveValue" jdbcType="INTEGER" />
        <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
        <result column="start_period" property="startPeriod" jdbcType="TIMESTAMP" />
        <result column="end_period" property="endPeriod" jdbcType="TIMESTAMP" />
        <result column="ext_flag1" property="extFlag1" jdbcType="VARCHAR" />
        <result column="ext_flag2" property="extFlag2" jdbcType="VARCHAR" />
        <result column="value_standard" property="valueStandard" jdbcType="INTEGER" />
        <result column="wave_standard" property="waveStandard" jdbcType="INTEGER" />
        <result column="hit_alert_type" property="hitAlertType" jdbcType="INTEGER" />
        </resultMap>

        <update id="updateAlertSend">
        update alert_send_kpi set create_time=now() where project=#{project}
        </update>
        </mapper>

    • cache-spring-boot-starter

      1. 配置即可用的StringRedisTemplate
      2. 配置即可用的注解Redis緩存
    • log-spring-boot-starter

    • frontends-spring-boot-starter

      1. 前置參數(shù)校驗(yàn)(注解)
      2. 統(tǒng)一返回?cái)?shù)據(jù)結(jié)構(gòu)
      3. 通過自定義業(yè)務(wù)異常,統(tǒng)一異常處理膘格,收攏異常分支
      4. 配置即可啟用CORS

背后的干貨

  • 如何開發(fā)spring-boot-starter(配置即可用峭范,spring-boot開發(fā)哲學(xué))

  • 解析AOP

    • 編碼共識原則
      re-use 和 maintain 原則。解決問題是:雜亂代碼的維護(hù)性和擴(kuò)展性差瘪贱。
    • OOP(Object Oriented Programming)
      1. 封裝性:高內(nèi)聚體現(xiàn)者纱控,代碼模塊化,數(shù)據(jù)和行為綁定菜秦,遵循maintain原則甜害。
      2. 繼承性:代碼復(fù)用者,層層抽象代碼進(jìn)行復(fù)用球昨,遵循re-use原則尔店。
      3. 多態(tài)性:接口和實(shí)現(xiàn)進(jìn)行分離,用接口組織整個框架邏輯主慰,指定不同實(shí)現(xiàn)適應(yīng)不同情況嚣州,遵循re-use原則。面向接口編程共螺,特別是讀各種框架代碼運(yùn)用十分廣泛避诽。
    • AOP(Aspect Oriented Programming)
      各種行為之間的公用的一部分邏輯,能不能有個共同的術(shù)語璃谨,那他就是AOP。比如:事務(wù),監(jiān)控佳吞。
    • 什么組成了AOP
      • Aspect拱雏,模塊化組織者。
      • Join Point:程序的執(zhí)行過程的連接點(diǎn)底扳。例如:方法的執(zhí)行铸抑,異常的處理。
      • Pointcut:切入點(diǎn)表達(dá)式
      • Target object:被切入的對象
      • Weaving:將切片和業(yè)務(wù)對象連接起來衷模。從編譯時期到加載時期到運(yùn)行時期都可以進(jìn)行鹊汛。
        編譯時期:靜態(tài)代理模式,通過AspectJ編譯器阱冶。
        加載時期:load-time刁憋,當(dāng)class文件被ClassLoader加載到JVM后。
        運(yùn)行時期:字節(jié)碼運(yùn)行期間木蹬,通過JVM的Proxy模塊或者內(nèi)似于Cglib通過繼承的方式至耻。
    • 如寫一個AOP
      我們一般通過AOP的幾個注解來進(jìn)行相關(guān)切面的表述。
      我們將AOP切面進(jìn)行不同的Weaving的方式镊叁。

原來尘颓,我們追求的是

  • 模塊化
  • 重用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市晦譬,隨后出現(xiàn)的幾起案子疤苹,更是在濱河造成了極大的恐慌,老刑警劉巖敛腌,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卧土,死亡現(xiàn)場離奇詭異,居然都是意外死亡迎瞧,警方通過查閱死者的電腦和手機(jī)夸溶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凶硅,“玉大人缝裁,你說我怎么就攤上這事∽闵穑” “怎么了捷绑?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長氢妈。 經(jīng)常有香客問我粹污,道長,這世上最難降的妖魔是什么首量? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任壮吩,我火速辦了婚禮进苍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸭叙。我一直安慰自己觉啊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布沈贝。 她就那樣靜靜地躺著杠人,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宋下。 梳的紋絲不亂的頭發(fā)上嗡善,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機(jī)與錄音学歧,去河邊找鬼罩引。 笑死,一個胖子當(dāng)著我的面吹牛撩满,可吹牛的內(nèi)容都是我干的蜒程。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼伺帘,長吁一口氣:“原來是場噩夢啊……” “哼昭躺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伪嫁,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤领炫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后张咳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帝洪,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年脚猾,在試婚紗的時候發(fā)現(xiàn)自己被綠了葱峡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡龙助,死狀恐怖砰奕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情提鸟,我是刑警寧澤军援,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站称勋,受9級特大地震影響胸哥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赡鲜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一空厌、第九天 我趴在偏房一處隱蔽的房頂上張望庐船。 院中可真熱鬧,春花似錦嘲更、人聲如沸醉鳖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壮韭,卻和暖如春北发,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喷屋。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工琳拨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屯曹。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓狱庇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親恶耽。 傳聞我的和親對象是個殘疾皇子密任,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容