女人荫蒂被添全过程13种图片,亚洲+欧美+在线,欧洲精品无码一区二区三区 ,在厨房拨开内裤进入毛片

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何在SpringBoot中應用DDD

科技綠洲 ? 來源:Java技術指北 ? 作者:Java技術指北 ? 2023-10-08 14:49 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在日常工作中,接手或維護的工程,大多數使用的是三層架構,即controller、service、dao三層,在使用的過程中,會遇到很多問題:

  • 面向數據建模,面向過程編程,沒有真正“面向對象”
  • 只注重結果,不注重過程,service層動輒數百上千行,充斥著過程代碼、膠水代碼,要么臃腫、要么流水賬、要不重復、要么邏輯分散,后期極難維護
  • 代碼耦合嚴重,層與層之間互相調用、逆向調用,牽一發而動全身
  • 代碼無法體現業務,在大家都不愛寫注釋的情況下,隨著時間的推移,代碼業務邏輯將無人理解,不敢改也改不動。

那么有沒有一個好的解決方案呢?今天要講的DDD就是一個不錯的選擇。

DDD

DDD,即 領域驅動設計 ,完美的解決了以上問題:

  • 面向領域建模,面向對象編程,代碼直接映射現實世界概念,貼近業務,離客戶更近
  • 領域邏輯高內聚,符合Java開發原則
  • 技術細節變更如數據庫、緩存、定時器等的變更對業務邏輯影響比較小,非常適合插件式架構
  • 代碼可讀性、可維護性更強,對后續擴展、移植等支持更好,分層更加科學

DDD的概念,在網上很容易找到,這里就不贅述了。

然而網上DDD的文章雖然很多,但大多數是理論知識,介紹的無非就是一些名詞:戰略設計、戰術設計、核心域、支撐域、值對象、實體、聚合... 對我們實際落地卻沒有太多的幫助,下面介紹下我在SpringBoot中應用DDD的落地方案。

落地方案

1、代碼分層

圖片

代碼分層

  • 用戶接口 :圖中的api包(即controller層,我嫌controller后綴太長...)
  • 應用層 :這里使用了命令模式,并且讀寫分離成了兩個包(command、query),如果不使用命令模式可以合并成一個service包
  • 領域層 :domain包,使用JPA(對DDD有良好的支持)
  • 基礎設施層 :infra包,其他所有的公用組件都放在這里,如果使用DIP依賴倒置,那么實現類也放在這里。
  • model模型 :model包,用于存放不同層間傳遞的對象,這些對象我試過放到好些地方,最后發現還是提出來統一放在一個包下比較好(便于服務間調用時共用對象)

2、層級關系及模型傳遞

圖片

分層及調用關系

3、分層詳細說明

  • api包(controller)
@Tag(name = "用戶", description = "用戶")
@RestController
@RequestMapping(value = "/api/sys-user")
public class SysUserApi extends BaseApi {


    @ApiResult
    @Operation(summary = "根據ID查詢用戶")
    @GetMapping("/{id}")
    public SysUserVo get(@PathVariable Long id) {
        return queryExecutor.execute(new SysUserByIdQry(id));
    }


    @Pagination(total = true)
    @ApiResult
    @Operation(summary = "分頁查詢用戶")
    @GetMapping
    public List< SysUserVo > getList(SysUserQo sysUserQo) {
        return queryExecutor.execute(new SysUserListQry(sysUserQo));
    }


    @ApiResult
    @Operation(summary = "新增用戶")
    @PostMapping
    public void save(@Valid @RequestBody SysUserDto sysUserDto) {
        commandExecutor.execute(new SysUserCommonCmd(sysUserDto));
    }
}
  1. 在BaseApi中封裝了兩個命令執行類queryExecutor和commandExecutor,調用應用層時執行不同的命令即可,無需@Autowired引入不同的服務
  2. @ApiResult加上這個自定義注解后,對返回結果統一封裝
  3. @Pagination加上這個自定義注解后,會自動將分頁參數存入線程變量,后面查詢時也會自動獲取分頁參數,返回結果統一封裝時也會加上分頁信息
  4. Qo是查詢參數對象,Dto是增刪改等命令參數對象,返回對象為Vo,這里要注意,Entity絕對不能暴露到這一層,需要轉換為Vo再返回
  5. 在這一層中,每個方法幾乎就是一行執行命令的語句,一般情況不進行業務邏輯(當然也有特殊情況咯)
  • command包
@AllArgsConstructor
public class SysDeptAddCmd implements Command Void > {


