欲善其事,必先利其器!
就在不久之前,Java領域的開發神器IntelliJ IDEA終于迎來2021年的一個重要的大版本更新:IntelliJ IDEA 2021.1。
現如今大量的Java開發者深度依賴著這款開發軟件,正如網上的段子所言:“可以毫不夸張地說,多少Java程序員離開了IDEA就不會寫代碼了(狗頭)”,由此可見其使用的廣泛程度。
新版本一出來,我也迫不及待地想嘗試一番。當然,主力開發機我是不敢亂升級的,所以這兩天,我在一臺平時用來做測試的老開發本子上更新了全新的IDEA。
軟件啟動界面打開的那一瞬間,我就知道事情并不簡單。
更新后,全新的啟動頁面更加花里胡哨了。
軟件啟動速度也是非常之快,就我這多年苦練的火箭般手速,都差點沒截來下面這張啟動頁面圖。
JetBrains提供的Space這個功能不知道大家有沒有聽說過,講白了就是一套集成的團隊協作環境,可以提供包括構建交付、聊天協作、團隊管理以及項目管理等在內的一整套協作一體化解決方案。
最新的IDEA 2021.1把Space環境給無縫地集成進來了,現在屬于開箱即用的狀態,軟件的右上角就有快捷入口:
這個功能相信對于很多依賴Windows系統以及WSL功能的用戶來說,簡直是喜大普奔!
以前WSL就算再好用,但是你的IDE并沒有和它打通,多少總是一個遺憾。
這下好了,二者直接打通了,IDEA支持WSL 2。你可以直接在新版IDEA 2021.1中運行并開發WSL 2中的Java項目,包括Gradle類型項目和Maven類型等項目均支持。
Run Targets這個功能的意思有點類似于上面剛聊過的WSL 2。它允許開發者直接在遠程主機甚至在Docker容器上運行和調試項目。
所以到目前為止,新版IDEA 2021允許開發者可以在本地、WSL 2、SSH遠程主機、Docker等目標上運行項目,可以說賊香了!
這也算是一個比較重磅的更新。
近兩年來,Java版本的發布速度也是快如老狗,我還在用Java 8,它都淦到Java 16了。
關于Java 16的新特性,我還準備寫篇文章來詳細聊一聊呢,包括比如:
這次IDEA 2021版的一個很重要的更新就是加入了對Java 16的基本支持,注意是基本支持。
除此之外IDEA還新增了幾項檢查機制,典型比如更加智能的數據流分析檢查。
鏈式構造方式的優化格式設置等等。
目的都是為了幫助提升可讀性,進一步提升用戶體驗。
Code With Me是一項用于協作開發與結對編程的服務,可以實Host-Guest模式的“手摸手”(滑稽)結對編程和群體編程。
目前,新版IDEA開箱即用地支持了Code With Me功能,同時它還具有音頻通話和視頻通話功能,可以滿足隨時隨地的溝通需求,這操作簡直騷到爆。
版本控制
版本控制這一塊目前做了不少的更新,包括可以更快地完成PR的創建提交,支持PR模板。
變更提交至代碼庫前的自定義代碼檢查配置。
以及支持自定義Git提交模板等等。
以前在IDEA中預覽網頁得跳到外部瀏覽器,而現如今IDE的編輯器內部就支持Built-in級別的網頁預覽,只需要在右上角點那個IDEA小圖標即可激活,而且可以編輯網頁源碼時做到同步更新和預覽。
在Windows平臺的新版IDEA上,可直接在任務欄(或開始菜單)上右鍵快捷呼出最近使用的項目。
講白了,就是使搜索范圍更易于自定義,我們可以直接在設置中進行Scope定義,自行選擇External Dependencies的范圍是否包含。
當你對編輯器里的多個文件進行垂直窗口拆分時,雙擊某個Tab就可以將當前文件窗口最大化,再次雙擊Tab則會還原。
當然除了這些之外,新版IDEA還新增了很多更新和增強,比如:對Kotlin、Scala、JavaScript等語言的開發優化、對常見框架與技術的優化和支持、對Kubernetes和Docker的更新支持和改進、數據庫工具的更新支持等等,由于時間有限,在此就不一一贅述了,有需要的可以按需細究。
最后,讓我們一起大喊一句:“IDEA,yyds!”
Java代碼的時候,經常會涉及到重復性的操作,這個時候就會想要是有這樣一個插件就好了,如果是大家都會遇到的場景,IDE或許已經提供了,再不然也有可能有人編寫了相關的插件。
要是這個操作是你們的編碼環境特有的,那就只能自己寫工具了。所以這里來學學如何編寫IDEA插件,讓自己的編程環境更加強大,更好的進行裝x。
開發IDEA插件有以下這些依賴:
你可能已經安裝了Ultimate版本,但是你還是需要安裝[IDEA][]的社區版本。因為商業版是閉源的,所以在調試時無法調試核心代碼。
社區版的安裝包里是不包含源碼的,所以我們需要手動從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
雖然不知道原因,但是根據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 教程,都是干貨。
打開 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>
插件擴展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就可以看到插件的效果了。
EasyCode是一款專為IntelliJ IDEA設計的代碼生成工具插件,旨在通過自動化和模板化的方式,極大地提高Java開發者的編碼效率和代碼質量。這款插件深度融合于IDEA的開發環境中,為開發者帶來全新的開發體驗,讓編程變得更加輕松愉快。
優點:
缺點:
綜上所述,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/包名
##定義初始變量
#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));
}
}
##定義初始變量
#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> {}
##定義初始變量
#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 {}
##定義初始變量
#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> {}
##引入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>
##引入宏定義
$!{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
}
##引入宏定義
$!{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}{
}
##引入宏定義
$!{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(View Object)、DTO(Data Transfer Object)和DOMAIN(領域模型)是三種常見的用于數據傳遞和處理的類型,它們各自在不同的場景下發揮著重要作用。下面分別解釋它們的區別和使用場景。
定義:VO通常用于表示視圖層(如JSP、HTML頁面等)與控制器(Controller)之間的數據傳輸對象。它封裝了需要展示給用戶的數據,但不包含業務邏輯。
使用場景:
定義:DTO是一種設計模式,用于在系統不同層(如表現層與業務層之間,或微服務之間的遠程調用)之間傳輸數據。DTO主要用于封裝跨層或跨系統邊界傳輸的數據。
使用場景:
定義:DOMAIN是領域驅動設計(Domain-Driven Design, DDD)中的一個核心概念,表示業務領域內的一組具有業務含義和規則的類及它們之間的關系。Domain類通常包含業務邏輯和狀態信息。
使用場景:
在實際項目中,應根據具體需求和場景來選擇合適的類型,以達到最佳的開發效率和系統性能。
?
"非常感謝您一直觀看到現在,這些看似基礎的內容,實則構建了我們知識的基石。我驚喜地發現,將這些基礎知識系統地記錄下來,不僅是對自我學習的一種鞏固,也是一件非常有意義且值得分享的事情。您也完全可以這樣做,讓我們一起在基礎中深耕,發現更多可能。"
原文:https://juejin.cn/post/7392513123860365339
作者:世界哪有真情
#記錄我的2024#
*請認真填寫需求信息,我們會在24小時內與您取得聯系。