簡介
本框架(Gitee地址 )結合公司日常業務場景,對Mybatis-Plus 做了進一步的拓展封裝,即保留MP原功能,又添加更多有用便捷的功能。具體拓展體現在
數據自動填充(類似JPA中的審計)
、關聯查詢(類似sql中的join)
、自動建表(僅支持mysql)
、冗余數據自動更新
、動態條件
等功能做了補充完善。其中自動建表
,是在A.CTable 框架上的基礎上改進適配本框架的,只保留了其表創建功能,因此改動較大不與原框架兼容。
項目地址
https://gitee.com/tangzc/mybatis-plus-ext
快速開始
引入jar包
starter內自帶了MybatisPlus3.4.3.3版本及spring-boot2.3.12的依賴管理,如果要更改springboot的版本,可以排除掉,但是如果要變更MybatisPlus的版本,請注意了,框架中重寫了TableInfoHelper,不同版本的MP該類有所變動,同時框架內也采用了MP的部分工具類,例如LambdaUtils、ReflectionKit等在不同的版本也有所變動,需要小心,哈哈哈哈,可以聯系我幫你改~~
<dependency>
<groupId>com.tangzc</groupId>
<artifactId>mybatis-plus-ext-boot-starter</artifactId>
<version>1.2.9</version>
</dependency>
自動建表
根據實體上的注解及字段注解自動創建、更新數據庫表。
官方的設計思路是默認Bean下的所有字段均不是表字段,需要手動通過@Column聲明,我在引用過來之后,改為了默認所有字段均為表字段,只有被MP的@TableField(exist=false)修飾的才會被排除,具備@TableField(exist=false)功能的注解有:@Exclude、@Bind**系列,他們集成了@TableField,且內置exist屬性為false了。
另外A.CTable框架內部集成了類似MP的功能,不如MP完善,所以我也剔除掉了,順帶解決了不兼容和bug。同時像DefaultValue注解重名了,也給它改名為ColumnDefault了,另外整理了一遍內部的注解利用spring的AliasFor做了關聯,更方便管理。
其中還有一點,@Table里面加了一個primary屬性,表示是否為主表,為了支持多個Entity對應一個數據庫表(正常用不到請忽略_)
@Data
// @Table標記的可被識別為需要自動創建表的Entity
@Table(comment = "用戶")
public class User {
// 自動識別id屬性名為主鍵
// @IsAutoIncrement聲明為自增主鍵,什么都不聲明的話,默認為雪花算法的唯一主鍵(MP的自帶功能),推薦默認便於后期的數據分布式存儲等處理。
@IsAutoIncrement
// 字段注釋
@ColumnComment("主鍵")
// 字段長度
@ColumnLength(32)
private String id;
// 索引
@Index
// 非空
@IsNotNull
@ColumnComment("名字")
private String name;
// 唯一索引
@Unique
// 非空
@IsNotNull
@ColumnComment("手機號")
private String phone;
// 省略其他屬性
......
}
// 啟用自動生成數據庫表功能,此處簡化了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_
數據填充
可以在數據插入或更新的時候,自動賦值數據操作人、操作時間、默認值等屬性。
以文章發布為例,講解一下數據填充的基本用法。通過如下例子可發現,在創建Artice的時候,我們無需再去關心過多的與業務無關的字段值,只需要關心
title
、content
兩個核心數據即可,其他的數據均會被框架處理。
@Data
@Table(comment = "文章")
public class Article {
// 字符串類型的ID,默認也是雪花算法的一串數字(MP的默認功能)
@ColumnComment("主鍵")
private String id;
@ColumnComment("標題")
private String title;
@ColumnComment("內容")
private String content;
// 文章默認激活狀態
@DefaultValue("ACTIVE")
@ColumnComment("內容")
// ActicleStatusEnum(ACTIVE, INACTIVE)
private ActicleStatusEnum status;
@ColumnComment("發布時間")
// 插入數據時候會自動獲取系統當前時間賦值,支持多種數據類型,具體可參考@OptionDate注解詳細介紹
@InsertOptionDate
private Date publishedTime;
@ColumnComment("發布人")
// 插入的時候,根據UserIdAutoFillHandler自動填充用戶id
@InsertOptionUser(UserIdAutoFillHandler.class)
private String publishedUserId;
@ColumnComment("發布人名字")
// 插入的時候,根據UserIdAutoFillHandler自動填充用戶名字
@InsertOptionUser(UsernameAutoFillHandler.class)
private String publishedUsername;
@ColumnComment("最后更新時間")
// 插入和更新數據時候會自動獲取系統當前時間賦值,支持多種數據類型,具體可參考@OptionDate注解詳細介紹
@InsertUpdateOptionDate
private Date publishedTime;
@ColumnComment("最后更新人")
// 插入和更新的時候,根據UserIdAutoFillHandler自動填充用戶id
@InsertUpdateOptionUser(UserIdAutoFillHandler.class)
private String publishedUserId;
@ColumnComment("最后更新人名字")
// 插入和更新的時候,根據UserIdAutoFillHandler自動填充用戶名字
@InsertUpdateOptionUser(UsernameAutoFillHandler.class)
private String publishedUsername;
}
/**
* 全局獲取用戶ID
* 此處實現IOptionByAutoFillHandler接口和AutoFillHandler接口均可,建議實現IOptionByAutoFillHandler接口,
* 因為框架內的BaseEntity默認需要IOptionByAutoFillHandler的實現。后面會講到BaseEntity的使用。
*/
@Component
public class UserIdAutoFillHandler implements IOptionByAutoFillHandler<String> {
/**
* @param object 當前操作的數據對象
* @param clazz 當前操作的數據對象的class
* @param field 當前操作的數據對象上的字段
* @return 當前登錄用戶id
*/
@Override
public String getVal(Object object, Class<?> clazz, Field field) {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
// 配合網關或者過濾器,token校驗成功后就把用戶信息塞到header中
return request.getHeader("user-id");
}
}
/**
* 全局獲取用戶名
*/
@Component
public class UsernameAutoFillHandler implements AutoFillHandler<String> {
/**
* @param object 當前操作的數據對象
* @param clazz 當前操作的數據對象的class
* @param field 當前操作的數據對象上的字段
* @return 當前登錄用戶id
*/
@Override
public String getVal(Object object, Class<?> clazz, Field field) {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
// 配合網關或者過濾器,token校驗成功后就把用戶信息塞到header中
return request.getHeader("user-name");
}
}
關聯查詢
數據關聯查詢的解決方案,替代sql中的join方式,通過注解關聯多表之間的關系,查詢某實體的時候,自動帶出其關聯性的數據實體。
本示例以比較復雜的通過中間表關聯數據的案例來講解下,用戶和角色之間多對多,通過中間表進行數據級聯,@BindEntity*系列是關聯Entity的數據,@BindField*系列是關聯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想關聯對應的Rule集合,中間表是UserRule
@BindEntityByMid(conditions = @MidCondition(
midEntity = UserRole.class, selfMidField = "userId", joinMidField = "roleId"
))
private List<Role> roles;
}
@Data
@Table(comment = "用戶-角色關聯關系")
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;
/**
* 根據用戶的名字模糊查詢所有用戶的詳細信息
*/
@Transactional(readOnly = true)
public List<UserDetailWithRoleDto> searchUserByNameWithRule(String name) {
// MP的lambda查詢方式
List<User> userList = userRepository.lambdaQuery()
.eq(name != null, User::getUsername, name)
.list();
// 關鍵步驟,指定關聯角色數據。如果你打開sql打印,會看到3條sql語句,第一條根據id去User表查詢user信息,第二條根據userId去UserRule中間表查詢所有的ruleId,第三條sql根據ruleId集合去Rule表查詢全部的權限
Binder.bindOn(userList, User::getRoles);
// Binder.bind(userList); 此種用法默認關聯user下所有聲明需要綁定的元素
return UserMapping.MAPPER.toDto5(userList);
}
/**
* 根據用戶的名字模糊查詢所有用戶的詳細信息,等價於上一個查詢方式
*/
@Transactional(readOnly = true)
public List<UserDetailWithRoleDto> searchUserByNameWithRule2(String name) {
// 本框架拓展的lambda查詢器lambdaQueryPlus,增加了bindOne、bindList、bindPage
// 顯然這是一種更加簡便的查詢方式,但是如果存在多級深度的關聯關系,此種方法就不適用了,還需要借助Binder
List<User> userList = userRepository.lambdaQueryPlus()
.eq(name != null, User::getUsername, name)
.bindList(User::getRoles);
return UserMapping.MAPPER.toDto5(userList);
}
}
提示: 假如存在此種場景:User
、Role
、Menu
三個實體,他們之間的關系是:User
多對多 Role
、Role
多對多Menu
,當我查詢出User的集合后,如何獲取Role和Menu的數據呢?
// 數據庫查詢出了用戶列表 【1】
List<User> userList = userRepository.list();
// 為所有用戶關聯角色信息 【2】
Binder.bindOn(userList, User::getRoles);
// 為所有角色信息關聯菜單信息 【3】
// Deeper為一個深度遍歷工具,可以深入到對象的多層屬性內部,從而獲取全局上該層級的所有對象同一屬性
Binder.bindOn(Deeper.with(userList).inList(User::getRoles), User::getMenus);
注意📢:【2】和【3】存在順序依賴,必須先執行【2】才能執行【3】
數據冗余
當其他表的數據需要作為當前表的查詢條件的時候,多數情況下會使用sql的join語法,另一種方案是做數據冗余,講其他表的字段作為當前表的字段,但是牽扯一個數據修改后同步的問題,本框架可以解決。
假設用戶評論的場景,評論上需要冗余用戶名和頭像,如果用戶的名字和頭像有改動,則需要同步新的改動,代碼如下:
@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("評論內容")
private String content;
@ColumnComment("評論人id")
private String userId;
// 基於該注解,框架會自動注冊監聽EntityUpdateEvent事件,User的updateById和updateBatchById兩個方法會自動發布EntityUpdateEvent事件
@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;
}
動態條件
適用場景:數據篩選,比如根據不同權限獲取不同數據,用戶只能看到自己的數據,管理員能看到所有人的數據。
此種場景,我們通常需要在每一個查詢、更新、刪除的sql操作上都追加上某個條件,很容易忘記,但是可以抽象成注解直接配置到Entity上,就省去了每個數據操作關心這個特殊條件了。
@Data
@Table(comment = "文章")
public class Article {
@ColumnComment("主鍵")
private String id;
@ColumnComment("標題")
private String title;
@ColumnComment("內容")
private String content;
@ColumnComment("發布人")
@InsertOptionUser(UserIdAutoFillHandler.class)
// 添加了該注解后,針對文章的查詢、修改、刪除操作,均會被自動帶上 published_user_id=或者in的添加
@DynamicCondition(CurrentUserDynamicConditionHandler.class)
private String publishedUserId;
// 省略其他字段
......
}
@Component
public class CurrentUserDynamicConditionHandler implements IDynamicConditionHandler {
@Resource
private HttpServletRequest request;
@Override
public List<Object> values() {
// 只有當enable()返回true的時候 本動態條件才 生效
// 返回空集合或者null的時候,sql上體現的是 [column] is null,只返回一個值的時候sql上體現的是 [column]=***,返回集合的時候,sql上體現的是 [column] in (***)
String userId = request.getHeader("USER_ID");
return Collections.singletonList(userId);
}
@Override
public boolean enable() {
// 簡單例子:header中取用戶權限,如果是非管理員則執行該過濾條件,如果是管理員默認查全部,返回false,本動態條件失效
String userRule = request.getHeader("USER_ROLE");
return !"ADMIN".equals(userRule);
}
}
BaseEntity使用
通常的表設計中,都會要求添加一些審計數據,比如創建人、創建時間、最后修改人、最后修改時間,但是這些屬性又不應該屬於業務的,更多的是為了數據管理使用的。如果業務需要使用的話,建議起一個有意義的業務名稱與上述的創建時間區分開,比如用戶的注冊時間(registrationTime)。為了簡化數據審計字段的工作量,框架內部集成了BaseEntity
@Getter
@Setter
public class BaseEntity<ID_TYPE extends Serializable, TIME_TYPE> {
// 這里就是數據填充樣例那里提到的IOptionByAutoFillHandler接口
// 此處單獨指定一個標記性的接口是為了區別用戶其他數據的自動填充,例如用戶名、用戶電話等都會實現AutoFillHandler接口,框架上根據該接口無法拿到唯一的實現,因此同樣IOptionByAutoFillHandler在整個系統中也只能有一個實現,不然會報錯。
@InsertOptionUser(IOptionByAutoFillHandler.class)
@ColumnComment("創建人")
protected ID_TYPE createBy;
@InsertUpdateOptionUser(IOptionByAutoFillHandler.class)
@ColumnComment("最后更新人")
protected ID_TYPE updateBy;
@InsertOptionDate
@ColumnComment("創建時間")
protected TIME_TYPE createTime;
@InsertUpdateOptionDate
@ColumnComment("最后更新時間")
protected TIME_TYPE updateTime;
}
還存在某些情況下數據表要求設計成邏輯刪除(邏輯刪除存在很多弊端,不建議無腦所有表都設計為邏輯刪除),所以框架同時提供了一個BaseLogicEntity,該實現方式利用的是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使用
建議開發中以此為數據基本操作類,而不是以*Mapper為基礎操作類,如果需要使用*Mapper中的方法,可以直接通過getMapper()取得Entity對應的*Mapper類,此類與*Mapper類相比做了很多的增強功能,尤其是其lambda語法,非常高效便捷。
// 集成了MP的ServiceImpl,實現了IBaseRepository接口(內部拓展了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) {
// 數據自動更新@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) {
// 數據自動更新@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屬性,isNull屬性為了一致性改為了isNotNull屬性默認false
@TableCharset
@TableComment
@TableEngine
@TablePrimary
新增注解,同步@Table中的primary屬性,在多個Entity映射一張表的情況下,確定主Entity是哪個,數據表生成的時候根據主表來生成。
@IgnoreTable
@EnableTimeSuffix
@Column
@ColumnComment
@ColumnDefault
原@DefaultValue,跟本框架中的數據插入的時候指定默認值的注解重名了,因此把這里改名字了
@ColumnType
@IsAutoIncrement
@IsKey
@IsNotNull
@IsNativeDefValue
@Unique
@Index
@IgnoreUpdate
數據填充類注解
@OptionDate
描述:
自動賦值數據操作時間。需結合mybatis-plus原框架注解
@TableField
(該注解的使用請查看官方文檔,懶得看的話,請往下讀,有驚喜)一並使用才有效。被標注的字段,在可允許的類型范圍(
String
、Long
、long
、Date
、LocalDate
、LocalDateTime
)內,數據被操作的情況下,會自動被賦值上當前時間。如果使用String的話需要同時指明
format
參,用以確認格式化后的樣式。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
format | String | 非必需 | yyyy-MM-dd HH:mm:ss | 如果字段類型為String,需要制定字符串格式 |
override | boolean | 非必需 | true | 若對象上存在值,是否覆蓋 |
擴展注解:
注解 | 描述 |
---|---|
@InsertOptionDate |
基於@OptionDate 的拓展,無需結合@TableField ,數據插入的時候,自動賦值數據操作時間。 |
@UpdateOptionDate |
基於@OptionDate 的拓展,無需結合@TableField ,數據更新(注意:update(Wrapper
|
@InsertUpdateOptionDate |
基於@OptionDate 的拓展,無需結合@TableField ,數據插入、更新(注意:update(Wrapper
|
@OptionUser
描述:
指定實現方式,自動賦值數據操作人員信息。需結合mybatis-plus原框架注解
@TableField
(該注解的使用請查看官方文檔,懶得看的話,請往下讀,有驚喜)一並使用才有效。被標注的字段,會根據
@OptionUser
中AuditHandler
的實現來返回對應的值。通常的實現方案都是用戶信息(id、name等)放入header中,全局定義函數來獲取。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
value | Class> | 必需 | 自定義用戶信息生成方式 | |
override | boolean | 非必需 | true | 若對象上存在值,是否覆蓋 |
擴展注解:
注解 | 描述 |
---|---|
@InsertOptionUser |
基於@OptionUser 的拓展,無需結合@TableField ,數據插入的時候,自動賦值操作人信息。 |
@UpdateOptionUser |
基於@OptionUser 的拓展,無需結合@TableField ,數據更新(注意:update(Wrapper
|
@InsertUpdateOptionUser |
基於@OptionUser 的拓展,無需結合@TableField ,數據插入、更新(注意:update(Wrapper
|
@DefaultValue
描述:
數據插入的時候字段的默認值,支持類型: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等),需要制定字符串格式 |
關聯查詢類注解
@BindField
描述:
綁定其他Entity的某個字段,可實現一對一、一對多的綁定查詢。
注意:所有Bind注解底層均依賴相關Entity的Mapper,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 是 | 被關聯的Entity | |
field | String | 是 | 被關聯的Entity的具體字段 | |
conditions | @JoinCondition[] | 是 | 關聯Entity所需要的條件 | |
customCondition | String | 否 | 被關聯的Entity所需要的額外條件,通常指被關聯的Entity自身的特殊條件,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件,被關聯的Entity或者字段為結果集的時候生效 |
@BindEntity
描述:
綁定其他Entity,可實現一對一、一對多的綁定查詢。
注意:所有Bind注解底層均依賴相關Entity的Mapper,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 否 | 字段聲明類型 | 被關聯的Entity,不再需要顯示的指明,默認取字段上的聲明類型 |
conditions | @JoinCondition[] | 是 | 關聯Entity所需要的條件 | |
customCondition | String | 否 | 被關聯的Entity所需要的額外條件,通常指被關聯的Entity自身的特殊條件,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件,被關聯的Entity或者字段為結果集的時候生效 | |
deepBind | boolean | 否 | false | 深度綁定,列表數據的情況下會產生性能問題。(不熟悉的,不建議使用) |
@JoinCondition
描述:
綁定條件
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
selfField | String | 是 | 關聯Entity所需的自身字段 | |
joinField | String | 是 | "id" | 被關聯Entity的關聯字段,默認為關聯Entity的id |
@JoinOrderBy
描述:
綁定結果的排序
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
field | String | 是 | 被關聯的Entity中結果集排序字段 | |
isAsc | boolean | 否 | false | 排序,true:正序,false:倒序 |
@BindFieldByMid
描述:
通過中間關系Entity的形式綁定其他Entity的某個字段,可實現一對一、一對多、多對多的綁定查詢。
注意:所有Bind注解底層均依賴相關Entity的Mapper,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 是 | 被關聯的Entity | |
field | String | 是 | 被關聯的Entity的具體字段 | |
conditions | @MidCondition | 是 | 中間表關聯條件 | |
customCondition | String | 否 | 被關聯的Entity所需要的額外條件,通常指被關聯的Entity自身的特殊條件,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件,被關聯的Entity或者字段為結果集的時候生效 |
@BindEntityByMid
描述:
通過中間關系Entity的形式綁定其他Entity,可實現一對一、一對多、多對多的綁定查詢。
注意:所有Bind注解底層均依賴相關Entity的Mapper,且Mapper必須繼承MybatisPlus的BaseMapper<Entity, ID>
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
entity | Class<?> | 是 | 被關聯的Entity | |
conditions | @MidCondition | 是 | 中間表關聯條件 | |
customCondition | String | 否 | 被關聯的Entity所需要的額外條件,通常指被關聯的Entity自身的特殊條件,例如:enable=1 and is_deleted=0 | |
orderBy | @JoinOrderBy[] | 否 | 排序條件,被關聯的Entity或者字段為結果集的時候生效 | |
deepBind | boolean | 否 | false | 深度綁定,列表數據的情況下會產生性能問題。(不熟悉的,不建議使用) |
@MidCondition
描述:
中間表條件描述
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
midEntity | Class<?> | 是 | 中間表Entity,需要對應創建其Mapper | |
selfField | String | 是 | "Id" | 關聯Entity所需的自身字段 |
selfMidField | String | 是 | 關聯Entity所需的自身字段,中間表字段名 | |
joinField | String | 是 | "id" | 被關聯Entity的關聯字段 |
joinMidField | String | 是 | 被關聯Entity的關聯字段,中間表字段名 |
數據同步注解
@DataSource
描述:
通過注解指定數據來源,底層框架自動通過Spring中的事件機制監聽EntityUpdateEvent事件,完成數據自動更新。在BaseRepository<Mapper, Entity>的基類中,默認實現了updateById、updateBatchById兩個方法自動發布EntityUpdateEvent事件,所以只要對應Entity的Repository繼承了BaseRepository<Mapper, Entity>便具備了通過ID更新數據的自動同步數據的功能。
拓展:分布式情況下如何同步其他服務的數據_?不妨先想一想。其實sourceName屬性就是為此情況預留的,引入外部MQ,監聽Spring下的EntityUpdateEvent事件,然后推送至MQ,另一邊消費MQ中的事件,再還原出EntityUpdateEvent事件廣播到各個系統即可,這其中還需要考慮和解決時序和事務的問題。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
source | Class<?> | 否,與sourceName 二選一 |
Void.class | 數據來源的Entity class |
sourceName | String | 否,與source 二選一 |
"" | 數據來源的Entity class 的全路徑名稱(包名.類名) |
field | String | 是 | 數據來源的Entity對應的屬性 | |
conditions | Condition[] | 是 | 被關聯的Entity所需要的條件 |
@Condition
描述:
數據來源的關聯條件
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
selfField | String | 是 | 關聯數據來源Entity所需的自身字段 | |
sourceField | String | 是 | "id" | 數據來源的Entity的字段,默認為id |
動態條件注解
@DynamicCondition
描述:
適用場景:數據篩選,比如根據不同權限獲取不同數據,用戶只能看到自己的數據,管理員能看到所有人的數據。
具體demo移步快速開始的例子。
字段:
屬性 | 類型 | 必需 | 默認值 | 描述 |
---|---|---|---|---|
value | Class<? extends IDynamicConditionHandler> | 是 | IDynamicConditionHandler接口有兩個方法,enable()決定了該條件是否生效,values()是條件匹配的值。 |