功能:在保险、规则、交易、积分和短信模块中实现初始功能和基础组件。

This commit is contained in:
abcv7
2026-03-03 04:04:22 +08:00
parent e050eb3317
commit e156d625bf
1999 changed files with 146080 additions and 63 deletions
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>sfbx-framework</artifactId>
<groupId>com.itheima.sfbx</groupId>
<version>2.0-SNAPSHOT</version>
</parent>
<!--基础模块-mybatis-plus支持-->
<artifactId>framework-mybatis-plus</artifactId>
<name>framework-mybatis-plus</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<dependencies>
<dependency>
<groupId>com.itheima.sfbx</groupId>
<artifactId>framework-commons</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,62 @@
package com.itheima.sfbx.framework.mybatisplus.basic;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @Description:实体基础类
*/
@Data
@NoArgsConstructor
public class BasePojo implements Serializable {
//主键
@JsonFormat(shape = JsonFormat.Shape.STRING)
public Long id;
//创建时间:INSERT代表只在插入时填充
@TableField(fill = FieldFill.INSERT)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")//set
public LocalDateTime createTime;
//修改时间:INSERT_UPDATE 首次插入、其次更新时填充(或修改)
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")//set
public LocalDateTime updateTime;
//创建人IdINSERT_UPDATE 首次插入、其次更新时填充(或修改)
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createBy;
//修改人Id:INSERT_UPDATE 首次插入、其次更新时填充(或修改)
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long updateBy;
//是否有效
@TableField(fill = FieldFill.INSERT)
public String dataState;
public BasePojo(Long id, String dataState) {
this.id = id;
this.dataState = dataState;
}
}
@@ -0,0 +1,228 @@
package com.itheima.sfbx.framework.mybatisplus.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.google.common.collect.Lists;
import com.itheima.sfbx.framework.commons.utils.EmptyUtil;
import com.itheima.sfbx.framework.commons.utils.SubjectContent;
import com.itheima.sfbx.framework.mybatisplus.constant.MybatisPlusConstant;
import com.itheima.sfbx.framework.mybatisplus.handler.AutoMetaObjectHandler;
import com.itheima.sfbx.framework.mybatisplus.handler.DeptNoLineHandler;
import com.itheima.sfbx.framework.mybatisplus.handler.PersonLineHandler;
import com.itheima.sfbx.framework.mybatisplus.interceptor.DeptNoLineInnerInterceptor;
import com.itheima.sfbx.framework.mybatisplus.interceptor.PersonLineInnerInterceptor;
import com.itheima.sfbx.framework.mybatisplus.properties.DataSecurityProperties;
import com.itheima.sfbx.framework.mybatisplus.properties.TenantProperties;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Description:配置文件
*/
@Slf4j
//申明此类为配置类
@Configuration
//读取配置
@EnableConfigurationProperties({MybatisPlusProperties.class, TenantProperties.class,DataSecurityProperties.class})
public class MyBatisPlusConfig {
@Autowired
MybatisPlusProperties mybatisPlusProperties;
@Autowired
TenantProperties tenantProperties;
@Autowired
DataSecurityProperties dataSecurityProperties;
/**
* @Description mybatis提供的主键生成策略【制定雪花】
*/
@Bean
public IdentifierGenerator identifierGenerator() {
return new DefaultIdentifierGenerator();
}
/**
* 自动填充
*/
@Bean
@ConditionalOnMissingBean
public AutoMetaObjectHandler myMetaObjectHandler() {
return new AutoMetaObjectHandler();
}
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 如果用了分页插件注意
// 先 add TenantLineInnerInterceptor
// 再 add PaginationInnerInterceptor
// 用了分页插件必须设置 MybatisConfiguration#useDeprecatedExecutor = false
//多租户租插件
interceptor.addInnerInterceptor(companyNoInterceptor());
//数据权限-部门插件
interceptor.addInnerInterceptor(deptNoLineInnerInterceptor());
//数据权限-本人插件
interceptor.addInnerInterceptor(personLineInnerInterceptor());
//分页的插件
interceptor.addInnerInterceptor(paginationInnerInterceptor());
return interceptor;
}
@Bean
public TenantLineInnerInterceptor companyNoInterceptor() {
return new TenantLineInnerInterceptor(new TenantLineHandler() {
@Override
public Expression getTenantId() {
//从当前的SubjectContent上下文中获取用户信息CompanyNo
String companyNo = SubjectContent.getCompanyNo();
return companyNo==null ? null : new StringValue(companyNo);
}
@Override
public String getTenantIdColumn() {
return MybatisPlusConstant.COMPANY_NO;
}
@Override
public boolean ignoreTable(String tableName) {
//如果当前为默认管理平台则忽略表
// String companyNo = SubjectContent.getCompanyNo();
// if (tenantProperties.getDefaultCompanyNo().equals(companyNo)){
// log.info("默认企业查询,忽略表:{}", tableName);
// return true;
// }
//如果tableName出现在忽略配置中则不添加企业查询条件
List<String> tableNameList = tenantProperties.getIgnoreCompanyTables();
if (!EmptyUtil.isNullOrEmpty(tableNameList)&&tableNameList.contains(tableName)) {
log.info("企业隐式传参为空,忽略表:{}", tableName);
return true;
}
//如果查询字段值为空则不添加企业查询条件
Expression tenantId = this.getTenantId();
if (EmptyUtil.isNullOrEmpty(tenantId)) {
log.info("企业隐式传参为空,忽略表:{}", tableName);
return true;
}
return false;
}
});
}
@Bean
public PersonLineInnerInterceptor personLineInnerInterceptor() {
return new PersonLineInnerInterceptor(new PersonLineHandler() {
@Override
public Expression getCreateBy() {
if (EmptyUtil.isNullOrEmpty(SubjectContent.getUserVO())){
return null;
}
if (EmptyUtil.isNullOrEmpty(SubjectContent.getUserVO().getDataSecurityVO())){
return null;
}
Boolean youselfData = SubjectContent.getUserVO().getDataSecurityVO().getYouselfData();
Long userId = SubjectContent.getUserVO().getId();
return youselfData ? new StringValue(String.valueOf(userId)) : null ;
}
@Override
public String getCreateByColumn() {
return PersonLineHandler.super.getCreateByColumn();
}
@Override
public boolean ignoreTable(String tableName) {
//如果未指定创建人
Expression expression = this.getCreateBy();
if (EmptyUtil.isNullOrEmpty(expression)){
log.info("数据权限-本人隐式传参为空,忽略表:{}", tableName);
return true;
}
//如果tableName出现在忽略配置中则不添加数据权限
List<String> tableNameList = dataSecurityProperties.getIgnoreDataSecurityTables();
if (!EmptyUtil.isNullOrEmpty(tableNameList)&&tableNameList.contains(tableName)) {
log.info("忽略表:{}", tableName);
return true;
}
return false;
}
});
}
@Bean
public DeptNoLineInnerInterceptor deptNoLineInnerInterceptor() {
return new DeptNoLineInnerInterceptor(new DeptNoLineHandler() {
@Override
public ExpressionList getDeptNoList() {
if (EmptyUtil.isNullOrEmpty(SubjectContent.getUserVO())){
return null;
}
if (EmptyUtil.isNullOrEmpty(SubjectContent.getUserVO().getDataSecurityVO())){
return null;
}
List<String> deptNos = SubjectContent.getUserVO().getDataSecurityVO().getDeptNos();
return EmptyUtil.isNullOrEmpty(deptNos)?null:new ExpressionList(deptNos
.stream().map(StringValue::new).collect(Collectors.toList()));
}
@Override
public String getDeptNoColumn() {
return DeptNoLineHandler.super.getDeptNoColumn();
}
@Override
public boolean ignoreTable(String tableName) {
//如果未指定部门列表
ExpressionList expressionList = this.getDeptNoList();
if (EmptyUtil.isNullOrEmpty(expressionList)){
log.info("数据权限-部门隐式传参为空,忽略表:{}", tableName);
return true;
}
//如果tableName出现在忽略配置中则不添加数据权限
List<String> tableNameList = dataSecurityProperties.getIgnoreDataSecurityTables();
if (!EmptyUtil.isNullOrEmpty(tableNameList)&&tableNameList.contains(tableName)) {
log.info("忽略表:{}", tableName);
return true;
}
return false;
}
});
}
//分页的插件配置
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor() {
return new PaginationInnerInterceptor(DbType.MYSQL);
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
@@ -0,0 +1,19 @@
package com.itheima.sfbx.framework.mybatisplus.constant;
/**
* @Description 静态变量
*/
public class MybatisPlusConstant {
//企业编号
public static final String COMPANY_NO ="company_no";
//创建人
public static final String CREATE_BY ="create_by";
//部门编号
public static final String DATA_DEPT_NO ="data_dept_no";
}
@@ -0,0 +1,190 @@
package com.itheima.sfbx.framework.mybatisplus.generator;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.itheima.sfbx.framework.commons.utils.EmptyUtil;
import java.util.*;
/**
* @Description:代码生成器
*/
public class CodeGenerator {
public static void autoGenerator(){
//用来获取generrator.properties文件的配置信息
final ResourceBundle rb = ResourceBundle.getBundle("generrator");
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String serviceProjectPath =rb.getString("serviceProjectPath");
gc.setOutputDir(serviceProjectPath + "/src/main/java");
gc.setAuthor(rb.getString("author"));
gc.setOpen(false);
gc.setFileOverride(true);
//指定时间处理类型
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true); //实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
//数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl(rb.getString("url"));
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername(rb.getString("userName"));
dsc.setPassword(rb.getString("password"));
mpg.setDataSource(dsc);
//包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(rb.getString("moduleName"));
pc.setParent(rb.getString("parent"));
pc.setController("web");
pc.setService("service");
pc.setServiceImpl("service.impl");
pc.setEntity("pojo");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
//管理需要附件功能的代码生成
List<String> tablesFile = Arrays.asList(rb.getString("tablesFile").split(","));
Map<String, Object> map = new HashMap<>();
map.put("tablesFile",tablesFile);
this.setMap(map);
}
};
String dtoOProjectPath =rb.getString("dtoOProjectPath");
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
if ("true".equals(rb.getString("constant"))){
String constantTemplatePath = rb.getString("constant.ftl.path")+".ftl";
// 自定义constant配置会被优先输出
focList.add(new FileOutConfig(constantTemplatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名
return dtoOProjectPath + "/src/main/java/" +pc.getParent().replace(".","/")+"/constant/"
+ tableInfo.getEntityName() + "CacheConstant" + StringPool.DOT_JAVA;
}
});
}
if ("true".equals(rb.getString("enums"))){
String enumsTemplatePath = rb.getString("enums.ftl.path")+".ftl";
// 自定义enums配置会被优先输出
focList.add(new FileOutConfig(enumsTemplatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名
return dtoOProjectPath + "/src/main/java/" +pc.getParent().replace(".","/")+"/enums/"
+ tableInfo.getEntityName() + "Enum" + StringPool.DOT_JAVA;
}
});
}
if ("true".equals(rb.getString("dto"))){
String dtoTemplatePath = rb.getString("dto.ftl.path")+".ftl";
// 自定义Vo配置会被优先输出
focList.add(new FileOutConfig(dtoTemplatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名
return dtoOProjectPath + "/src/main/java/" +pc.getParent().replace(".","/")+"/dto/"
+ tableInfo.getEntityName() + "VO" + StringPool.DOT_JAVA;
}
});
}
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
if ("true".equals(rb.getString("entity"))){
String entityFtlPath = rb.getString("entity.ftl.path");
if (!EmptyUtil.isNullOrEmpty(entityFtlPath)){
templateConfig.setEntity(entityFtlPath);
}
}else {
templateConfig.setEntity(null);
}
if ("true".equals(rb.getString("mapper"))){
String mapperFtlPath = rb.getString("mapper.ftl.path");
if (!EmptyUtil.isNullOrEmpty(mapperFtlPath)){
templateConfig.setMapper(mapperFtlPath);
}
}else {
templateConfig.setMapper(null);
}
if ("true".equals(rb.getString("service"))){
String serviceFtlPath = rb.getString("service.ftl.path");
if (!EmptyUtil.isNullOrEmpty(serviceFtlPath)){
templateConfig.setService(serviceFtlPath);
}
}else {
templateConfig.setService(null);
}
if ("true".equals(rb.getString("serviceImpl"))){
String serviceImpFtlPath = rb.getString("serviceImpl.ftl.path");
if (!EmptyUtil.isNullOrEmpty(serviceImpFtlPath)){
templateConfig.setServiceImpl(serviceImpFtlPath);
}
}else {
templateConfig.setServiceImpl(null);
}
if ("true".equals(rb.getString("controller"))){
String controllerFtlPath = rb.getString("controller.ftl.path");
if (!EmptyUtil.isNullOrEmpty(controllerFtlPath)){
templateConfig.setController(controllerFtlPath);
}
}else {
templateConfig.setController(null);
}
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setSuperEntityClass(rb.getString("SuperEntityClass"));
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 写于父类中的公共字段
String[] SuperEntityColumns = rb.getString("superEntityColumns").split(",");
strategy.setSuperEntityColumns(SuperEntityColumns);
strategy.setInclude(rb.getString("tableName").split(","));
strategy.setControllerMappingHyphenStyle(true);
String tablePrefix = rb.getString("tablePrefix");
if (tablePrefix!=null){
strategy.setTablePrefix(tablePrefix);
}
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
@@ -0,0 +1,67 @@
package com.itheima.sfbx.framework.mybatisplus.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.itheima.sfbx.framework.commons.constant.basic.SuperConstant;
import com.itheima.sfbx.framework.commons.dto.security.UserVO;
import com.itheima.sfbx.framework.commons.utils.EmptyUtil;
import com.itheima.sfbx.framework.commons.utils.SubjectContent;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* @Description:自动填充
*/
@Slf4j
@Component
public class AutoMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始插入填充.....");
UserVO userVO = SubjectContent.getUserVO();
if (EmptyUtil.isNullOrEmpty(userVO)){
userVO= new UserVO();
}
Object dataState = getFieldValByName("dataState", metaObject);
Object companyNo = getFieldValByName("companyNo", metaObject);
if (metaObject.hasSetter("dataState")&&dataState==null) {
this.setFieldValByName("dataState", SuperConstant.DATA_STATE_0,metaObject);
}
if (metaObject.hasSetter("createTime")) {
this.setFieldValByName("createTime", LocalDateTime.now(),metaObject);
}
if (metaObject.hasSetter("updateTime")) {
this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
}
if (metaObject.hasSetter("createBy")) {
this.setFieldValByName("createBy",userVO.getId(),metaObject);
}
if (metaObject.hasSetter("updateBy")) {
this.setFieldValByName("updateBy",userVO.getId(),metaObject);
}
if (metaObject.hasSetter("dataDeptNo")) {
this.setFieldValByName("dataDeptNo",userVO.getDeptNo(),metaObject);
}
if (metaObject.hasSetter("companyNo")&&companyNo==null) {
this.setFieldValByName("companyNo",userVO.getCompanyNo(),metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始更新填充.....");
UserVO userVO = SubjectContent.getUserVO();
if (EmptyUtil.isNullOrEmpty(userVO)){
userVO= new UserVO();
}
if (metaObject.hasSetter("updateTime")) {
this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
}
if (metaObject.hasSetter("updateBy")) {
this.setFieldValByName("updateBy",userVO.getId(),metaObject);
}
}
}
@@ -0,0 +1,36 @@
package com.itheima.sfbx.framework.mybatisplus.handler;
import com.itheima.sfbx.framework.mybatisplus.constant.MybatisPlusConstant;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
/**
* @ClassName DataSecurityLineHandler.java
* @Description 数据权限处理器( DeptNo 行级 )
*/
public interface DeptNoLineHandler {
/**
* 获取数据权限值表达式
* @return 数据权限值表达式
*/
ExpressionList getDeptNoList();
/**
* 获取数据权限字段名
* 默认字段名叫: data_security_id
* @return 数据权限字段名
*/
default String getDeptNoColumn() {
return MybatisPlusConstant.DATA_DEPT_NO;
}
/**
* 根据表名判断是否忽略拼接数据权限条件
* 默认都要进行解析并拼接数据权限条件
* @param tableName 表名
* @return 是否忽略, true:表示忽略,false:需要解析并拼接数据权限条件
*/
default boolean ignoreTable(String tableName) {
return false;
}
}
@@ -0,0 +1,37 @@
package com.itheima.sfbx.framework.mybatisplus.handler;
import com.itheima.sfbx.framework.mybatisplus.constant.MybatisPlusConstant;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
/**
* @ClassName DataSecurityLineHandler.java
* @Description 数据权限处理器( createBy 行级 )
*/
public interface PersonLineHandler {
/**
* 获取数据权限值表达式
* @return 数据权限值表达式
*/
Expression getCreateBy();
/**
* 获取数据权限字段名
* 默认字段名叫: data_security_id
* @return 数据权限字段名
*/
default String getCreateByColumn() {
return MybatisPlusConstant.CREATE_BY;
}
/**
* 根据表名判断是否忽略拼接数据权限条件
* 默认都要进行解析并拼接数据权限条件
* @param tableName 表名
* @return 是否忽略, true:表示忽略,false:需要解析并拼接数据权限条件
*/
default boolean ignoreTable(String tableName) {
return false;
}
}
@@ -0,0 +1,227 @@
package com.itheima.sfbx.framework.mybatisplus.interceptor;
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper;
import com.itheima.sfbx.framework.mybatisplus.handler.DeptNoLineHandler;
import lombok.*;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.*;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
/**
* @ClassName DeptNoLineInnerInterceptor.java
* @Description 数据权限-部门拦截处理
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@SuppressWarnings({"rawtypes"})
public class DeptNoLineInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {
private DeptNoLineHandler deptNoLineHandler;
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) return;
if (SqlParserHelper.getSqlParserInfo(ms)) return;
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(parserSingle(mpBs.sql(), null));
}
@Override
protected void processSelect(Select select, int index, Object obj) {
processSelectBody(select.getSelectBody());
List<WithItem> withItemsList = select.getWithItemsList();
if (!CollectionUtils.isEmpty(withItemsList)) {
withItemsList.forEach(this::processSelectBody);
}
}
protected void processSelectBody(SelectBody selectBody) {
if (selectBody instanceof PlainSelect) {
processPlainSelect((PlainSelect) selectBody);
} else if (selectBody instanceof WithItem) {
WithItem withItem = (WithItem) selectBody;
if (withItem.getSelectBody() != null) {
processSelectBody(withItem.getSelectBody());
}
} else {
SetOperationList operationList = (SetOperationList) selectBody;
if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {
operationList.getSelects().forEach(this::processSelectBody);
}
}
}
/**
* 追加 SelectItem
*
* @param selectItems SelectItem
*/
protected void appendSelectItem(List<SelectItem> selectItems) {
if (CollectionUtils.isEmpty(selectItems)) return;
if (selectItems.size() == 1) {
SelectItem item = selectItems.get(0);
if (item instanceof AllColumns || item instanceof AllTableColumns) return;
}
selectItems.add(new SelectExpressionItem(new Column(deptNoLineHandler.getDeptNoColumn())));
}
/**
* 处理 PlainSelect
*/
protected void processPlainSelect(PlainSelect plainSelect) {
FromItem fromItem = plainSelect.getFromItem();
if (fromItem instanceof Table) {
Table fromTable = (Table) fromItem;
if (!deptNoLineHandler.ignoreTable(fromTable.getName())) {
//#1186 github
plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable));
}
} else {
processFromItem(fromItem);
}
List<Join> joins = plainSelect.getJoins();
if (joins != null && joins.size() > 0) {
joins.forEach(j -> {
processJoin(j);
processFromItem(j.getRightItem());
});
}
}
/**
* 处理子查询等
*/
protected void processFromItem(FromItem fromItem) {
if (fromItem instanceof SubJoin) {
SubJoin subJoin = (SubJoin) fromItem;
if (subJoin.getJoinList() != null) {
subJoin.getJoinList().forEach(this::processJoin);
}
if (subJoin.getLeft() != null) {
processFromItem(subJoin.getLeft());
}
} else if (fromItem instanceof SubSelect) {
SubSelect subSelect = (SubSelect) fromItem;
if (subSelect.getSelectBody() != null) {
processSelectBody(subSelect.getSelectBody());
}
} else if (fromItem instanceof ValuesList) {
logger.debug("Perform a subquery, if you do not give us feedback");
} else if (fromItem instanceof LateralSubSelect) {
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
if (lateralSubSelect.getSubSelect() != null) {
SubSelect subSelect = lateralSubSelect.getSubSelect();
if (subSelect.getSelectBody() != null) {
processSelectBody(subSelect.getSelectBody());
}
}
}
}
/**
* 处理联接语句
*/
protected void processJoin(Join join) {
if (join.getRightItem() instanceof Table) {
Table fromTable = (Table) join.getRightItem();
if (deptNoLineHandler.ignoreTable(fromTable.getName())) {
// 过滤退出执行
return;
}
join.setOnExpression(builderExpression(join.getOnExpression(), fromTable));
}
}
/**
* 处理条件
*/
protected Expression builderExpression(Expression currentExpression, Table table) {
InExpression inExpression = new InExpression();
inExpression.setLeftExpression(this.getAliasColumn(table));
inExpression.setRightItemsList(deptNoLineHandler.getDeptNoList());
if (currentExpression == null) {
return inExpression;
}
if (currentExpression instanceof BinaryExpression) {
BinaryExpression binaryExpression = (BinaryExpression) currentExpression;
doExpression(binaryExpression.getLeftExpression());
doExpression(binaryExpression.getRightExpression());
} else if (currentExpression instanceof InExpression) {
InExpression inExp = (InExpression) currentExpression;
ItemsList rightItems = inExp.getRightItemsList();
if (rightItems instanceof SubSelect) {
processSelectBody(((SubSelect) rightItems).getSelectBody());
}
}
if (currentExpression instanceof OrExpression) {
return new AndExpression(new Parenthesis(currentExpression), inExpression);
} else {
return new AndExpression(currentExpression, inExpression);
}
}
protected void doExpression(Expression expression) {
if (expression instanceof FromItem) {
processFromItem((FromItem) expression);
} else if (expression instanceof InExpression) {
InExpression inExp = (InExpression) expression;
ItemsList rightItems = inExp.getRightItemsList();
if (rightItems instanceof SubSelect) {
processSelectBody(((SubSelect) rightItems).getSelectBody());
}
}
}
/**
* 数据权限-部门字段别名设置
* <p>tenantId 或 tableAlias.tenantId</p>
*
* @param table 表对象
* @return 字段
*/
protected Column getAliasColumn(Table table) {
StringBuilder column = new StringBuilder();
if (table.getAlias() != null) {
column.append(table.getAlias().getName()).append(StringPool.DOT);
}
column.append(deptNoLineHandler.getDeptNoColumn());
return new Column(column.toString());
}
@Override
public void setProperties(Properties properties) {
PropertyMapper.newInstance(properties)
.whenNotBlack("deptNoLineHandler", ClassUtils::newInstance, this::setDeptNoLineHandler);
}
}
@@ -0,0 +1,226 @@
package com.itheima.sfbx.framework.mybatisplus.interceptor;
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper;
import com.itheima.sfbx.framework.mybatisplus.handler.PersonLineHandler;
import lombok.*;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
/**
* @ClassName PersonLineInnerInterceptor.java
* @Description 数据权限-个人拦截处理
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@SuppressWarnings({"rawtypes"})
public class PersonLineInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {
private PersonLineHandler personLineHandler;
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) return;
if (SqlParserHelper.getSqlParserInfo(ms)) return;
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(parserSingle(mpBs.sql(), null));
}
@Override
protected void processSelect(Select select, int index, Object obj) {
processSelectBody(select.getSelectBody());
List<WithItem> withItemsList = select.getWithItemsList();
if (!CollectionUtils.isEmpty(withItemsList)) {
withItemsList.forEach(this::processSelectBody);
}
}
protected void processSelectBody(SelectBody selectBody) {
if (selectBody instanceof PlainSelect) {
processPlainSelect((PlainSelect) selectBody);
} else if (selectBody instanceof WithItem) {
WithItem withItem = (WithItem) selectBody;
if (withItem.getSelectBody() != null) {
processSelectBody(withItem.getSelectBody());
}
} else {
SetOperationList operationList = (SetOperationList) selectBody;
if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {
operationList.getSelects().forEach(this::processSelectBody);
}
}
}
/**
* 追加 SelectItem
*
* @param selectItems SelectItem
*/
protected void appendSelectItem(List<SelectItem> selectItems) {
if (CollectionUtils.isEmpty(selectItems)) return;
if (selectItems.size() == 1) {
SelectItem item = selectItems.get(0);
if (item instanceof AllColumns || item instanceof AllTableColumns) return;
}
selectItems.add(new SelectExpressionItem(new Column(personLineHandler.getCreateByColumn())));
}
/**
* 处理 PlainSelect
*/
protected void processPlainSelect(PlainSelect plainSelect) {
FromItem fromItem = plainSelect.getFromItem();
if (fromItem instanceof Table) {
Table fromTable = (Table) fromItem;
if (!personLineHandler.ignoreTable(fromTable.getName())) {
//#1186 github
plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable));
}
} else {
processFromItem(fromItem);
}
List<Join> joins = plainSelect.getJoins();
if (joins != null && joins.size() > 0) {
joins.forEach(j -> {
processJoin(j);
processFromItem(j.getRightItem());
});
}
}
/**
* 处理子查询等
*/
protected void processFromItem(FromItem fromItem) {
if (fromItem instanceof SubJoin) {
SubJoin subJoin = (SubJoin) fromItem;
if (subJoin.getJoinList() != null) {
subJoin.getJoinList().forEach(this::processJoin);
}
if (subJoin.getLeft() != null) {
processFromItem(subJoin.getLeft());
}
} else if (fromItem instanceof SubSelect) {
SubSelect subSelect = (SubSelect) fromItem;
if (subSelect.getSelectBody() != null) {
processSelectBody(subSelect.getSelectBody());
}
} else if (fromItem instanceof ValuesList) {
logger.debug("Perform a subquery, if you do not give us feedback");
} else if (fromItem instanceof LateralSubSelect) {
LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
if (lateralSubSelect.getSubSelect() != null) {
SubSelect subSelect = lateralSubSelect.getSubSelect();
if (subSelect.getSelectBody() != null) {
processSelectBody(subSelect.getSelectBody());
}
}
}
}
/**
* 处理联接语句
*/
protected void processJoin(Join join) {
if (join.getRightItem() instanceof Table) {
Table fromTable = (Table) join.getRightItem();
if (personLineHandler.ignoreTable(fromTable.getName())) {
// 过滤退出执行
return;
}
join.setOnExpression(builderExpression(join.getOnExpression(), fromTable));
}
}
/**
* 处理条件
*/
protected Expression builderExpression(Expression currentExpression, Table table) {
EqualsTo equalsTo = new EqualsTo();
equalsTo.setLeftExpression(this.getAliasColumn(table));
equalsTo.setRightExpression(personLineHandler.getCreateBy());
if (currentExpression == null) {
return equalsTo;
}
if (currentExpression instanceof BinaryExpression) {
BinaryExpression binaryExpression = (BinaryExpression) currentExpression;
doExpression(binaryExpression.getLeftExpression());
doExpression(binaryExpression.getRightExpression());
} else if (currentExpression instanceof InExpression) {
InExpression inExp = (InExpression) currentExpression;
ItemsList rightItems = inExp.getRightItemsList();
if (rightItems instanceof SubSelect) {
processSelectBody(((SubSelect) rightItems).getSelectBody());
}
}
if (currentExpression instanceof OrExpression) {
return new AndExpression(new Parenthesis(currentExpression), equalsTo);
} else {
return new AndExpression(currentExpression, equalsTo);
}
}
protected void doExpression(Expression expression) {
if (expression instanceof FromItem) {
processFromItem((FromItem) expression);
} else if (expression instanceof InExpression) {
InExpression inExp = (InExpression) expression;
ItemsList rightItems = inExp.getRightItemsList();
if (rightItems instanceof SubSelect) {
processSelectBody(((SubSelect) rightItems).getSelectBody());
}
}
}
/**
* 租户字段别名设置
* <p>tenantId 或 tableAlias.tenantId</p>
*
* @param table 表对象
* @return 字段
*/
protected Column getAliasColumn(Table table) {
StringBuilder column = new StringBuilder();
if (table.getAlias() != null) {
column.append(table.getAlias().getName()).append(StringPool.DOT);
}
column.append(personLineHandler.getCreateByColumn());
return new Column(column.toString());
}
@Override
public void setProperties(Properties properties) {
PropertyMapper.newInstance(properties)
.whenNotBlack("personLineHandler", ClassUtils::newInstance, this::setPersonLineHandler);
}
}
@@ -0,0 +1,19 @@
package com.itheima.sfbx.framework.mybatisplus.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @ClassName DataSecurityProperties.java
* @Description 数据权限配置
*/
@Data
@ConfigurationProperties(prefix = "mybatis-plus")
public class DataSecurityProperties {
//需要忽略的企业表
private List<String> ignoreDataSecurityTables;
}
@@ -0,0 +1,24 @@
package com.itheima.sfbx.framework.mybatisplus.properties;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @ClassName TenantProperties.java
* @Description MyBaits-plus多租户属性
*/
@Slf4j
@Data
@ConfigurationProperties(prefix = "mybatis-plus")
public class TenantProperties {
//需要忽略的企业表
private List<String> ignoreCompanyTables;
//默认企业编号Id
private String defaultCompanyNo;
}