整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          IDEA 2021首個大版本發布,Java開發者感動哭了(附新亮點演示)

          欲善其事,必先利其器!

          就在不久之前,Java領域的開發神器IntelliJ IDEA終于迎來2021年的一個重要的大版本更新:IntelliJ IDEA 2021.1

          現如今大量的Java開發者深度依賴著這款開發軟件,正如網上的段子所言:“可以毫不夸張地說,多少Java程序員離開了IDEA就不會寫代碼了(狗頭)”,由此可見其使用的廣泛程度。

          新版本一出來,我也迫不及待地想嘗試一番。當然,主力開發機我是不敢亂升級的,所以這兩天,我在一臺平時用來做測試的老開發本子上更新了全新的IDEA。

          軟件啟動界面打開的那一瞬間,我就知道事情并不簡單。


          全新的啟動頁面

          更新后,全新的啟動頁面更加花里胡哨了。

          軟件啟動速度也是非常之快,就我這多年苦練的火箭般手速,都差點沒截來下面這張啟動頁面圖。


          Space集成

          JetBrains提供的Space這個功能不知道大家有沒有聽說過,講白了就是一套集成的團隊協作環境,可以提供包括構建交付、聊天協作、團隊管理以及項目管理等在內的一整套協作一體化解決方案。

          最新的IDEA 2021.1把Space環境給無縫地集成進來了,現在屬于開箱即用的狀態,軟件的右上角就有快捷入口:


          支持WSL 2

          這個功能相信對于很多依賴Windows系統以及WSL功能的用戶來說,簡直是喜大普奔!

          以前WSL就算再好用,但是你的IDE并沒有和它打通,多少總是一個遺憾。

          這下好了,二者直接打通了,IDEA支持WSL 2。你可以直接在新版IDEA 2021.1中運行并開發WSL 2中的Java項目,包括Gradle類型項目和Maven類型等項目均支持。


          Run Targets

          Run Targets這個功能的意思有點類似于上面剛聊過的WSL 2。它允許開發者直接在遠程主機甚至在Docker容器上運行和調試項目。

          所以到目前為止,新版IDEA 2021允許開發者可以在本地、WSL 2、SSH遠程主機、Docker等目標上運行項目,可以說賊香了!


          支持Java 16

          這也算是一個比較重磅的更新。

          近兩年來,Java版本的發布速度也是快如老狗,我還在用Java 8,它都淦到Java 16了。

          關于Java 16的新特性,我還準備寫篇文章來詳細聊一聊呢,包括比如:

          • Records特性轉正
          • instanceof模式匹配轉正
          • jpackage轉正
          • Unix域套接字通道
          • 彈性Metaspace
          • ZGC
          • 矢量API
          • 外部鏈接API
          • ...

          這次IDEA 2021版的一個很重要的更新就是加入了對Java 16的基本支持,注意是基本支持。

          除此之外IDEA還新增了幾項檢查機制,典型比如更加智能的數據流分析檢查。

          鏈式構造方式的優化格式設置等等。

          目的都是為了幫助提升可讀性,進一步提升用戶體驗。


          Code With Me

          Code With Me是一項用于協作開發與結對編程的服務,可以實Host-Guest模式的“手摸手”(滑稽)結對編程和群體編程。

          目前,新版IDEA開箱即用地支持了Code With Me功能,同時它還具有音頻通話和視頻通話功能,可以滿足隨時隨地的溝通需求,這操作簡直騷到爆。

          版本控制

          版本控制這一塊目前做了不少的更新,包括可以更快地完成PR的創建提交,支持PR模板。

          變更提交至代碼庫前的自定義代碼檢查配置。

          以及支持自定義Git提交模板等等。


          其他用戶體驗提升

          IDEA內置HTML網頁預覽

          以前在IDEA中預覽網頁得跳到外部瀏覽器,而現如今IDE的編輯器內部就支持Built-in級別的網頁預覽,只需要在右上角點那個IDEA小圖標即可激活,而且可以編輯網頁源碼時做到同步更新和預覽。

          Windows版本任務欄增強

          在Windows平臺的新版IDEA上,可直接在任務欄(或開始菜單)上右鍵快捷呼出最近使用的項目。

          搜索時自定義外部依賴項

          講白了,就是使搜索范圍更易于自定義,我們可以直接在設置中進行Scope定義,自行選擇External Dependencies的范圍是否包含。

          窗口拆分優化

          當你對編輯器里的多個文件進行垂直窗口拆分時,雙擊某個Tab就可以將當前文件窗口最大化,再次雙擊Tab則會還原。


          當然除了這些之外,新版IDEA還新增了很多更新和增強,比如:對Kotlin、Scala、JavaScript等語言的開發優化、對常見框架與技術的優化和支持、對Kubernetes和Docker的更新支持和改進、數據庫工具的更新支持等等,由于時間有限,在此就不一一贅述了,有需要的可以按需細究。

          最后,讓我們一起大喊一句:“IDEA,yyds!”

          Java代碼的時候,經常會涉及到重復性的操作,這個時候就會想要是有這樣一個插件就好了,如果是大家都會遇到的場景,IDE或許已經提供了,再不然也有可能有人編寫了相關的插件。

          要是這個操作是你們的編碼環境特有的,那就只能自己寫工具了。所以這里來學學如何編寫IDEA插件,讓自己的編程環境更加強大,更好的進行裝x。

          開發環境

          開發IDEA插件有以下這些依賴:

          • IntelliJ IDEA Community Edition
          • IntelliJ IDEA Community Edition 源碼
          • Plugin DevKit 插件
          • IntelliJ Platform SDK

          安裝IntelliJ IDEA Community Edition

          你可能已經安裝了Ultimate版本,但是你還是需要安裝[IDEA][]的社區版本。因為商業版是閉源的,所以在調試時無法調試核心代碼。

          下載IntelliJ IDEA Community Edition源碼

          社區版的安裝包里是不包含源碼的,所以我們需要手動從github上clone一份:

          git clone --depth 1 git://git.jetbrains.org/idea/community.git idea

          關于從源碼運行IDEA的方法參考 Check Out And Build Community Edition:

          http://www.jetbrains.org/intellij/sdk/docs/basics/checkout_and_build_community.html

          添加IDEA jdk

          雖然不知道原因,但是根據Check Out And Build Community Edition:

          http://www.jetbrains.org/intellij/sdk/docs/basics/checkout_and_build_community.html

          我們需要建立一個 IDEA jdk來運行插件:

          除非你在Mac上使用官方JDK,否則你需要手動添加 /lib/tools.jar到classpath中。關注微信公眾號:匠心零度,在后臺回復:idea,可以獲取我整最新 IDEA 教程,都是干貨。

          配置IntelliJ Platform SDK

          打開 File|ProjectStructure新建一個 IntelliJPlatformSDK:

          Java SDK選擇我們剛剛建立的 IDEA jdk:

          然后我們可以把下載的IDEA社區版源碼添加到源碼路徑中,這樣在調試時,就可以調試IDEA自身的代碼了:

          第一個插件

          我們來編寫一個最簡單的插件來學習編寫一個插件的完整步驟。

          新建工程

          選擇 IntellJPlatformPlugin,然后Project SDK指定剛剛新建的plugin sdk:

          新建的插件項目:

          插件根目錄下有兩個目錄 src和 resources。src是插件代碼目錄, resource是插件資源目錄,其中 META-INF/plugin.xml是插件的描述文件,就像Java web項目的 web.xml一樣。

          plugin.xml默認的內容如下:

          <idea-plugin>    <id>com.your.company.unique.plugin.id</id>    <name>Plugin display name here</name>    <version>1.0</version>    <vendor email="support@yourcompany.com" url="http://www.yourcompany.com">YourCompany</vendor>    <description><!\[CDATA\[      Enter short description for your plugin here.<br>        <em>most HTML tags may be used</em>      \]\]></description>    <change-notes><!\[CDATA\[      Add change notes here.<br>        <em>most HTML tags may be used</em>      \]\]>  </change-notes>    <!\-\- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting\_started/build\_number_ranges.html for description -->  <idea-version since-build="145.0"/>    <!\-\- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting\_started/plugin\_compatibility.html       on how to target different products -->  <!\-\- uncomment to enable plugin in all products  <depends>com.intellij.modules.lang</depends>    -->  <extensions defaultExtensionNs="com.intellij">      <!\-\- Add your extensions here -->  </extensions>    <actions>      <!\-\- Add your actions here -->  </actions>  </idea-plugin>  

          新建一個Action

          插件擴展IDEA最常見的方式就是在菜單欄或者工具欄中添加菜單項,用戶通過點擊菜單項來觸發插件功能。IDEA提供了 AnAction類,這個類有一個虛方法 actionPerformed,這個方法會在每次菜單被點擊時調用。

          新建一個自定義的Action有兩個步驟:

          1、 繼承 AnAction類,在 actionPerformed方法中實現插件邏輯 2、 注冊action,有兩種方式,通過代碼注冊和通過 plugin.xml注冊

          我們先寫一個簡單的Action類:

          publicclass TextBoxes extends AnAction {      // 如果通過Java代碼來注冊,這個構造函數會被調用,傳給父類的字符串會被作為菜單項的名稱    // 如果你通過plugin.xml來注冊,可以忽略這個構造函數    public TextBoxes() {          // 設置菜單項名稱        super("Text _Boxes");          // 還可以設置菜單項名稱,描述,圖標        // super("Text _Boxes","Item description",IconLoader.getIcon("/Mypackage/icon.png"));    }      public void actionPerformed(AnActionEvent event) {          Project project = event.getData(PlatformDataKeys.PROJECT);          String txt= Messages.showInputDialog(project, "What is your name?", "Input your name", Messages.getQuestionIcon());          Messages.showMessageDialog(project, "Hello, " \+ txt + "!\n I am glad to see you.", "Information", Messages.getInformationIcon());      }  }  

          然后我們在 plugin.xml中注冊這個Action:

          <actions>    <group id="MyPlugin.SampleMenu" text="_Sample Menu" description="Sample menu">      <add-to-group group-id="MainMenu" anchor="last"  />         <action id="Myplugin.Textboxes"class="Mypackage.TextBoxes" text="Text _Boxes" description="A test menu item" />    </group>  </actions>  

          這里我們新建了一個菜單組,其中text字符串的下劃線表示這個字母作為快捷鍵。這個菜單顯示的效果如下:

          除了手動新建Action,IDEA還提供了快速新建的方法,在代碼目錄上點擊新建,可以看到Action:

          可以在這個面板中填寫你要新建的Action信息,IDEA會幫你新建類,還有在plugin.xml中幫你注冊:

          運行插件

          運行插件特別簡單,和運行普通Java代碼一樣,點擊運行或者調試的按鈕,就會啟動一個新的IDEA實例,這個實例中插件是生效的。

          點擊Text Boxes就可以看到插件的效果了。

          asyCode

          EasyCode是一款專為IntelliJ IDEA設計的代碼生成工具插件,旨在通過自動化和模板化的方式,極大地提高Java開發者的編碼效率和代碼質量。這款插件深度融合于IDEA的開發環境中,為開發者帶來全新的開發體驗,讓編程變得更加輕松愉快。

          功能特點

          1. 智能代碼生成
          2. EasyCode基于模板引擎的原理,能夠快速生成標準化的代碼片段,包括類、方法、注釋、測試等。通過簡單的配置和選擇,開發者可以在幾秒鐘內完成繁瑣的代碼編寫工作,如實體類的屬性、Getter和Setter方法、數據庫操作代碼等。
          3. 它支持自定義代碼模板,開發者可以根據項目需求和團隊編碼規范,定制適合自己的代碼模板,以最佳實踐的方式生成代碼,減少因格式問題而浪費的時間。
          4. 智能代碼補全
          5. 在編程過程中,開發者只需輸入少量的關鍵字或方法名,EasyCode便能自動補全剩余部分,不僅減少了輸入的工作量,還降低了出現拼寫錯誤或語法錯誤的可能性,提高了代碼的可讀性和穩定性。
          6. 豐富的模板庫
          7. EasyCode提供了豐富的代碼模板庫,涵蓋了常見的代碼結構和設計模式。開發者可以根據項目需求,選擇合適的模板快速生成代碼,節省了大量的編碼時間。
          8. 高效便捷的操作
          9. 插件支持通過快捷鍵和上下文菜單快速生成代碼。開發者可以自定義快捷鍵組合,或在編輯器中選中代碼片段后,通過右鍵菜單選擇EasyCode的相關選項,快速生成對應的代碼。
          10. 其他實用功能
          11. EasyCode還提供了快速生成文檔注釋、自動導入所需的包和類、代碼格式化等實用功能,幫助開發者更加專注于解決問題和實現功能,而不必在瑣碎的代碼編寫上花費過多的時間和精力。

          優缺點

          優點

          • 簡單容易上手:EasyCode與IDEA完美結合,界面操作簡潔明了,操作起來簡單方便。
          • 配置少,修改少:幾乎不需要手寫配置,只需修改模板文件,即可輕松適應項目需求,生成所需代碼。
          • 提高開發效率:通過自動生成重復性的代碼,減少了手動編寫代碼的時間和精力,使開發者能夠更專注于業務邏輯的實現。
          • 保持代碼一致性:使用EasyCode生成的代碼遵循統一的標準和規范,提高了代碼的一致性和可讀性。

          缺點

          • 精細度不夠:EasyCode主要基于數據庫表的字段生成代碼,但在實際開發中,某些字段可能需要更精細的處理,如狀態字段的多種狀態表示、關聯字段的關聯關系等。
          • 團隊共享性差:在團隊中,如果某個成員修改了模板,需要手動導出并分享給其他成員導入,才能獲得最新的模板,這在一定程度上影響了模板的共享性和更新效率。

          綜上所述,EasyCode作為一款高效的IDEA插件,通過自動化和模板化的方式,為Java開發者帶來了極大的便利和效率提升。盡管存在一些缺點,但在大多數情況下,它仍然是提高開發效率、保持代碼一致性的有力工具。

          ?

          其實這么古老的插件大家應該都知道,我就簡單講述一下。并且逆向生成也有很多的方式,這篇文章主要是記錄下生成的模板配置信息,方便后續使用。

          image.png

          使用教程

          1.通過IDEA自帶的數據庫工具連接上數據庫

          image.png

          image.png

          2.配置EasyCode生成的模板

          *注:點擊上面的+是創建分組,輸入分組名創建后點擊里面的+是創建該分組的模板,后續生成的時候選擇其分組就行

          3.選擇數據表,鼠標右鍵選擇EasyCode來生成模板

          image.png

          image.png

          *注:Package和Path選到要生成的模塊級就行了(模塊包名會根據模板自動創建,不要自己去創),比如:xxx/src/main/java/com/xx/包名

          Mybatis-plus模板:

          • controller.java.vm
          ##定義初始變量
          #set($tableName = $tool.append($tableInfo.name, "Controller"))
          ##設置回調
          $!callback.setFileName($tool.append($tableName, ".java"))
          $!callback.setSavePath($tool.append($tableInfo.savePath, "/controller"))
          ##拿到主鍵
          #if(!$tableInfo.pkColumn.isEmpty())
              #set($pk = $tableInfo.pkColumn.get(0))
          #end
          
          #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller;
          
          import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
          import $!{tableInfo.savePackageName}.domain.$!{tableInfo.name};
          import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
          import $!{tableInfo.savePackageName}.common.R;
          import org.springframework.web.bind.annotation.*;
          
          import jakarta.annotation.Resource;
          import java.io.Serializable;
          import java.util.List;
          
          /**
           * $!{tableInfo.comment}($!{tableInfo.name})控制層
           *
           * @author ycc
           * @since $!time.currTime()
           */
          @RestController
          @RequestMapping("$!tool.firstLowerCase($tableInfo.name)")
          public class $!{tableName} {
          
              /**
               * 服務對象
               */
              @Resource
              private $!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service;
          
              /**
               * 分頁查詢所有數據
               */
              @GetMapping
              public R page(@RequestParam int current,@RequestParam int size){
                  Page<$!{tableInfo.name}> page=new Page<>(current,size);
                  return R.ok($!{tool.firstLowerCase($tableInfo.name)}Service.page(page));}
          
          
              /**
               * 通過主鍵查詢單條數據
               */
              @GetMapping("{id}")
              public R selectOne(@PathVariable Serializable id){
                  return R.ok($!{tool.firstLowerCase($tableInfo.name)}Service.getById(id));}
              
              /**
               * 新增數據
               */
              @PostMapping
              public R save(@RequestBody $!{tableInfo.name} $!tool.firstLowerCase($tableInfo.name)){
                  return R.ok($!{tool.firstLowerCase($tableInfo.name)}Service.save($!tool.firstLowerCase($tableInfo.name)));}
              
              /**
               * 修改數據
               */
              @PutMapping
              public R updateById(@RequestBody $!{tableInfo.name} $!tool.firstLowerCase($tableInfo.name)){
                  return R.ok($!{tool.firstLowerCase($tableInfo.name)}Service.updateById($!tool.firstLowerCase($tableInfo.name)));}
              
              /**
               * 單條/批量刪除數據
               */
              @DeleteMapping
              public R delete(@RequestParam List<Long> id){
                  return R.ok($!{tool.firstLowerCase($tableInfo.name)}Service.removeByIds(id));
              }
          }
          
          • service.java.vm
          ##定義初始變量
          #set($tableName = $tool.append($tableInfo.name, "Service"))
          ##設置回調
          $!callback.setFileName($tool.append($tableName, ".java"))
          $!callback.setSavePath($tool.append($tableInfo.savePath, "/service"))
          
          ##拿到主鍵
          #if(!$tableInfo.pkColumn.isEmpty())
              #set($pk = $tableInfo.pkColumn.get(0))
          #end
          
          #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service;
          
          import $!{tableInfo.savePackageName}.domain.$!{tableInfo.name};
          import com.baomidou.mybatisplus.extension.service.IService;
          
          /**
           * $!{tableInfo.comment}($!{tableInfo.name})服務接口
           *
           * @author ycc
           * @since $!time.currTime()
           */
          public interface $!{tableName} extends IService<$!tableInfo.name> {}
          
          • serviceImpl.java.vm
          ##定義初始變量
          #set($tableName = $tool.append($tableInfo.name, "ServiceImpl"))
          ##設置回調
          $!callback.setFileName($tool.append($tableName, ".java"))
          $!callback.setSavePath($tool.append($tableInfo.savePath, "/service/impl"))
          
          ##拿到主鍵
          #if(!$tableInfo.pkColumn.isEmpty())
              #set($pk = $tableInfo.pkColumn.get(0))
          #end
          
          #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service.impl;
          
          import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
          import $!{tableInfo.savePackageName}.domain.$!{tableInfo.name};
          import $!{tableInfo.savePackageName}.mapper.$!{tableInfo.name}Mapper;
          import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service;
          import org.springframework.stereotype.Service;
          
          /**
           * $!{tableInfo.comment}($!{tableInfo.name})服務實現類
           *
           * @author ycc
           * @since $!time.currTime()
           */
          @Service
          public class $!{tableName} extends ServiceImpl<$!{tableInfo.name}Mapper, $!{tableInfo.name}> implements $!{tableInfo.name}Service {}
          
          • mapper.java.vm
          ##定義初始變量
          #set($tableName = $tool.append($tableInfo.name, "Mapper"))
          ##設置回調
          $!callback.setFileName($tool.append($tableName, ".java"))
          $!callback.setSavePath($tool.append($tableInfo.savePath, "/mapper"))
          
          ##拿到主鍵
          #if(!$tableInfo.pkColumn.isEmpty())
              #set($pk = $tableInfo.pkColumn.get(0))
          #end
          
          #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}mapper;
          
          import com.baomidou.mybatisplus.core.mapper.BaseMapper;
          import $!{tableInfo.savePackageName}.domain.$!tableInfo.name;
          
          /**
           * $!{tableInfo.comment}($!{tableInfo.name})數據庫訪問層
           *
           * @author ycc
           * @since $!time.currTime()
           */
           @Mapper
          public interface $!{tableName} extends BaseMapper<$!tableInfo.name> {}
          
          • mapper.xml.vm
          ##引入mybatis支持
          $!{mybatisSupport.vm}
          
          ##設置保存名稱與保存位置
          $!callback.setFileName($tool.append($!{tableInfo.name}, "Mapper.xml"))
          $!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mapper"))
          
          ##拿到主鍵
          #if(!$tableInfo.pkColumn.isEmpty())
              #set($pk = $tableInfo.pkColumn.get(0))
          #end
          
          <?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="$!{tableInfo.savePackageName}.mapper.$!{tableInfo.name}Mapper">
          
              <resultMap type="$!{tableInfo.savePackageName}.domain.vo.$!{tableInfo.name}VO" id="$!{tableInfo.name}VOMap">
          #foreach($column in $tableInfo.fullColumn)
                  <result property="$!column.name" column="$!column.obj.name" jdbcType="$!column.ext.jdbcType"/>
          #end
              </resultMap>
              
          </mapper>
          
          • domain.java.vm
          ##引入宏定義
          $!{define.vm}
          
          ##使用宏定義設置回調(保存位置與文件后綴)
          #save("/domain", ".java")
          
          ##使用宏定義設置包后綴
          #setPackageSuffix("domain")
          
          ##使用全局變量實現默認包導入
          import com.baomidou.mybatisplus.annotation.*;
          import lombok.AllArgsConstructor;
          import lombok.Data;
          import lombok.NoArgsConstructor;
          
          
          /**
           * $!{tableInfo.comment}($!{tableInfo.comment})表
           *
           * @author ycc
           * @since $!time.currTime()
           */
          @Data
          @AllArgsConstructor
          @NoArgsConstructor
          public class $!{tableInfo.name}{
          private static final long serialVersionUID= 1L;
          #foreach($column in $tableInfo.pkColumn)
              #if(${column.comment})/**
               * ${column.comment}
               */#end
          
              @TableId(value = "$!{column.obj.name}" , type = IdType.NONE)
              private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
          #end
          #foreach($column in $tableInfo.otherColumn)
          
              #if(${column.comment})
          /**
               * ${column.comment}
               */
              #end
          @TableField(value = "$!{column.obj.name}")
              private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
          #end
          }
          
          • dto.java.vm
          ##引入宏定義
          $!{define.vm}
          
          ##使用宏定義設置回調(保存位置與文件后綴)
          #save("/domain/dto", "DTO.java")
          
          ##使用宏定義設置包后綴
          #setPackageSuffix("domain.dto")
          
          import $!{tableInfo.savePackageName}.domain.$!{tableInfo.name};
          
          ##使用全局變量實現默認包導入
          import lombok.AllArgsConstructor;
          import lombok.Data;
          import lombok.NoArgsConstructor;
          
          /**
           * $!{tableInfo.comment}($!{tableInfo.name})DTO
           *
           * @author ycc
           * @since $!time.currTime()
           */
          ##使用宏定義實現類注釋信息
          @Data
          @NoArgsConstructor
          public class $!{tableInfo.name}DTO extends $!{tableInfo.name}{
              
          }
          
          • vo.java.vm
          ##引入宏定義
          $!{define.vm}
          
          ##使用宏定義設置回調(保存位置與文件后綴)
          #save("/domain/vo", "VO.java")
          
          ##使用宏定義設置包后綴
          #setPackageSuffix("domain.vo")
          
          import $!{tableInfo.savePackageName}.domain.$!{tableInfo.name};
          
          ##使用全局變量實現默認包導入
          import lombok.AllArgsConstructor;
          import lombok.Data;
          import lombok.NoArgsConstructor;
          
          /**
           * $!{tableInfo.comment}($!{tableInfo.name})VO
           *
           * @author ycc
           * @since $!time.currTime()
           */
          ##使用宏定義實現類注釋信息
          @Data
          @NoArgsConstructor
          public class $!{tableInfo.name}VO extends $!{tableInfo.name}{
              
          }
          

          VO/DTO/DOMAIN區別

          VO(View Object)、DTO(Data Transfer Object)和DOMAIN(領域模型)是三種常見的用于數據傳遞和處理的類型,它們各自在不同的場景下發揮著重要作用。下面分別解釋它們的區別和使用場景。

          1. VO(View Object)

          定義:VO通常用于表示視圖層(如JSP、HTML頁面等)與控制器(Controller)之間的數據傳輸對象。它封裝了需要展示給用戶的數據,但不包含業務邏輯。

          使用場景

          • 當需要將數據庫中的某些數據展示到頁面上時,可以使用VO來封裝這些數據。
          • VO可以包含多個領域模型(Domain)的屬性,用于滿足特定視圖的展示需求。
          • 便于前端直接處理,減少數據轉換的復雜度。

          2. DTO(Data Transfer Object)

          定義:DTO是一種設計模式,用于在系統不同層(如表現層與業務層之間,或微服務之間的遠程調用)之間傳輸數據。DTO主要用于封裝跨層或跨系統邊界傳輸的數據。

          使用場景

          • 在微服務架構中,服務間的通信通常使用DTO來傳遞數據。
          • 當需要在網絡間傳輸數據時(如REST API的返回數據),DTO可以有效地封裝需要傳輸的數據。
          • DTO可以只包含需要的字段,減少數據傳輸的冗余,提高性能。
          • 在分層架構中,DTO可以隔離層與層之間的數據依賴,提高系統的可擴展性和可維護性。

          3. DOMAIN(領域模型)

          定義:DOMAIN是領域驅動設計(Domain-Driven Design, DDD)中的一個核心概念,表示業務領域內的一組具有業務含義和規則的類及它們之間的關系。Domain類通常包含業務邏輯和狀態信息。

          使用場景

          • Domain模型是業務邏輯的核心,它封裝了業務領域的知識和規則。
          • 在復雜的業務系統中,Domain模型幫助開發者理解和實現業務邏輯。
          • Domain模型可以直接與數據庫表映射(通過ORM工具),但更重要的是,它代表了業務邏輯和數據行為的抽象。
          • 相比DTO和VO,Domain模型更加側重于業務邏輯的實現和表達。

          總結

          • VO 專注于視圖展示,封裝展示層需要的數據。
          • DTO 專注于數據的跨層或跨系統傳輸,減少數據冗余,提高傳輸效率。
          • DOMAIN 專注于業務邏輯的實現,封裝業務領域的知識和規則。

          在實際項目中,應根據具體需求和場景來選擇合適的類型,以達到最佳的開發效率和系統性能。

          結語

          ?

          "非常感謝您一直觀看到現在,這些看似基礎的內容,實則構建了我們知識的基石。我驚喜地發現,將這些基礎知識系統地記錄下來,不僅是對自我學習的一種鞏固,也是一件非常有意義且值得分享的事情。您也完全可以這樣做,讓我們一起在基礎中深耕,發現更多可能。"


          原文:https://juejin.cn/post/7392513123860365339

          作者:世界哪有真情

          #記錄我的2024#


          主站蜘蛛池模板: 精品欧洲av无码一区二区| 美女福利视频一区| 国产一区二区三区夜色| 日本免费一区二区在线观看| 欲色aV无码一区二区人妻| 一区二区三区四区视频| 爱爱帝国亚洲一区二区三区| 中文字幕日韩一区二区不卡 | 国产精品特级毛片一区二区三区 | 亚洲日本一区二区三区| 国产在线无码视频一区二区三区| 高清在线一区二区| 国产精品久久久久一区二区| 无码一区二区三区在线观看| 久久婷婷色综合一区二区| 亚洲国产成人久久一区WWW| 久久精品国产一区二区| 八戒久久精品一区二区三区| 无码视频一区二区三区在线观看 | 丝袜美腿一区二区三区| 精品一区二区久久久久久久网精| 一区二区三区电影在线观看| 国产AV天堂无码一区二区三区| 亚洲欧美日韩国产精品一区| 久久久老熟女一区二区三区| 中文字幕精品无码一区二区| 国产一区二区三区久久| 亚洲一区二区三区在线网站| 亚洲中文字幕久久久一区| 国产aⅴ一区二区三区| 日韩有码一区二区| 无码精品一区二区三区在线| 国产乱码精品一区二区三区香蕉 | 波多野结衣在线观看一区二区三区| 国产激情一区二区三区四区| 国产av熟女一区二区三区| 国产精品亚洲一区二区麻豆| 精品乱子伦一区二区三区| 蜜桃视频一区二区三区在线观看| 中文字幕精品一区二区2021年| 成人在线视频一区|