    private SysDeptDto sysDeptDto;


    @Override
    public Void execute(Executor executor) {
        // 獲取命令的接收者:領域服務
        SysDeptManager receiver = executor.getReceiver(SysDeptManager.class);
        // 對象模型轉換,由DTO轉為Entity,使用了MapStruct
        SysDept sysDept = SysDeptMapper.INSTANCE.toSysDept(sysDeptDto);
        // 使用JPA保存
        receiver.save(sysDept);
        return null;
    }
}
  1. 增刪改命令,很薄的一層,作為一項工作的組織者,幾乎沒有業務邏輯,調用領域服務和充血對象方法
  2. 命令模式,實現自定義Command接口,泛型為返回值
  3. 通過屬性和構造方法(使用lombok注解)接收參數
  4. 一個命令里只有一個execute方法,缺點是會產生大量的命令類,一個類相當于之前service類中的一個方法,但是這樣符合了單一職責原則
  5. 通過executor.getRecerver方法獲取到領域服務(manager)
  6. DTO絕對不下探到領域層中,需要先由DTO轉換為Entity(轉換方法這里使用的MapStruct,以后再單獨細講)
  • query包
@AllArgsConstructor
public class SysDeptByIdQry extends CommonQry< SysDeptVo > {


    private Long id;


    @Override
    public SysDeptVo execute(Executor executor) {
        if (id == null) {
            throw new BusinessException("部門ID不能為空");
        }
        QSysDept sysDept = QSysDept.sysDept;
        return queryFactory.select(this.fields())
                .from(sysDept)
                .where(sysDept.deleted.eq(false), sysDept.id.eq(id))
                .fetchOne();
    }


    /**
     * 部門VO映射
     *
     * @return QBean< SysDeptVo >
     */
    public static QBean< SysDeptVo > fields() {
        QSysDept sysDept = QSysDept.sysDept;
        return Projections.fields(
            SysDeptVo.class,
            sysDept.deptName,
            sysDept.orderNum,
            sysDept.id
        );
    }
}
  1. 命令模式,繼承自定義CommonQry基類(此類也實現了自定義的Command接口,其中引用了QueryDSL的queryFactory類,且封裝了分頁方法),泛型為返回值
  2. query包中的查詢命令與command包中的命令大體相同,唯一區別是query命令理論上直接查詢數據庫,不調用領域層
  3. 由于JPA對于復雜查詢不太好用,這里強烈推薦使用QueryDSL(以后再單獨細講),圖中是一個簡單的使用例子
  • domain包

類較多,代碼部分不一一羅列:

  1. 由Entity類自動生成數據庫表,僅維護Entity類(屏蔽數據庫)
  2. 設計Entity時根據實際業務靈活使用@OneToMany、@OneToOne等注解(聚合根的概念)
  3. 聚合根不要太大,80%的情況一個聚合根中只包含一個實體(不要過度設計成大聚合根)
  4. 不要使用貧血模型,而是要面向對象,屬于對象的方法要放到對象中,但是對象中不建議引入倉庫repository類,需要操作數據庫的方法寫在領域服務manager里
  5. 業務邏輯盡量寫在領域服務(manager)中,不斷提取、抽象不同的方法供應用層調用
  6. 適當的使用領域事件,JPA可以在Entity中使用@DomainEvents注解來發送領域事件

心得

  1. 通過DDD對業務理解更加透徹,寫的代碼可以更好的傳達客戶的業務訴求
  2. 能夠盡情的編寫低耦合的、符合單一職責、開閉等原則、封裝、繼承、多態的代碼,是很身心愉悅的
  3. 前期相比傳統架構代碼量更多,開發人員前期投入更多:
    • 領域的合理劃分、實體的合理設計
    • 大量的DTO、VO等數據對象
    • 大量的數據對象轉換方法
    • 大量的命令類
    • ...
  4. 但是,除非是特別簡單的功能,對于一個中等復雜的系統,這些前期的付出還是值得的,一張圖說明:
    圖片

小結

