1.引入依赖
<dependency>
<groupId>com.xy</groupId>
<artifactId>xy-core-framework-dal-common</artifactId>
<version>${xy-core-framework-dal-common.version}</version>
</dependency>
提供了6个自定义注解
数据权限注解
TenantId(租户隔离),DeptId(部门ID),CreateBy(创建人)
强制选择主从数据源
ShardingMaster(强制走主库,可指定) ShardingOneSlave(强制从库,可指定)
2.设置DO类的权限注解
@Data
public class BaseEntity {
/**
* 主键
*/
@TableId
private Long id;
/**
* 创建人,添加注解可作为权限数据查询条件
*/
@CreateBy(value = "create_by", type = "String")
private String createBy;
}
@Data
public class ExtendEntity extends BaseEntity {
/**
* 商户编码,添加注解可作为权限数据查询条件
*/
@TenantId(value = "merchant_code", type = "String")
private String merchantCode;
/**
* 部门ID,添加注解可作为权限数据查询条件
*/
@DeptId(value = "dept_id", type = "Long")
private Long deptId;
}
3.实现权限数据加载
/**
* 数据权限加载
* <p>双层map结构,第一层map的key为表名</p >
* <p>第二层map的key为数据权限字段,目前二层key仅支持merchantCode,deptId,createBy</p >
*
* @author jack.li
* @version 1.0
* @date 2020/3/17 下午11:12
*/
@Slf4j
@Service("roleDataService")
public class RoleDataServiceImpl implements RoleDataService {
Map<String, Map<String, String>> columns = new HashMap<>();
@Override
public Map<String, Map<String, String>> tableColumns() {
log.info("<<<<<<<<<<<<<<<<<<<<<<XXXXXXXXXXXXXXXXX>>>>>>>>>>>>>>>>>>>>>");
Map<String, String> taskNotify = new HashMap<>();
// taskNotify.put("merchantCode", "channel");
// taskNotify.put("deptId", "dept");
// taskNotify.put("createBy", "create_id");
// columns.put("system_task_notify", taskNotify);
return columns;
}
}
4.框架默认装配
4.1分页拦截器
单数据源情况下,需要指定db-type类型。多数据源情况下,一定不要指定db类型,分页查询最大行数为100,
mybatis-plus.db-type=mysql
mybatis-plus.max-limit=100
4.2数据权限
只需实现步骤3,便会动态修改查询条件
4.3乐观锁
表结构定义中需要version版本号字段,更新时候将查询到的version设置到更新条件即可
4.4全局更新,删除禁止组件
对于无条件的更新,删除操作,会自动禁止sql执行.
4.5sql性能插件
建议在开发,测试环境开启,对于性能较差的sql,会跑出异常。例如!=,not in等操作,默认关闭。
mybatis-plus.illegal-s-q-l-inner-interceptor=true
5.数据权限底层实现说明(开发无需关心)
5.1自定义XyDataPermissionHandler接口
通过XyDataPermissionHandler获取mybaits-plus中的查询条件Expression
public interface XyDataPermissionHandler {
/**
* 获取数据权限 SQL 片段
*
* @param where 待执行 SQL Where 条件表达式
* @param mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法
* @return JSqlParser 条件表达式
*/
Expression getSqlSegment(Expression where, String mappedStatementId, Select select);
}
5.2自定义XyJsqlParserSupport sql解析
在processSelect方法中,通过XyDataPermissionHandler改变动态查询条件
@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
public class XyJsqlParserSupport extends JsqlParserSupport implements InnerInterceptor {
private XyDataPermissionHandler dataPermissionHandler;
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
log.info("---------beforeQuery start----------------");
/*
String sql = boundSql.getSql();
if (!boundSql.hasAdditionalParameter("merchant_code")) {
JwtUser userInfo = UserUtils.getUserInfo();
if (!Objects.isNull(userInfo)) {
boundSql.setAdditionalParameter("merchant_code", userInfo.getMerchantCode());
}
}
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
*/
log.info("---------beforeQuery end:{}----------------", boundSql.getSql());
}
@Override
public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
log.info("---------beforePrepare----------------");
}
@Override
protected void processInsert(Insert insert, int index, String sql, Object obj) {
super.processInsert(insert, index, sql, obj);
log.info("---------processInsert----------------");
}
@Override
protected void processDelete(Delete delete, int index, String sql, Object obj) {
super.processDelete(delete, index, sql, obj);
log.info("---------processDelete----------------");
}
@Override
protected void processUpdate(Update update, int index, String sql, Object obj) {
super.processUpdate(update, index, sql, obj);
log.info("---------processUpdate----------------");
}
@Override
protected void processSelect(Select select, int index, String sql, Object obj) {
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
Table table = (Table) plainSelect.getFromItem();
String name = table.getName();
log.info("---------processSelect---op table name :{}-------------", name);
Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), (String) obj, select);
if (null != sqlSegment) {
plainSelect.setWhere(sqlSegment);
}
log.info("---------processSelect----------------");
}
}
6.属性填充
框架默认提供MetaObjectHandler,对inser,update操作的创建人,创建时间,更新人,更新时间进行自动填充。
如果项目自定义了自己的MetaObjectHandler,可以通过@Primary注解选当前项目自定义的MetaObjectHandler