簡介
本框架結(jié)合公司日常業(yè)務場景真朗,對[Mybatis-Plus] 做了進一步的拓展封裝介却,即保留MP原功能臼闻,又添加更多有用便捷的功能有巧。具體拓展體現(xiàn)在
數(shù)據(jù)自動填充(類似JPA中的審計)
鹉胖、關聯(lián)查詢(類似sql中的join)
、自動建表(僅支持mysql)
审编、冗余數(shù)據(jù)自動更新
撼班、動態(tài)條件
等功能做了補充完善歧匈。其中自動建表
垒酬,是在[A.CTable]框架上的基礎上改進適配本框架的,只保留了其表創(chuàng)建功能件炉,因此改動較大不與原框架兼容勘究。
詳細設計及源碼請移步碼云搜索mybatis-plus-ext
原理介紹
基于注解的形式,將日常工作中重復的模板式代碼進行了封裝斟冕,底層實現(xiàn)完全調(diào)用的Mybatis-Plus的框架口糕,全都是走的單表查詢的方式,所以不用擔心數(shù)據(jù)庫兼容問題(自動建表功能除外磕蛇,只支持mysql)景描,同樣也不需要擔心性能問題(前提是正確使用[捂臉])十办,因為框架內(nèi)部會自動做查詢整合。
快速開始
引入jar包
starter內(nèi)自帶了MybatisPlus及spring-boot的依賴管理超棺,如果要更改springboot的版本向族,可以排除掉,但是如果要變更MybatisPlus的版本棠绘,請注意了件相,框架中重寫了MP中的TableInfoHelper類,不同版本的MP該類有所變動氧苍,同時框架內(nèi)也采用了MP的部分工具類夜矗,例如LambdaUtils、ReflectionKit等在不同的版本也有所變動让虐,需要小心紊撕,哈哈哈哈,可以聯(lián)系我?guī)湍愀膥~
框架在設計上赡突,盡量以拓展的功能為單位做了模塊拆分逛揩,所有功能均能獨立引入也可以合并引入,大家視情況選用吧麸俘。
<!-- 1缁!从媚!重點說明逞泄,框架內(nèi)部已經(jīng)引入了MybatisPlus的包,自己項目中的需要去掉0菪АE缰凇! -->
<!-- 全功能整體引入 -->
<dependency>
<groupId>com.tangzc</groupId>
<artifactId>mybatis-plus-ext-boot-starter</artifactId>
<version>{maven倉庫搜索最新版}</version>
</dependency>
<!-- 如果想只引入自動建表 -->
<dependency>
<groupId>com.tangzc</groupId>
<artifactId>mybatis-plus-ext-actable-core</artifactId>
<version>{maven倉庫搜索最新版}</version>
</dependency>
<!-- 如果想只引入關聯(lián)查詢 -->
<dependency>
<groupId>com.tangzc</groupId>
<artifactId>mybatis-plus-ext-bind</artifactId>
<version>{maven倉庫搜索最新版}</version>
</dependency>
<!-- 如果想只引入數(shù)據(jù)冗余(關聯(lián)更新) -->
<dependency>
<groupId>com.tangzc</groupId>
<artifactId>mybatis-plus-ext-datasource</artifactId>
<version>{maven倉庫搜索最新版}</version>
</dependency>
<!-- 如果想只引入動態(tài)條件 -->
<dependency>
<groupId>com.tangzc</groupId>
<artifactId>mybatis-plus-ext-condition</artifactId>
<version>{maven倉庫搜索最新版}</version>
</dependency>
自動建表
根據(jù)實體上的注解及字段注解自動創(chuàng)建紧憾、更新數(shù)據(jù)庫表到千。
本模塊核心代碼采用了A.CTable框架,因該框架與本框架的需求不太符合赴穗,因此就對其進行了一版魔改憔四,具體改動如下:
- 官方的設計思路是默認Bean下的所有字段均不是表字段,需要手動通過@Column聲明般眉,我在引用過來之后了赵,改為了默認所有字段均為表字段,只有被MP的@TableField(exist=false)修飾的才會被排除甸赃,具備@TableField(exist=false)功能的注解有:@Exclude柿汛、@Bind**系列,他們集成了@TableField埠对,且內(nèi)置exist屬性為false了络断。
- A.CTable框架內(nèi)部集成了類似MP的功能裁替,不如MP完善,所以我也剔除掉了貌笨,順帶解決了不兼容和bug胯究。
- 像DefaultValue注解與本框架內(nèi)部注解重名了,因此改名為ColumnDefault躁绸。
- 整理了一遍內(nèi)部的注解裕循,利用spring的AliasFor做了關聯(lián),更方便管理净刮。
- @Table里面加了一個primary屬性(對應@TablePrimary)剥哑,表示是否為主表,為了支持多個Entity對應一個數(shù)據(jù)庫表(正常用不到請忽略_)淹父。
- @Table里面加了一個dsName屬性(對應@DsName)株婴,可以配合MP的多數(shù)據(jù)框架實現(xiàn)不同的表在不同數(shù)據(jù)源下創(chuàng)建。
- 數(shù)據(jù)庫類型映射改動增加對MySQL8的支持暑认,Double數(shù)據(jù)類型困介,自動保留2位小數(shù),BigDecimal類型保留4位小數(shù)蘸际。
- 數(shù)據(jù)庫表名和字段名的生成會參照mybatis-plus的配置:
mybatis-plus.global-config.db-config.table-underline
和mybatis-plus.configuration.map-underscore-to-camel-case
決定是否自動駝峰轉(zhuǎn)下劃線座哩,完成了跟mybatis-plus的一致性。
@Data
// @Table標記的可被識別為需要自動創(chuàng)建表的Entity
@Table(comment = "用戶")
public class User {
// 自動識別id屬性名為主鍵
// @IsAutoIncrement聲明為自增主鍵粮彤,什么都不聲明的話根穷,默認為雪花算法的唯一主鍵(MP的自帶功能),推薦默認便于后期的數(shù)據(jù)分布式存儲等處理导坟。
@IsAutoIncrement
// 字段注釋屿良、類型、長度惫周。@Column的所有屬性均有獨立的注解對應尘惧,具體請參照后面的注解介紹
@Column(comment = "主鍵", type = MySqlTypeConstant.BIGINT, length = 32)
private String id;
// 索引
@Index
// 非空
@IsNotNull
@ColumnComment("名字")
private String name;
// 唯一索引
@Unique
// 非空
@IsNotNull
@ColumnComment("手機號")
private String phone;
// 省略其他屬性
......
}
// 啟用自動生成數(shù)據(jù)庫表功能,此處簡化了A.CTable的復雜配置递递,均采用默認配置
@EnableAutoTable
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
# actable的配置信息保留了如下幾項喷橙,均做了默認配置,正常無需配置
actable.table.auto=update
actable.model.pack=[Spring啟動類所在包]
actable.database.type=mysql
actable.index.prefix=自己定義的索引前綴#該配置項不設置默認使用actable_idx_
actable.unique.prefix=自己定義的唯一約束前綴#該配置項不設置默認使用actable_uni_
數(shù)據(jù)填充
可以在數(shù)據(jù)插入或更新的時候漾狼,自動賦值數(shù)據(jù)操作人重慢、操作時間、默認值等屬性逊躁。
以文章發(fā)布為例,講解一下數(shù)據(jù)填充的基本用法隅熙。通過如下例子可發(fā)現(xiàn)稽煤,在創(chuàng)建Artice的時候核芽,我們無需再去關心過多的與業(yè)務無關的字段值,只需要關心
title
酵熙、content
兩個核心數(shù)據(jù)即可轧简,其他的數(shù)據(jù)均會被框架處理。
@Data
@Table(comment = "文章")
public class Article {
// 字符串類型的ID匾二,默認也是雪花算法的一串數(shù)字(MP的默認功能)
@ColumnComment("主鍵")
private String id;
@ColumnComment("標題")
private String title;
@ColumnComment("內(nèi)容")
private String content;
// 文章默認激活狀態(tài)
@DefaultValue("ACTIVE")
@ColumnComment("內(nèi)容")
// ActicleStatusEnum(ACTIVE, INACTIVE)
private ActicleStatusEnum status;
@ColumnComment("發(fā)布時間")
// 插入數(shù)據(jù)時候會自動獲取系統(tǒng)當前時間賦值哮独,支持多種數(shù)據(jù)類型,具體可參考@OptionDate注解詳細介紹
@InsertOptionDate
private Date publishedTime;
@ColumnComment("發(fā)布人")
// 插入的時候察藐,根據(jù)UserIdAutoFillHandler自動填充用戶id
@InsertOptionUser(UserIdAutoFillHandler.class)
private String publishedUserId;
@ColumnComment("發(fā)布人名字")
// 插入的時候皮璧,根據(jù)UserIdAutoFillHandler自動填充用戶名字
@InsertOptionUser(UsernameAutoFillHandler.class)
private String publishedUsername;
@ColumnComment("最后更新時間")
// 插入和更新數(shù)據(jù)時候會自動獲取系統(tǒng)當前時間賦值,支持多種數(shù)據(jù)類型分飞,具體可參考@OptionDate注解詳細介紹
@InsertUpdateOptionDate
private Date publishedTime;
@ColumnComment("最后更新人")
// 插入和更新的時候悴务,根據(jù)UserIdAutoFillHandler自動填充用戶id
@InsertUpdateOptionUser(UserIdAutoFillHandler.class)
private String publishedUserId;
@ColumnComment("最后更新人名字")
// 插入和更新的時候,根據(jù)UserIdAutoFillHandler自動填充用戶名字
@InsertUpdateOptionUser(UsernameAutoFillHandler.class)
private String publishedUsername;
}
/**
* 全局獲取用戶ID
* 此處實現(xiàn)IOptionByAutoFillHandler接口和AutoFillHandler接口均可譬猫,建議實現(xiàn)IOptionByAutoFillHandler接口讯檐,
* 因為框架內(nèi)的BaseEntity默認需要IOptionByAutoFillHandler的實現(xiàn)。后面會講到BaseEntity的使用染服。
*/
@Component
public class UserIdAutoFillHandler implements IOptionByAutoFillHandler<String> {
/**
* @param object 當前操作的數(shù)據(jù)對象
* @param clazz 當前操作的數(shù)據(jù)對象的class
* @param field 當前操作的數(shù)據(jù)對象上的字段
* @return 當前登錄用戶id
*/
@Override
public String getVal(Object object, Class<?> clazz, Field field) {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
// 配合網(wǎng)關或者過濾器别洪,token校驗成功后就把用戶信息塞到header中
return request.getHeader("user-id");
}
}
/**
* 全局獲取用戶名
*/
@Component
public class UsernameAutoFillHandler implements AutoFillHandler<String> {
/**
* @param object 當前操作的數(shù)據(jù)對象
* @param clazz 當前操作的數(shù)據(jù)對象的class
* @param field 當前操作的數(shù)據(jù)對象上的字段
* @return 當前登錄用戶id
*/
@Override
public String getVal(Object object, Class<?> clazz, Field field) {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
// 配合網(wǎng)關或者過濾器,token校驗成功后就把用戶信息塞到header中
return request.getHeader("user-name");
}
}
關聯(lián)查詢
數(shù)據(jù)關聯(lián)查詢的解決方案柳刮,替代sql中的join方式蕉拢,通過注解關聯(lián)多表之間的關系,查詢某實體的時候诚亚,自動帶出其關聯(lián)性的數(shù)據(jù)實體晕换。
本示例以比較復雜的通過中間表關聯(lián)數(shù)據(jù)的案例來講解下,用戶和角色之間多對多站宗,通過中間表進行數(shù)據(jù)級聯(lián)闸准,@BindEntity*系列是關聯(lián)Entity的數(shù)據(jù),@BindField*系列是關聯(lián)Entity下的某個字段梢灭。當@Bind*系列注解用在對象上即表達一對一夷家,當注解在List上時便表達一對多的意思,當外部對象本身就是查詢集合的情況下便是多對多的場景了敏释。
@Data
@Table(comment = "角色信息")
public class Role {
@ColumnComment("主鍵")
private String id;
@ColumnComment("角色名")
private String name;
}
@Data
@Table(comment = "用戶信息")
public class User {
@ColumnComment("主鍵")
private String id;
@ColumnComment("用戶名")
private String username;
@ColumnComment("密碼")
private String password;
// 關鍵配置库快,聲明了User想關聯(lián)對應的Rule集合,中間表是UserRule
@BindEntityByMid(conditions = @MidCondition(
midEntity = UserRole.class, selfMidField = "userId", joinMidField = "roleId"
))
private List<Role> roles;
}
@Data
@Table(comment = "用戶-角色關聯(lián)關系")
public class UserRole {
@ColumnComment("主鍵")
private String id;
@ColumnComment("用戶id")
private String userId;
@ColumnComment("角色id")
private String roleId;
}
/**
* 用戶服務
*/
@Slf4j
@Service
public class UserService {
// UserRepository繼承了BaseRepository<UserMapper, User>钥顽,后面會講BaseRepository
@Resource
private UserRepository userRepository;
/**
* 根據(jù)用戶的名字模糊查詢所有用戶的詳細信息
*/
@Transactional(readOnly = true)
public List<UserDetailWithRoleDto> searchUserWithRuleByName(String name) {
// MP的lambda查詢方式
List<User> userList = userRepository.lambdaQuery()
.eq(name != null, User::getUsername, name)
.list();
// 關鍵步驟义屏,指定關聯(lián)角色數(shù)據(jù)。如果你打開sql打印,會看到3條sql語句闽铐,第一條根據(jù)id去User表查詢user信息蝶怔,第二條根據(jù)userId去UserRule中間表查詢所有的ruleId,第三條sql根據(jù)ruleId集合去Rule表查詢?nèi)康臋?quán)限
// 用法一兄墅、指定屬性關聯(lián)踢星。
Binder.bindOn(userList, User::getRoles);
// 用法二、全關聯(lián)隙咸。此種用法默認關聯(lián)user下所有聲明需要綁定的屬性
// Binder.bind(userList);
return UserMapping.MAPPER.toDto5(userList);
}
/**
* 根據(jù)用戶的名字模糊查詢所有用戶的詳細信息沐悦,等價于上一個查詢方式
*/
@Transactional(readOnly = true)
public List<UserDetailWithRoleDto> searchUserWithRuleByName2(String name) {
// 本框架拓展的lambda查詢器lambdaQueryPlus,增加了bindOne五督、bindList藏否、bindPage
// 顯然這是一種更加簡便的查詢方式,但是如果存在多級深度的關聯(lián)關系概荷,此種方法就不適用了秕岛,還需要借助Binder
List<User> userList = userRepository.lambdaQueryPlus()
.eq(name != null, User::getUsername, name)
// 用法一、指定屬性關聯(lián)误证。
.bindList(User::getRoles);
// 用法二继薛、全關聯(lián)。
// .bindList();
return UserMapping.MAPPER.toDto5(userList);
}
}
==提示==: 假如存在此種場景:User
愈捅、Role
遏考、Menu
三個實體,他們之間的關系是:User
多對多 Role
蓝谨、Role
多對多Menu
灌具,當我查詢出User的集合后,如何獲取Role和Menu的數(shù)據(jù)呢譬巫?
// 數(shù)據(jù)庫查詢出了用戶列表 【1】
List<User> userList = userRepository.list();
// 為所有用戶關聯(lián)角色信息 【2】
Binder.bindOn(userList, User::getRoles);
// 為所有角色信息關聯(lián)菜單信息 【3】
// Deeper為一個深度遍歷工具咖楣,可以深入到對象的多層屬性內(nèi)部,從而獲取全局上該層級的所有對象同一屬性
Binder.bindOn(Deeper.with(userList).inList(User::getRoles), Role::getMenus);
注意??:【2】和【3】存在順序依賴芦昔,必須先執(zhí)行【2】才能執(zhí)行【3】
數(shù)據(jù)冗余
當其他表的數(shù)據(jù)需要作為當前表的查詢條件的時候诱贿,多數(shù)情況下會使用sql的join語法,另一種方案是做數(shù)據(jù)冗余咕缎,將其他表的字段冗余到當前表珠十,但是牽扯一個數(shù)據(jù)修改后同步的問題,本框架可以解決凭豪。
假設用戶評論的場景焙蹭,評論上需要冗余用戶名和頭像,如果用戶的名字和頭像有改動嫂伞,則需要同步新的改動孔厉,代碼如下:
@Data
@Table(comment = "用戶信息")
public class User {
@ColumnComment("主鍵")
private String id;
@ColumnComment("用戶名")
private String username;
@ColumnComment("頭像")
private String icon;
// 省略其他屬性
......
}
@Data
@Table(comment = "評論")
public class Comment {
@ColumnComment("主鍵")
private String id;
@ColumnComment("評論內(nèi)容")
private String content;
@ColumnComment("評論人id")
private String userId;
/* 基于該注解拯钻,框架會自動注冊監(jiān)聽EntityUpdateEvent事件,User的updateById和updateBatchById兩個方法會自動發(fā)布EntityUpdateEvent事件烟馅。
* 因此说庭,除了mybatis-plus的updateById和updateBatchById兩個更新方法外然磷,其他數(shù)據(jù)更新方式(比如手動寫sql的形式)不會觸發(fā)數(shù)據(jù)自動更新郑趁,需要用戶自己拋出EntityUpdateEvent事件,完成數(shù)據(jù)自動更新
*/
@DataSource(source = User.class, field = "username", conditions = @Condition(selfField = "userId"))
@ColumnComment("評論人名稱")
private String userName;
@DataSource(source = User.class, field = "icon", condition = @Condition(selfField = "userId"))
@ColumnComment("評論人頭像")
private String userIcon;
}
動態(tài)條件
適用場景:數(shù)據(jù)篩選姿搜,比如根據(jù)不同權(quán)限獲取不同數(shù)據(jù)寡润,用戶只能看到自己的數(shù)據(jù),管理員能看到所有人的數(shù)據(jù)舅柜。
此種場景梭纹,我們通常需要在每一個查詢、更新致份、刪除的sql操作上都追加上某個條件变抽,很容易忘記,但是可以抽象成注解直接配置到Entity上氮块,就省去了每個數(shù)據(jù)操作關心這個特殊條件了绍载。
/**
* congfig中注冊動態(tài)條件攔截器【1.3.0之前的版本(不包括1.3.0)可以忽略,不注冊該Bean】
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加動態(tài)條件滔蝉,若同時添加了其他的攔截器击儡,繼續(xù)添加即可
interceptor.addInnerInterceptor(new DynamicConditionInterceptor());
return interceptor;
}
@Data
@Table(comment = "文章")
public class Article {
@ColumnComment("主鍵")
private String id;
@ColumnComment("標題")
private String title;
@ColumnComment("內(nèi)容")
private String content;
@ColumnComment("發(fā)布人")
@InsertOptionUser(UserIdAutoFillHandler.class)
// 添加了該注解后,針對文章的查詢蝠引、修改阳谍、刪除操作,均會被自動帶上 published_user_id=?或者published_user_id in (?)的條件螃概,?值來自于CurrentUserDynamicConditionHandler的values()返回值
@DynamicCondition(CurrentUserDynamicConditionHandler.class)
private String publishedUserId;
// 省略其他字段
......
}
@Component
public class CurrentUserDynamicConditionHandler implements IDynamicConditionHandler {
@Resource
private HttpServletRequest request;
@Override
public List<Object> values() {
/* 只有當enable()返回true的時候 本動態(tài)條件才生效矫夯。
* 返回空集合或者null的時候,sql上體現(xiàn)的是 [column] is null吊洼,只返回一個值的時候sql上體現(xiàn)的是 [column]=***训貌,返回集合的時候,sql上體現(xiàn)的是 [column] in (***)
*/
String userId = request.getHeader("USER_ID");
return Collections.singletonList(userId);
}
@Override
public boolean enable() {
// 簡單例子:header中取用戶權(quán)限融蹂,如果是非管理員則執(zhí)行該過濾條件旺订,如果是管理員默認查全部,返回false超燃,本動態(tài)條件失效
String userRule = request.getHeader("USER_ROLE");
return !"ADMIN".equals(userRule);
}
}
BaseEntity使用
通常的表設計中区拳,都會要求添加一些審計數(shù)據(jù),比如創(chuàng)建人意乓、創(chuàng)建時間樱调、最后修改人约素、最后修改時間,但是這些屬性又不應該屬于業(yè)務的笆凌,更多的是為了數(shù)據(jù)管理使用的圣猎。如果業(yè)務需要使用的話,建議起一個有意義的業(yè)務名稱與上述的創(chuàng)建時間區(qū)分開乞而,比如用戶的注冊時間(registrationTime)送悔。為了簡化數(shù)據(jù)審計字段的工作量,框架內(nèi)部集成了BaseEntity
@Getter
@Setter
public class BaseEntity<ID_TYPE extends Serializable, TIME_TYPE> {
// 這里就是數(shù)據(jù)填充樣例那里提到的IOptionByAutoFillHandler接口
// 此處單獨指定一個標記性的接口是為了區(qū)別用戶其他數(shù)據(jù)的自動填充爪模,例如用戶名欠啤、用戶電話等都會實現(xiàn)AutoFillHandler接口,框架上根據(jù)該接口無法拿到唯一的實現(xiàn)屋灌,因此同樣IOptionByAutoFillHandler在整個系統(tǒng)中也只能有一個實現(xiàn)洁段,不然會報錯。
@InsertOptionUser(IOptionByAutoFillHandler.class)
@ColumnComment("創(chuàng)建人")
protected ID_TYPE createBy;
@InsertUpdateOptionUser(IOptionByAutoFillHandler.class)
@ColumnComment("最后更新人")
protected ID_TYPE updateBy;
@InsertOptionDate
@ColumnComment("創(chuàng)建時間")
protected TIME_TYPE createTime;
@InsertUpdateOptionDate
@ColumnComment("最后更新時間")
protected TIME_TYPE updateTime;
}
還存在某些情況下數(shù)據(jù)表要求設計成邏輯刪除(邏輯刪除存在很多弊端共郭,不建議無腦所有表都設計為邏輯刪除)祠丝,所以框架同時提供了一個BaseLogicEntity,該實現(xiàn)方式利用的是MP本身自帶的邏輯刪除策略除嘹。
@Getter
@Setter
public class BaseLogicEntity<ID_TYPE extends Serializable, TIME_TYPE> extends BaseEntity<ID_TYPE, TIME_TYPE> {
// 使用了MP支持的邏輯刪除注解
@TableLogic
@DefaultValue("0")
@ColumnComment("邏輯刪除標志")
protected Integer deleted;
}
BaseRepository使用
建議開發(fā)中以此為數(shù)據(jù)基本操作類写半,而不是以*Mapper為基礎操作類,如果需要使用*Mapper中的方法憾赁,可以直接通過getMapper()取得Entity對應的*Mapper類污朽,此類與*Mapper類相比做了很多的增強功能,尤其是其lambda語法龙考,非常高效便捷蟆肆。
// 集成了MP的ServiceImpl,實現(xiàn)了IBaseRepository接口(內(nèi)部拓展了lambda查詢操作)
public abstract class BaseRepository<M extends BaseMapper<E>, E> extends ServiceImpl<M, E> implements IBaseRepository<E> {
@Override
public boolean updateById(E entity) {
boolean result = super.updateById(entity);
if(result) {
// 數(shù)據(jù)自動更新@DataSource注解的配合邏輯
SpringContextUtil.getApplicationContext()
.publishEvent(EntityUpdateEvent.create(entity));
}
return result;
}
@Override
public boolean updateBatchById(Collection<E> entityList, int batchSize) {
boolean result = super.updateBatchById(entityList, batchSize);
if(result) {
// 數(shù)據(jù)自動更新@DataSource注解的配合邏輯
for (E entity : entityList) {
SpringContextUtil.getApplicationContext().publishEvent(EntityUpdateEvent.create(entity));
}
}
return result;
}
@Override
protected Class<M> currentMapperClass() {
return (Class<M>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseRepository.class, 0);
}
@Override
protected Class<E> currentModelClass() {
return (Class<E>) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseRepository.class, 1);
}
}
注解詳細介紹
自動建表注解
只有小部分注解晦款,進行了輕微改動炎功,基本所有注解均是通用的,詳細教程可以直接參考A.CTable官方缓溅。
@Table
- 新增primary屬性蛇损,對應@TablePrimary
- isNull屬性為了一致性改為了isNotNull屬性默認false
- 新增dsName屬性,對應@DsName
@TableCharset
@TableComment
@TableEngine
@TablePrimary
新增注解坛怪,等同@Table中的primary屬性淤齐,在多個Entity映射一張表的情況下,確定主Entity是哪個袜匿,數(shù)據(jù)表生成的時候根據(jù)主表來生成更啄。
@DsName
新增注解,等同@Table中的dsName屬性居灯,在多數(shù)據(jù)源場景下祭务,指定某個表的數(shù)據(jù)源内狗。
@IgnoreTable
@EnableTimeSuffix
@Column
@ColumnComment
@ColumnDefault
原@DefaultValue,跟本框架中的數(shù)據(jù)插入的時候指定默認值的注解重名了义锥,因此把這里改名字了
@ColumnType
@IsAutoIncrement
@IsKey
@IsNotNull
@IsNativeDefValue
@Unique
@Index
@IgnoreUpdate
數(shù)據(jù)填充類注解
@OptionDate
描述:
自動賦值數(shù)據(jù)操作時間柳沙。需結(jié)合mybatis-plus原框架注解
@TableField
(該注解的使用請查看官方文檔,懶得看的話拌倍,請往下讀赂鲤,有驚喜)一并使用才有效。被標注的字段贰拿,在可允許的類型范圍(
String
蛤袒、Long
熄云、long
膨更、Date
、LocalDate
缴允、LocalDateTime
)內(nèi)荚守,數(shù)據(jù)被操作的情況下,會自動被賦值上當前時間练般。如果使用String的話需要同時指明
format
參矗漾,用以確認格式化后的樣式。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
format | String | 非必需 | yyyy-MM-dd HH:mm:ss | 如果字段類型為String薄料,需要制定字符串格式 |
override | boolean | 非必需 | true | 若對象上存在值敞贡,是否覆蓋 |
擴展注解:
注解 | 描述 |
---|---|
@InsertOptionDate |
基于@OptionDate 的拓展,無需結(jié)合@TableField 摄职,數(shù)據(jù)插入的時候誊役,自動賦值數(shù)據(jù)操作時間。 |
@UpdateOptionDate |
基于@OptionDate 的拓展谷市,無需結(jié)合@TableField 蛔垢,數(shù)據(jù)更新(注意:update(Wrapper<T> updateWrapper)方法除外)的時候,自動賦值數(shù)據(jù)操作時間迫悠。 |
@InsertUpdateOptionDate |
基于@OptionDate 的拓展鹏漆,無需結(jié)合@TableField ,數(shù)據(jù)插入创泄、更新(注意:update(Wrapper<T> updateWrapper)方法除外)的時候艺玲,自動賦值數(shù)據(jù)操作時間。 |
@OptionUser
描述:
指定實現(xiàn)方式鞠抑,自動賦值數(shù)據(jù)操作人員信息饭聚。需結(jié)合mybatis-plus原框架注解
@TableField
(該注解的使用請查看官方文檔,懶得看的話碍拆,請往下讀若治,有驚喜)一并使用才有效慨蓝。被標注的字段,會根據(jù)
@OptionUser
中AuditHandler
的實現(xiàn)來返回對應的值端幼。通常的實現(xiàn)方案都是用戶信息(id礼烈、name等)放入header中,全局定義函數(shù)來獲取婆跑。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
value | Class<? extends AuditHandler<?>> | 必需 | 自定義用戶信息生成方式 | |
override | boolean | 非必需 | true | 若對象上存在值此熬,是否覆蓋 |
擴展注解:
注解 | 描述 |
---|---|
@InsertOptionUser |
基于@OptionUser 的拓展,無需結(jié)合@TableField 滑进,數(shù)據(jù)插入的時候犀忱,自動賦值操作人信息。 |
@UpdateOptionUser |
基于@OptionUser 的拓展扶关,無需結(jié)合@TableField 阴汇,數(shù)據(jù)更新(注意:update(Wrapper<T> updateWrapper)方法除外)的時候,自動賦值操作人信息节槐。 |
@InsertUpdateOptionUser |
基于@OptionUser 的拓展搀庶,無需結(jié)合@TableField ,數(shù)據(jù)插入铜异、更新(注意:update(Wrapper<T> updateWrapper)方法除外)的時候哥倔,自動賦值操作人信息。 |
@DefaultValue
描述:
數(shù)據(jù)插入的時候字段的默認值揍庄,支持類型:String, Integer, int, Long, long, Boolean, boolean, Double, double, Float, float, BigDecimal, Date, LocalDate, LocalDateTime咆蒿,枚舉(僅支持枚舉的名字作為默認值)
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
value | String | 必需 | 默認值 | |
format | boolean | 非必需 | yyyy-MM-dd HH:mm:ss | 如果字段類型為時間類型(Date,LocalDateTime等),需要制定字符串格式 |
關聯(lián)查詢類注解
@BindField
描述:
綁定其他Entity的某個字段蚂子,可實現(xiàn)一對一沃测、一對多的綁定查詢。
注意:所有Bind注解底層均依賴相關Entity的Mapper缆镣,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 是 | 被關聯(lián)的Entity | |
field | String | 是 | 被關聯(lián)的Entity的具體字段 | |
conditions | @JoinCondition[] | 是 | 關聯(lián)Entity所需要的條件 | |
customCondition | String | 否 | 被關聯(lián)的Entity所需要的額外條件芽突,通常指被關聯(lián)的Entity自身的特殊條件,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件董瞻,被關聯(lián)的Entity或者字段為結(jié)果集的時候生效 |
@BindEntity
描述:
綁定其他Entity寞蚌,可實現(xiàn)一對一、一對多的綁定查詢钠糊。
注意:所有Bind注解底層均依賴相關Entity的Mapper挟秤,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 否 | 字段聲明類型 | 被關聯(lián)的Entity,不再需要顯示的指明抄伍,默認取字段上的聲明類型 |
conditions | @JoinCondition[] | 是 | 關聯(lián)Entity所需要的條件 | |
customCondition | String | 否 | 被關聯(lián)的Entity所需要的額外條件艘刚,通常指被關聯(lián)的Entity自身的特殊條件,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件截珍,被關聯(lián)的Entity或者字段為結(jié)果集的時候生效 | |
deepBind | boolean | 否 | false | 深度綁定攀甚,列表數(shù)據(jù)的情況下會產(chǎn)生性能問題箩朴。(不熟悉的,不建議使用) |
@JoinCondition
描述:
綁定條件
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
selfField | String | 是 | 關聯(lián)Entity所需的自身字段 | |
joinField | String | 是 | "id" | 被關聯(lián)Entity的關聯(lián)字段秋度,默認為關聯(lián)Entity的id |
@JoinOrderBy
描述:
綁定結(jié)果的排序
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
field | String | 是 | 被關聯(lián)的Entity中結(jié)果集排序字段 | |
isAsc | boolean | 否 | false | 排序炸庞,true:正序,false:倒序 |
@BindFieldByMid
描述:
通過中間關系Entity的形式綁定其他Entity的某個字段荚斯,可實現(xiàn)一對一埠居、一對多、多對多的綁定查詢事期。
注意:所有Bind注解底層均依賴相關Entity的Mapper滥壕,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 是 | 被關聯(lián)的Entity | |
field | String | 是 | 被關聯(lián)的Entity的具體字段 | |
conditions | @MidCondition | 是 | 中間表關聯(lián)條件 | |
customCondition | String | 否 | 被關聯(lián)的Entity所需要的額外條件,通常指被關聯(lián)的Entity自身的特殊條件兽泣,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件绎橘,被關聯(lián)的Entity或者字段為結(jié)果集的時候生效 |
@BindEntityByMid
描述:
通過中間關系Entity的形式綁定其他Entity,可實現(xiàn)一對一撞叨、一對多金踪、多對多的綁定查詢。
注意:所有Bind注解底層均依賴相關Entity的Mapper牵敷,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 是 | 被關聯(lián)的Entity | |
conditions | @MidCondition | 是 | 中間表關聯(lián)條件 | |
customCondition | String | 否 | 被關聯(lián)的Entity所需要的額外條件,通常指被關聯(lián)的Entity自身的特殊條件法希,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件枷餐,被關聯(lián)的Entity或者字段為結(jié)果集的時候生效 | |
deepBind | boolean | 否 | false | 深度綁定,列表數(shù)據(jù)的情況下會產(chǎn)生性能問題苫亦。(不熟悉的毛肋,不建議使用) |
@MidCondition
描述:
中間表條件描述
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
midEntity | Class<?> | 是 | 中間表Entity,需要對應創(chuàng)建其Mapper | |
selfField | String | 是 | "Id" | 關聯(lián)Entity所需的自身字段 |
selfMidField | String | 是 | 關聯(lián)Entity所需的自身字段屋剑,中間表字段名 | |
joinField | String | 是 | "id" | 被關聯(lián)Entity的關聯(lián)字段 |
joinMidField | String | 是 | 被關聯(lián)Entity的關聯(lián)字段润匙,中間表字段名 |
數(shù)據(jù)同步注解
@DataSource
描述:
通過注解指定數(shù)據(jù)來源,底層框架自動通過Spring中的事件機制監(jiān)聽EntityUpdateEvent事件唉匾,完成數(shù)據(jù)自動更新孕讳。在BaseRepository<Mapper, Entity>的基類中,默認實現(xiàn)了updateById巍膘、updateBatchById兩個方法自動發(fā)布EntityUpdateEvent事件厂财,所以只要對應Entity的Repository繼承了BaseRepository<Mapper, Entity>便具備了通過ID更新數(shù)據(jù)的自動同步數(shù)據(jù)的功能。
拓展:分布式情況下如何同步其他服務的數(shù)據(jù)_峡懈?不妨先想一想璃饱。其實sourceName屬性就是為此情況預留的,引入外部MQ肪康,監(jiān)聽Spring下的EntityUpdateEvent事件荚恶,然后推送至MQ撩穿,另一邊消費MQ中的事件,再還原出EntityUpdateEvent事件廣播到各個系統(tǒng)即可谒撼,這其中還需要考慮和解決時序和事務的問題冗锁。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
source | Class<?> | 否,與sourceName 二選一 |
Void.class | 數(shù)據(jù)來源的Entity class |
sourceName | String | 否嗤栓,與source 二選一 |
"" | 數(shù)據(jù)來源的Entity class 的全路徑名稱(包名.類名) |
field | String | 是 | 數(shù)據(jù)來源的Entity對應的屬性 | |
conditions | Condition[] | 是 | 被關聯(lián)的Entity所需要的條件 |
@Condition
描述:
數(shù)據(jù)來源的關聯(lián)條件
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
selfField | String | 是 | 關聯(lián)數(shù)據(jù)來源Entity所需的自身字段 | |
sourceField | String | 是 | "id" | 數(shù)據(jù)來源的Entity的字段冻河,默認為id |
動態(tài)條件注解
@DynamicCondition
描述:
適用場景:數(shù)據(jù)篩選,比如根據(jù)不同權(quán)限獲取不同數(shù)據(jù)茉帅,用戶只能看到自己的數(shù)據(jù)叨叙,管理員能看到所有人的數(shù)據(jù)。
具體demo移步快速開始的例子堪澎。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
value | Class<? extends IDynamicConditionHandler> | 是 | IDynamicConditionHandler接口有兩個方法擂错,enable()決定了該條件是否生效,values()是條件匹配的值樱蛤。 |