以上簡單介紹了下我對DDD的理解和實踐,并通過實際的代碼展現了如何在SpringBoot中應用DDD,希望能為大家提供一個思路。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編程
    +關注

    關注

    88

    文章

    3686

    瀏覽量

    95000
  • 代碼
    +關注

    關注

    30

    文章

    4892

    瀏覽量

    70407
  • ddd
    ddd
    +關注

    關注

    0

    文章

    23

    瀏覽量

    3025
  • SpringBoot
    +關注

    關注

    0

    文章

    175

    瀏覽量

    352
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    SpringBoot的Druid介紹

    SpringBootDruid數據源配置
    發表于 05-07 09:21

    SpringBoot知識總結

    SpringBoot干貨學習總結
    發表于 08-01 10:40

    怎么學習SpringBoot

    SpringBoot學習之路(X5)- 整合JPA
    發表于 06-10 14:52

    怎樣去使用springboot

    怎樣去使用springboot呢?學習springboot需要懂得哪些?
    發表于 10-25 07:13

    SpringBoot應用啟動運行run方法

    )、refreshContext(context);SpringBoot刷新IOC容器【創建IOC容器對象,并初始化容器,創建容器的每一個組件】;如果是web應用創建**AnnotationConfigEmbeddedWebApplicationContext**,否則
    發表于 12-20 06:16

    黑客攻防入門與進階ddd

    黑客攻防入門與進階ddd黑客攻防入門與進階ddd
    發表于 02-23 15:45 ?9次下載

    為什么建議你替換掉SpringBoot框架的Tomcat?

    SpringBoot框架,我們使用最多的是Tomcat,這是SpringBoot默認的容器技術,而且是內嵌式的Tomcat。
    的頭像 發表于 01-07 10:26 ?1344次閱讀

    SpringBoot實現多線程

    SpringBoot實現多線程
    的頭像 發表于 01-12 16:59 ?2148次閱讀
    <b class='flag-5'>SpringBoot</b>實現多線程

    用好DDD必須先過Spring Data這關

    DDD 是一種領域驅動的設計方法,旨在通過建立對領域模型的清晰理解來解決業務問題。和事務腳本不同,DDD 使用面向對象設計來應對復雜的業務場景。
    的頭像 發表于 03-07 09:38 ?2337次閱讀

    什么是 SpringBoot

    本文從為什么要有 `SpringBoot`,以及 `SpringBoot` 到底方便在哪里開始入手,逐步分析了 `SpringBoot` 自動裝配的原理,最后手寫了一個簡單的 `start` 組件,通過實戰來體會了 `
    的頭像 發表于 04-07 11:28 ?1698次閱讀
    什么是 <b class='flag-5'>SpringBoot</b>?

    SpringBoot的核心注解1

    今天跟大家來探討下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot為什么不需要XML,達到零配置
    的頭像 發表于 04-07 14:34 ?918次閱讀
    <b class='flag-5'>SpringBoot</b>的核心注解1

    SpringBoot的核心注解2

    今天跟大家來探討下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot為什么不需要XML,達到零配置
    的頭像 發表于 04-07 14:34 ?2181次閱讀
    <b class='flag-5'>SpringBoot</b>的核心注解2

    何在SpringBoot解決Redis的緩存穿透等問題

    今天給大家介紹一下如何在SpringBoot解決Redis的緩存穿透、緩存擊穿、緩存雪崩的問題。
    的頭像 發表于 04-28 11:35 ?912次閱讀

    DDD是什么?DDD核心概念梳理

    DDD 是什么,DDD 的英文全稱是 Domain-Driven Design,翻譯過來就是領域驅動設計。
    的頭像 發表于 09-07 11:12 ?1w次閱讀
    <b class='flag-5'>DDD</b>是什么?<b class='flag-5'>DDD</b>核心概念梳理

    DDD學習與感悟——向屎山沖鋒

    軟件系統是通過軟件開發來解決某一個業務領域或問題單元而產生的一個交付物。而通過軟件設計可以幫助我們開發出更加健壯的軟件系統。因此,軟件設計是從業務領域到軟件開發之間的橋梁。而DDD是軟件設計的其中
    的頭像 發表于 09-24 13:31 ?485次閱讀
    <b class='flag-5'>DDD</b>學習與感悟——向屎山沖鋒
    主站蜘蛛池模板: 刚察县| 庄河市| 镇雄县| 巫山县| 永仁县| 呼伦贝尔市| 江孜县| 绵竹市| 高邑县| 弥勒县| 九江市| 曲靖市| 平乡县| 永兴县| 丹东市| 塔河县| 沙坪坝区| 巴林左旗| 高要市| 九龙城区| 宝鸡市| 阳原县| 新干县| 上林县| 碌曲县| 清原| 墨玉县| 本溪市| 隆尧县| 滦平县| 高陵县| 双桥区| 铜山县| 铁岭市| 阳城县| 那曲县| 神木县| 旌德县| 德州市| 海盐县| 河西区|