mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-10 08:57:19 +08:00
refactor(data): mybatis-plus => mp,mybatis-flex => mf
This commit is contained in:
47
continew-starter-data/continew-starter-data-mp/pom.xml
Normal file
47
continew-starter-data/continew-starter-data-mp/pom.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?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>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-data</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-starter-data-mp</artifactId>
|
||||
<description>ContiNew Starter 数据访问模块 - MyBatis Plus</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- MyBatis Plus(MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,简化开发、提高效率) -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Dynamic Datasource(基于 Spring Boot 的快速集成多数据源的启动器) -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- P6Spy(SQL 性能分析组件) -->
|
||||
<dependency>
|
||||
<groupId>p6spy</groupId>
|
||||
<artifactId>p6spy</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据访问模块 - 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-data-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- CosId(通用、灵活、高性能的分布式 ID 生成器) -->
|
||||
<dependency>
|
||||
<groupId>me.ahoo.cosid</groupId>
|
||||
<artifactId>cosid-spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 是否启用数据权限注解
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Documented
|
||||
@ConditionalOnProperty(prefix = "mybatis-plus.extension.data-permission", name = PropertiesConstants.ENABLED, havingValue = "true")
|
||||
public @interface ConditionalOnEnabledDataPermission {
|
||||
}
|
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.autoconfigure;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import top.continew.starter.data.mp.autoconfigure.idgenerator.MyBatisPlusIdGeneratorProperties;
|
||||
|
||||
/**
|
||||
* MyBatis Plus 扩展配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@ConfigurationProperties("mybatis-plus.extension")
|
||||
public class MyBatisPlusExtensionProperties {
|
||||
|
||||
/**
|
||||
* 是否启用扩展
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* Mapper 接口扫描包(配置时必须使用:mapper-package 键名)
|
||||
* <p>
|
||||
* e.g. com.example.**.mapper
|
||||
* </p>
|
||||
*/
|
||||
private String mapperPackage;
|
||||
|
||||
/**
|
||||
* ID 生成器
|
||||
*/
|
||||
@NestedConfigurationProperty
|
||||
private MyBatisPlusIdGeneratorProperties idGenerator;
|
||||
|
||||
/**
|
||||
* 数据权限插件配置
|
||||
*/
|
||||
private DataPermissionProperties dataPermission;
|
||||
|
||||
/**
|
||||
* 分页插件配置
|
||||
*/
|
||||
private PaginationProperties pagination;
|
||||
|
||||
/**
|
||||
* 启用防全表更新与删除插件
|
||||
*/
|
||||
private boolean blockAttackPluginEnabled = true;
|
||||
|
||||
/**
|
||||
* 数据权限插件配置属性
|
||||
*/
|
||||
public static class DataPermissionProperties {
|
||||
|
||||
/**
|
||||
* 是否启用数据权限插件
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页插件配置属性
|
||||
*/
|
||||
public static class PaginationProperties {
|
||||
|
||||
/**
|
||||
* 是否启用分页插件
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 数据库类型
|
||||
*/
|
||||
private DbType dbType;
|
||||
|
||||
/**
|
||||
* 是否溢出处理
|
||||
*/
|
||||
private boolean overflow = false;
|
||||
|
||||
/**
|
||||
* 单页分页条数限制(默认:-1 表示无限制)
|
||||
*/
|
||||
private Long maxLimit = -1L;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public DbType getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public void setDbType(DbType dbType) {
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public boolean isOverflow() {
|
||||
return overflow;
|
||||
}
|
||||
|
||||
public void setOverflow(boolean overflow) {
|
||||
this.overflow = overflow;
|
||||
}
|
||||
|
||||
public Long getMaxLimit() {
|
||||
return maxLimit;
|
||||
}
|
||||
|
||||
public void setMaxLimit(Long maxLimit) {
|
||||
this.maxLimit = maxLimit;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getMapperPackage() {
|
||||
return mapperPackage;
|
||||
}
|
||||
|
||||
public void setMapperPackage(String mapperPackage) {
|
||||
this.mapperPackage = mapperPackage;
|
||||
}
|
||||
|
||||
public MyBatisPlusIdGeneratorProperties getIdGenerator() {
|
||||
return idGenerator;
|
||||
}
|
||||
|
||||
public void setIdGenerator(MyBatisPlusIdGeneratorProperties idGenerator) {
|
||||
this.idGenerator = idGenerator;
|
||||
}
|
||||
|
||||
public DataPermissionProperties getDataPermission() {
|
||||
return dataPermission;
|
||||
}
|
||||
|
||||
public void setDataPermission(DataPermissionProperties dataPermission) {
|
||||
this.dataPermission = dataPermission;
|
||||
}
|
||||
|
||||
public PaginationProperties getPagination() {
|
||||
return pagination;
|
||||
}
|
||||
|
||||
public void setPagination(PaginationProperties pagination) {
|
||||
this.pagination = pagination;
|
||||
}
|
||||
|
||||
public boolean isBlockAttackPluginEnabled() {
|
||||
return blockAttackPluginEnabled;
|
||||
}
|
||||
|
||||
public void setBlockAttackPluginEnabled(boolean blockAttackPluginEnabled) {
|
||||
this.blockAttackPluginEnabled = blockAttackPluginEnabled;
|
||||
}
|
||||
}
|
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.autoconfigure;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.continew.starter.core.util.GeneralPropertySourceFactory;
|
||||
import top.continew.starter.data.mp.autoconfigure.idgenerator.MyBatisPlusIdGeneratorConfiguration;
|
||||
import top.continew.starter.data.mp.datapermission.DataPermissionFilter;
|
||||
import top.continew.starter.data.mp.datapermission.DataPermissionHandlerImpl;
|
||||
import top.continew.starter.data.mp.handler.MybatisBaseEnumTypeHandler;
|
||||
|
||||
/**
|
||||
* MyBatis Plus 自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@MapperScan("${mybatis-plus.extension.mapper-package}")
|
||||
@EnableTransactionManagement(proxyTargetClass = true)
|
||||
@EnableConfigurationProperties(MyBatisPlusExtensionProperties.class)
|
||||
@ConditionalOnProperty(prefix = "mybatis-plus.extension", name = PropertiesConstants.ENABLED, havingValue = "true")
|
||||
@PropertySource(value = "classpath:default-data-mybatis-plus.yml", factory = GeneralPropertySourceFactory.class)
|
||||
public class MybatisPlusAutoConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MybatisPlusAutoConfiguration.class);
|
||||
|
||||
/**
|
||||
* MyBatis Plus 配置
|
||||
*
|
||||
* @since 2.4.0
|
||||
*/
|
||||
@Bean
|
||||
public MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer() {
|
||||
return properties -> properties.getConfiguration().setDefaultEnumTypeHandler(MybatisBaseEnumTypeHandler.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* MyBatis Plus 插件配置
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor(MyBatisPlusExtensionProperties properties) {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
// 数据权限插件
|
||||
MyBatisPlusExtensionProperties.DataPermissionProperties dataPermissionProperties = properties
|
||||
.getDataPermission();
|
||||
if (null != dataPermissionProperties && dataPermissionProperties.isEnabled()) {
|
||||
interceptor.addInnerInterceptor(new DataPermissionInterceptor(SpringUtil
|
||||
.getBean(DataPermissionHandler.class)));
|
||||
}
|
||||
// 分页插件
|
||||
MyBatisPlusExtensionProperties.PaginationProperties paginationProperties = properties.getPagination();
|
||||
if (null != paginationProperties && paginationProperties.isEnabled()) {
|
||||
interceptor.addInnerInterceptor(this.paginationInnerInterceptor(paginationProperties));
|
||||
}
|
||||
// 防全表更新与删除插件
|
||||
if (properties.isBlockAttackPluginEnabled()) {
|
||||
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID 生成器配置
|
||||
*/
|
||||
@Configuration
|
||||
@Import({MyBatisPlusIdGeneratorConfiguration.Default.class, MyBatisPlusIdGeneratorConfiguration.CosId.class,
|
||||
MyBatisPlusIdGeneratorConfiguration.Custom.class})
|
||||
protected static class MyBatisPlusIdGeneratorAutoConfiguration {}
|
||||
|
||||
/**
|
||||
* 数据权限处理器
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledDataPermission
|
||||
public DataPermissionHandler dataPermissionHandler(DataPermissionFilter dataPermissionFilter) {
|
||||
return new DataPermissionHandlerImpl(dataPermissionFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页插件配置(<a href="https://baomidou.com/pages/97710a/#paginationinnerinterceptor">PaginationInnerInterceptor</a>)
|
||||
*/
|
||||
private PaginationInnerInterceptor paginationInnerInterceptor(MyBatisPlusExtensionProperties.PaginationProperties paginationProperties) {
|
||||
// 对于单一数据库类型来说,都建议配置该值,避免每次分页都去抓取数据库类型
|
||||
PaginationInnerInterceptor paginationInnerInterceptor = null != paginationProperties.getDbType()
|
||||
? new PaginationInnerInterceptor(paginationProperties.getDbType())
|
||||
: new PaginationInnerInterceptor();
|
||||
paginationInnerInterceptor.setOverflow(paginationProperties.isOverflow());
|
||||
paginationInnerInterceptor.setMaxLimit(paginationProperties.getMaxLimit());
|
||||
return paginationInnerInterceptor;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'MyBatis Plus' completed initialization.");
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.autoconfigure.idgenerator;
|
||||
|
||||
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
|
||||
import me.ahoo.cosid.snowflake.SnowflakeId;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
/**
|
||||
* MyBatis Plus ID 生成器 - CosId
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class MyBatisPlusCosIdIdentifierGenerator implements IdentifierGenerator {
|
||||
|
||||
@Qualifier("__share__SnowflakeId")
|
||||
@Lazy
|
||||
@Autowired
|
||||
private SnowflakeId snowflakeId;
|
||||
|
||||
@Override
|
||||
public Number nextId(Object entity) {
|
||||
return snowflakeId.generate();
|
||||
}
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.autoconfigure.idgenerator;
|
||||
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
|
||||
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
|
||||
import me.ahoo.cosid.IdGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
/**
|
||||
* MyBatis ID 生成器配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class MyBatisPlusIdGeneratorConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MyBatisPlusIdGeneratorConfiguration.class);
|
||||
|
||||
private MyBatisPlusIdGeneratorConfiguration() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 ID 生成器-默认(雪花算法,使用网卡信息绑定雪花生成器,防止集群雪花 ID 重复)
|
||||
*/
|
||||
@ConditionalOnMissingBean(IdentifierGenerator.class)
|
||||
@ConditionalOnProperty(name = "mybatis-plus.extension.id-generator.type", havingValue = "default", matchIfMissing = true)
|
||||
public static class Default {
|
||||
static {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'MyBatis Plus-IdGenerator-Default' completed initialization.");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IdentifierGenerator identifierGenerator() {
|
||||
return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 ID 生成器-CosId
|
||||
*/
|
||||
@ConditionalOnMissingBean(IdentifierGenerator.class)
|
||||
@ConditionalOnClass(IdGenerator.class)
|
||||
@ConditionalOnProperty(name = "mybatis-plus.extension.id-generator.type", havingValue = "cosid")
|
||||
public static class CosId {
|
||||
static {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'MyBatis Plus-IdGenerator-CosId' completed initialization.");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IdentifierGenerator identifierGenerator() {
|
||||
return new MyBatisPlusCosIdIdentifierGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 ID 生成器
|
||||
*/
|
||||
@ConditionalOnProperty(name = "mybatis-plus.extension.id-generator.type", havingValue = "custom")
|
||||
public static class Custom {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public IdentifierGenerator identifierGenerator() {
|
||||
if (log.isErrorEnabled()) {
|
||||
log.error("Consider defining a bean of type '{}' in your configuration.", ResolvableType
|
||||
.forClass(IdentifierGenerator.class));
|
||||
}
|
||||
throw new NoSuchBeanDefinitionException(IdentifierGenerator.class);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.autoconfigure.idgenerator;
|
||||
|
||||
import top.continew.starter.data.mp.enums.MyBatisPlusIdGeneratorType;
|
||||
|
||||
/**
|
||||
* MyBatis ID 生成器配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class MyBatisPlusIdGeneratorProperties {
|
||||
|
||||
/**
|
||||
* ID 生成器类型
|
||||
*/
|
||||
private MyBatisPlusIdGeneratorType type = MyBatisPlusIdGeneratorType.DEFAULT;
|
||||
|
||||
public MyBatisPlusIdGeneratorType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(MyBatisPlusIdGeneratorType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.base;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
|
||||
import com.baomidou.mybatisplus.extension.toolkit.Db;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Mapper 基类
|
||||
*
|
||||
* @param <T> 实体类
|
||||
* @author Charles7c
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface BaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> {
|
||||
|
||||
/**
|
||||
* 批量插入记录
|
||||
*
|
||||
* @param entityList 实体列表
|
||||
* @return 是否成功
|
||||
*/
|
||||
default boolean insertBatch(Collection<T> entityList) {
|
||||
return Db.saveBatch(entityList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新记录
|
||||
*
|
||||
* @param entityList 实体列表
|
||||
* @return 是否成功
|
||||
*/
|
||||
default boolean updateBatchById(Collection<T> entityList) {
|
||||
return Db.updateBatchById(entityList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 链式查询
|
||||
*
|
||||
* @return QueryWrapper 的包装类
|
||||
*/
|
||||
default QueryChainWrapper<T> query() {
|
||||
return ChainWrappers.queryChain(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 链式查询(lambda 式)
|
||||
*
|
||||
* @return LambdaQueryWrapper 的包装类
|
||||
*/
|
||||
default LambdaQueryChainWrapper<T> lambdaQuery() {
|
||||
return ChainWrappers.lambdaQueryChain(this, this.currentEntityClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 链式查询(lambda 式)
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @return LambdaQueryWrapper 的包装类
|
||||
*/
|
||||
default LambdaQueryChainWrapper<T> lambdaQuery(T entity) {
|
||||
return ChainWrappers.lambdaQueryChain(this, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 链式更改
|
||||
*
|
||||
* @return UpdateWrapper 的包装类
|
||||
*/
|
||||
default UpdateChainWrapper<T> update() {
|
||||
return ChainWrappers.updateChain(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 链式更改(lambda 式)
|
||||
*
|
||||
* @return LambdaUpdateWrapper 的包装类
|
||||
*/
|
||||
default LambdaUpdateChainWrapper<T> lambdaUpdate() {
|
||||
return ChainWrappers.lambdaUpdateChain(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体类 Class 对象
|
||||
*
|
||||
* @return 实体类 Class 对象
|
||||
*/
|
||||
default Class<T> currentEntityClass() {
|
||||
return (Class<T>)ClassUtil.getTypeArgument(this.getClass(), 0);
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.datapermission;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 数据权限注解
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DataPermission {
|
||||
|
||||
/**
|
||||
* 表别名
|
||||
*/
|
||||
String tableAlias() default "";
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
String id() default "id";
|
||||
|
||||
/**
|
||||
* 部门 ID
|
||||
*/
|
||||
String deptId() default "dept_id";
|
||||
|
||||
/**
|
||||
* 用户 ID
|
||||
*/
|
||||
String userId() default "create_user";
|
||||
|
||||
/**
|
||||
* 角色 ID(角色和部门关联表)
|
||||
*/
|
||||
String roleId() default "role_id";
|
||||
|
||||
/**
|
||||
* 部门表别名
|
||||
*/
|
||||
String deptTableAlias() default "sys_dept";
|
||||
|
||||
/**
|
||||
* 角色和部门关联表别名
|
||||
*/
|
||||
String roleDeptTableAlias() default "sys_role_dept";
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.datapermission;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 当前用户信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class DataPermissionCurrentUser {
|
||||
|
||||
/**
|
||||
* 用户 ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
*/
|
||||
private Set<CurrentUserRole> roles;
|
||||
|
||||
/**
|
||||
* 部门 ID
|
||||
*/
|
||||
private String deptId;
|
||||
|
||||
/**
|
||||
* 当前用户角色信息
|
||||
*/
|
||||
public static class CurrentUserRole {
|
||||
|
||||
/**
|
||||
* 角色 ID
|
||||
*/
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 数据权限
|
||||
*/
|
||||
private DataScope dataScope;
|
||||
|
||||
public CurrentUserRole() {
|
||||
}
|
||||
|
||||
public CurrentUserRole(String roleId, DataScope dataScope) {
|
||||
this.roleId = roleId;
|
||||
this.dataScope = dataScope;
|
||||
}
|
||||
|
||||
public String getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(String roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
public DataScope getDataScope() {
|
||||
return dataScope;
|
||||
}
|
||||
|
||||
public void setDataScope(DataScope dataScope) {
|
||||
this.dataScope = dataScope;
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Set<CurrentUserRole> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(Set<CurrentUserRole> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public String getDeptId() {
|
||||
return deptId;
|
||||
}
|
||||
|
||||
public void setDeptId(String deptId) {
|
||||
this.deptId = deptId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.datapermission;
|
||||
|
||||
/**
|
||||
* 数据权限过滤器接口
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public interface DataPermissionFilter {
|
||||
|
||||
/**
|
||||
* 是否过滤
|
||||
*
|
||||
* @return true:过滤;false:不过滤
|
||||
*/
|
||||
boolean isFilter();
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
*
|
||||
* @return 当前用户信息
|
||||
*/
|
||||
DataPermissionCurrentUser getCurrentUser();
|
||||
}
|
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.datapermission;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
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.EqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 数据权限处理器实现类
|
||||
*
|
||||
* @author <a href="https://gitee.com/baomidou/mybatis-plus/issues/I37I90">DataPermissionInterceptor 如何使用?</a>
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class DataPermissionHandlerImpl implements DataPermissionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DataPermissionHandlerImpl.class);
|
||||
private final DataPermissionFilter dataPermissionFilter;
|
||||
|
||||
public DataPermissionHandlerImpl(DataPermissionFilter dataPermissionFilter) {
|
||||
this.dataPermissionFilter = dataPermissionFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getSqlSegment(Expression where, String mappedStatementId) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId
|
||||
.lastIndexOf(StringConstants.DOT)));
|
||||
String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(StringConstants.DOT) + 1);
|
||||
Method[] methodArr = clazz.getMethods();
|
||||
for (Method method : methodArr) {
|
||||
DataPermission dataPermission = method.getAnnotation(DataPermission.class);
|
||||
String name = method.getName();
|
||||
if (null == dataPermission || !CharSequenceUtil.equalsAny(methodName, name, name + "_COUNT")) {
|
||||
continue;
|
||||
}
|
||||
if (dataPermissionFilter.isFilter()) {
|
||||
return buildDataScopeFilter(dataPermission, where);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("Data permission handler build data scope filter occurred an error: {}.", e.getMessage(), e);
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建数据范围过滤条件
|
||||
*
|
||||
* @param dataPermission 数据权限
|
||||
* @param where 当前查询条件
|
||||
* @return 构建后查询条件
|
||||
*/
|
||||
private Expression buildDataScopeFilter(DataPermission dataPermission, Expression where) {
|
||||
Expression expression = null;
|
||||
DataPermissionCurrentUser currentUser = dataPermissionFilter.getCurrentUser();
|
||||
Set<DataPermissionCurrentUser.CurrentUserRole> roles = currentUser.getRoles();
|
||||
for (DataPermissionCurrentUser.CurrentUserRole role : roles) {
|
||||
DataScope dataScope = role.getDataScope();
|
||||
if (DataScope.ALL.equals(dataScope)) {
|
||||
return where;
|
||||
}
|
||||
switch (dataScope) {
|
||||
case DEPT_AND_CHILD -> expression = this
|
||||
.buildDeptAndChildExpression(dataPermission, currentUser, expression);
|
||||
case DEPT -> expression = this.buildDeptExpression(dataPermission, currentUser, expression);
|
||||
case SELF -> expression = this.buildSelfExpression(dataPermission, currentUser, expression);
|
||||
case CUSTOM -> expression = this.buildCustomExpression(dataPermission, role, expression);
|
||||
default -> throw new IllegalArgumentException("暂不支持 [%s] 数据权限".formatted(dataScope));
|
||||
}
|
||||
}
|
||||
return null != where ? new AndExpression(where, new Parenthesis(expression)) : expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建本部门及以下数据权限表达式
|
||||
*
|
||||
* <p>
|
||||
* 处理完后的 SQL 示例:<br /> select t1.* from table as t1 where t1.dept_id in (select id from sys_dept where id =
|
||||
* xxx or find_in_set(xxx, ancestors));
|
||||
* </p>
|
||||
*
|
||||
* @param dataPermission 数据权限
|
||||
* @param currentUser 当前用户
|
||||
* @param expression 处理前的表达式
|
||||
* @return 处理完后的表达式
|
||||
*/
|
||||
private Expression buildDeptAndChildExpression(DataPermission dataPermission,
|
||||
DataPermissionCurrentUser currentUser,
|
||||
Expression expression) {
|
||||
ParenthesedSelect subSelect = new ParenthesedSelect();
|
||||
PlainSelect select = new PlainSelect();
|
||||
select.setSelectItems(Collections.singletonList(new SelectItem<>(new Column(dataPermission.id()))));
|
||||
select.setFromItem(new Table(dataPermission.deptTableAlias()));
|
||||
EqualsTo equalsTo = new EqualsTo();
|
||||
equalsTo.setLeftExpression(new Column(dataPermission.id()));
|
||||
equalsTo.setRightExpression(new LongValue(currentUser.getDeptId()));
|
||||
Function function = new Function();
|
||||
function.setName("find_in_set");
|
||||
function.setParameters(new ExpressionList(new LongValue(currentUser.getDeptId()), new Column("ancestors")));
|
||||
select.setWhere(new OrExpression(equalsTo, function));
|
||||
subSelect.setSelect(select);
|
||||
// 构建父查询
|
||||
InExpression inExpression = new InExpression();
|
||||
inExpression.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
|
||||
inExpression.setRightExpression(subSelect);
|
||||
return null != expression ? new OrExpression(expression, inExpression) : inExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建本部门数据权限表达式
|
||||
*
|
||||
* <p>
|
||||
* 处理完后的 SQL 示例:<br /> select t1.* from table as t1 where t1.dept_id = xxx;
|
||||
* </p>
|
||||
*
|
||||
* @param dataPermission 数据权限
|
||||
* @param currentUser 当前用户
|
||||
* @param expression 处理前的表达式
|
||||
* @return 处理完后的表达式
|
||||
*/
|
||||
private Expression buildDeptExpression(DataPermission dataPermission,
|
||||
DataPermissionCurrentUser currentUser,
|
||||
Expression expression) {
|
||||
EqualsTo equalsTo = new EqualsTo();
|
||||
equalsTo.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
|
||||
equalsTo.setRightExpression(new LongValue(currentUser.getDeptId()));
|
||||
return null != expression ? new OrExpression(expression, equalsTo) : equalsTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建仅本人数据权限表达式
|
||||
*
|
||||
* <p>
|
||||
* 处理完后的 SQL 示例:<br /> select t1.* from table as t1 where t1.create_user = xxx;
|
||||
* </p>
|
||||
*
|
||||
* @param dataPermission 数据权限
|
||||
* @param currentUser 当前用户
|
||||
* @param expression 处理前的表达式
|
||||
* @return 处理完后的表达式
|
||||
*/
|
||||
private Expression buildSelfExpression(DataPermission dataPermission,
|
||||
DataPermissionCurrentUser currentUser,
|
||||
Expression expression) {
|
||||
EqualsTo equalsTo = new EqualsTo();
|
||||
equalsTo.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.userId()));
|
||||
equalsTo.setRightExpression(new LongValue(currentUser.getUserId()));
|
||||
return null != expression ? new OrExpression(expression, equalsTo) : equalsTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建自定义数据权限表达式
|
||||
*
|
||||
* <p>
|
||||
* 处理完后的 SQL 示例:<br /> select t1.* from table as t1 where t1.dept_id in (select dept_id from sys_role_dept
|
||||
* where role_id = xxx);
|
||||
* </p>
|
||||
*
|
||||
* @param dataPermission 数据权限
|
||||
* @param role 当前用户角色
|
||||
* @param expression 处理前的表达式
|
||||
* @return 处理完后的表达式
|
||||
*/
|
||||
private Expression buildCustomExpression(DataPermission dataPermission,
|
||||
DataPermissionCurrentUser.CurrentUserRole role,
|
||||
Expression expression) {
|
||||
ParenthesedSelect subSelect = new ParenthesedSelect();
|
||||
PlainSelect select = new PlainSelect();
|
||||
select.setSelectItems(Collections.singletonList(new SelectItem<>(new Column(dataPermission.deptId()))));
|
||||
select.setFromItem(new Table(dataPermission.roleDeptTableAlias()));
|
||||
EqualsTo equalsTo = new EqualsTo();
|
||||
equalsTo.setLeftExpression(new Column(dataPermission.roleId()));
|
||||
equalsTo.setRightExpression(new LongValue(role.getRoleId()));
|
||||
select.setWhere(equalsTo);
|
||||
subSelect.setSelect(select);
|
||||
// 构建父查询
|
||||
InExpression inExpression = new InExpression();
|
||||
inExpression.setLeftExpression(this.buildColumn(dataPermission.tableAlias(), dataPermission.deptId()));
|
||||
inExpression.setRightExpression(subSelect);
|
||||
return null != expression ? new OrExpression(expression, inExpression) : inExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 Column
|
||||
*
|
||||
* @param tableAlias 表别名
|
||||
* @param columnName 字段名称
|
||||
* @return 带表别名字段
|
||||
*/
|
||||
private Column buildColumn(String tableAlias, String columnName) {
|
||||
if (StringUtils.isNotEmpty(tableAlias)) {
|
||||
return new Column("%s.%s".formatted(tableAlias, columnName));
|
||||
}
|
||||
return new Column(columnName);
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.datapermission;
|
||||
|
||||
/**
|
||||
* 数据权限枚举
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public enum DataScope {
|
||||
|
||||
/**
|
||||
* 全部数据权限
|
||||
*/
|
||||
ALL,
|
||||
|
||||
/**
|
||||
* 本部门及以下数据权限
|
||||
*/
|
||||
DEPT_AND_CHILD,
|
||||
|
||||
/**
|
||||
* 本部门数据权限
|
||||
*/
|
||||
DEPT,
|
||||
|
||||
/**
|
||||
* 仅本人数据权限
|
||||
*/
|
||||
SELF,
|
||||
|
||||
/**
|
||||
* 自定义数据权限
|
||||
*/
|
||||
CUSTOM,
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.enums;
|
||||
|
||||
/**
|
||||
* MyBatis ID 生成器类型枚举
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public enum MyBatisPlusIdGeneratorType {
|
||||
|
||||
/**
|
||||
* 默认
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* CosId
|
||||
*/
|
||||
COSID,
|
||||
|
||||
/**
|
||||
* 自定义
|
||||
*/
|
||||
CUSTOM
|
||||
}
|
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.handler;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import com.baomidou.mybatisplus.annotation.IEnum;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import org.apache.ibatis.reflection.DefaultReflectorFactory;
|
||||
import org.apache.ibatis.reflection.MetaClass;
|
||||
import org.apache.ibatis.reflection.ReflectorFactory;
|
||||
import org.apache.ibatis.reflection.invoker.Invoker;
|
||||
import org.apache.ibatis.type.BaseTypeHandler;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
import top.continew.starter.core.enums.BaseEnum;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 自定义枚举属性转换器
|
||||
*
|
||||
* @author hubin
|
||||
* @author Charles7c
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public class MybatisBaseEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
|
||||
|
||||
private static final Map<String, String> TABLE_METHOD_OF_ENUM_TYPES = new ConcurrentHashMap<>();
|
||||
private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();
|
||||
private final Class<E> enumClassType;
|
||||
private final Class<?> propertyType;
|
||||
private final Invoker getInvoker;
|
||||
|
||||
public MybatisBaseEnumTypeHandler(Class<E> enumClassType) {
|
||||
if (enumClassType == null) {
|
||||
throw new IllegalArgumentException("Type argument cannot be null");
|
||||
}
|
||||
this.enumClassType = enumClassType;
|
||||
MetaClass metaClass = MetaClass.forClass(enumClassType, REFLECTOR_FACTORY);
|
||||
String name = "value";
|
||||
if (!BaseEnum.class.isAssignableFrom(enumClassType) && !IEnum.class.isAssignableFrom(enumClassType)) {
|
||||
name = findEnumValueFieldName(this.enumClassType).orElseThrow(() -> new IllegalArgumentException(String
|
||||
.format("Could not find @EnumValue in Class: %s.", this.enumClassType.getName())));
|
||||
}
|
||||
this.propertyType = ReflectionKit.resolvePrimitiveIfNecessary(metaClass.getGetterType(name));
|
||||
this.getInvoker = metaClass.getGetInvoker(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找标记标记EnumValue字段
|
||||
*
|
||||
* @param clazz class
|
||||
* @return EnumValue字段
|
||||
*/
|
||||
public static Optional<String> findEnumValueFieldName(Class<?> clazz) {
|
||||
if (clazz != null && clazz.isEnum()) {
|
||||
String className = clazz.getName();
|
||||
return Optional.ofNullable(CollectionUtils.computeIfAbsent(TABLE_METHOD_OF_ENUM_TYPES, className, key -> {
|
||||
Optional<Field> fieldOptional = findEnumValueAnnotationField(clazz);
|
||||
return fieldOptional.map(Field::getName).orElse(null);
|
||||
}));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static Optional<Field> findEnumValueAnnotationField(Class<?> clazz) {
|
||||
return Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(field -> field.isAnnotationPresent(EnumValue.class))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为MP枚举处理
|
||||
*
|
||||
* @param clazz class
|
||||
* @return 是否为MP枚举处理
|
||||
*/
|
||||
public static boolean isMpEnums(Class<?> clazz) {
|
||||
return clazz != null && clazz.isEnum() && (BaseEnum.class.isAssignableFrom(clazz) || IEnum.class
|
||||
.isAssignableFrom(clazz) || findEnumValueFieldName(clazz).isPresent());
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
|
||||
if (jdbcType == null) {
|
||||
ps.setObject(i, this.getValue(parameter));
|
||||
} else {
|
||||
// see r3589
|
||||
ps.setObject(i, this.getValue(parameter), jdbcType.TYPE_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
||||
Object value = rs.getObject(columnName, this.propertyType);
|
||||
if (null == value || rs.wasNull()) {
|
||||
return null;
|
||||
}
|
||||
return this.valueOf(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
||||
Object value = rs.getObject(columnIndex, this.propertyType);
|
||||
if (null == value || rs.wasNull()) {
|
||||
return null;
|
||||
}
|
||||
return this.valueOf(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
||||
Object value = cs.getObject(columnIndex, this.propertyType);
|
||||
if (null == value || cs.wasNull()) {
|
||||
return null;
|
||||
}
|
||||
return this.valueOf(value);
|
||||
}
|
||||
|
||||
private E valueOf(Object value) {
|
||||
E[] es = this.enumClassType.getEnumConstants();
|
||||
return Arrays.stream(es).filter(e -> equalsValue(value, getValue(e))).findAny().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 值比较
|
||||
*
|
||||
* @param sourceValue 数据库字段值
|
||||
* @param targetValue 当前枚举属性值
|
||||
* @return 是否匹配
|
||||
*/
|
||||
private boolean equalsValue(Object sourceValue, Object targetValue) {
|
||||
String sValue = StringUtils.toStringTrim(sourceValue);
|
||||
String tValue = StringUtils.toStringTrim(targetValue);
|
||||
if (sourceValue instanceof Number && targetValue instanceof Number && new BigDecimal(sValue)
|
||||
.compareTo(new BigDecimal(tValue)) == 0) {
|
||||
return true;
|
||||
}
|
||||
return Objects.equals(sValue, tValue);
|
||||
}
|
||||
|
||||
private Object getValue(Object object) {
|
||||
try {
|
||||
return this.getInvoker.invoke(object, new Object[0]);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw ExceptionUtils.mpe(e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.service;
|
||||
|
||||
/**
|
||||
* 通用业务接口
|
||||
*
|
||||
* @param <T> 实体类型
|
||||
* @author Charles7c
|
||||
* @since 1.2.0
|
||||
*/
|
||||
public interface IService<T> extends com.baomidou.mybatisplus.extension.service.IService<T> {
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import top.continew.starter.core.util.ReflectUtils;
|
||||
import top.continew.starter.core.util.validate.CheckUtils;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
import top.continew.starter.data.mp.service.IService;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用业务实现类
|
||||
*
|
||||
* @param <M> Mapper 接口
|
||||
* @param <T> 实体类型
|
||||
* @author Charles7c
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class ServiceImpl<M extends BaseMapper<T>, T> extends com.baomidou.mybatisplus.extension.service.impl.ServiceImpl<M, T> implements IService<T> {
|
||||
|
||||
private List<Field> entityFields;
|
||||
|
||||
@Override
|
||||
public T getById(Serializable id) {
|
||||
return this.getById(id, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前实体类型字段
|
||||
*
|
||||
* @return 当前实体类型字段列表
|
||||
*/
|
||||
public List<Field> getEntityFields() {
|
||||
if (this.entityFields == null) {
|
||||
this.entityFields = ReflectUtils.getNonStaticFields(this.getEntityClass());
|
||||
}
|
||||
return this.entityFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 ID 查询
|
||||
*
|
||||
* @param id ID
|
||||
* @param isCheckExists 是否检查存在
|
||||
* @return 实体信息
|
||||
*/
|
||||
protected T getById(Serializable id, boolean isCheckExists) {
|
||||
T entity = baseMapper.selectById(id);
|
||||
if (isCheckExists) {
|
||||
CheckUtils.throwIfNotExists(entity, ClassUtil.getClassName(this.getEntityClass(), true), "ID", id);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.data.mp.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import top.continew.starter.core.exception.BadRequestException;
|
||||
import top.continew.starter.core.util.ReflectUtils;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
import top.continew.starter.data.core.annotation.Query;
|
||||
import top.continew.starter.data.core.annotation.QueryIgnore;
|
||||
import top.continew.starter.data.core.enums.QueryType;
|
||||
import top.continew.starter.data.core.util.SqlInjectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* QueryWrapper 助手
|
||||
*
|
||||
* @author Charles7c
|
||||
* @author Jasmine
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class QueryWrapperHelper {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(QueryWrapperHelper.class);
|
||||
|
||||
private QueryWrapperHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 QueryWrapper
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param <Q> 查询条件数据类型
|
||||
* @param <R> 查询数据类型
|
||||
* @return QueryWrapper
|
||||
*/
|
||||
public static <Q, R> QueryWrapper<R> build(Q query) {
|
||||
return build(query, Sort.unsorted());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 QueryWrapper
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param sort 排序条件
|
||||
* @param <Q> 查询条件数据类型
|
||||
* @param <R> 查询数据类型
|
||||
* @return QueryWrapper
|
||||
* @since 2.5.2
|
||||
*/
|
||||
public static <Q, R> QueryWrapper<R> build(Q query, Sort sort) {
|
||||
QueryWrapper<R> queryWrapper = new QueryWrapper<>();
|
||||
// 没有查询条件,直接返回
|
||||
if (null == query) {
|
||||
return queryWrapper;
|
||||
}
|
||||
// 设置排序条件
|
||||
if (sort != null && sort.isSorted()) {
|
||||
for (Sort.Order order : sort) {
|
||||
String field = CharSequenceUtil.toUnderlineCase(order.getProperty());
|
||||
ValidationUtils.throwIf(SqlInjectionUtils.check(field), "排序字段包含非法字符");
|
||||
queryWrapper.orderBy(true, order.isAscending(), field);
|
||||
}
|
||||
}
|
||||
// 获取查询条件中所有的字段
|
||||
List<Field> fieldList = ReflectUtils.getNonStaticFields(query.getClass());
|
||||
return build(query, fieldList, queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 QueryWrapper
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param fields 查询条件字段列表
|
||||
* @param queryWrapper QueryWrapper
|
||||
* @param <Q> 查询条件数据类型
|
||||
* @param <R> 查询数据类型
|
||||
* @return QueryWrapper
|
||||
*/
|
||||
public static <Q, R> QueryWrapper<R> build(Q query, List<Field> fields, QueryWrapper<R> queryWrapper) {
|
||||
// 没有查询条件,直接返回
|
||||
if (null == query) {
|
||||
return queryWrapper;
|
||||
}
|
||||
// 解析并拼接查询条件
|
||||
for (Field field : fields) {
|
||||
List<Consumer<QueryWrapper<R>>> consumers = buildWrapperConsumer(query, field);
|
||||
queryWrapper.and(CollUtil.isNotEmpty(consumers), q -> consumers.forEach(q::or));
|
||||
}
|
||||
return queryWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 QueryWrapper Consumer
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param field 查询条件字段
|
||||
* @param <Q> 查询条件数据类型
|
||||
* @param <R> 查询数据类型
|
||||
* @return QueryWrapper Consumer
|
||||
*/
|
||||
private static <Q, R> List<Consumer<QueryWrapper<R>>> buildWrapperConsumer(Q query, Field field) {
|
||||
boolean accessible = field.canAccess(query);
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
// 如果字段值为空,直接返回
|
||||
Object fieldValue = field.get(query);
|
||||
if (ObjectUtil.isEmpty(fieldValue)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 设置了 @QueryIgnore 注解,直接忽略
|
||||
QueryIgnore queryIgnoreAnnotation = field.getAnnotation(QueryIgnore.class);
|
||||
if (null != queryIgnoreAnnotation && queryIgnoreAnnotation.value()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 建议:数据库表列建议采用下划线连接法命名,程序变量建议采用驼峰法命名
|
||||
String fieldName = field.getName();
|
||||
// 没有 @Query 注解,默认等值查询
|
||||
Query queryAnnotation = field.getAnnotation(Query.class);
|
||||
if (null == queryAnnotation) {
|
||||
return Collections.singletonList(q -> q.eq(CharSequenceUtil.toUnderlineCase(fieldName), fieldValue));
|
||||
}
|
||||
// 解析单列查询
|
||||
QueryType queryType = queryAnnotation.type();
|
||||
String[] columns = queryAnnotation.columns();
|
||||
final int columnLength = ArrayUtil.length(columns);
|
||||
List<Consumer<QueryWrapper<R>>> consumers = new ArrayList<>(columnLength);
|
||||
if (columnLength <= 1) {
|
||||
String columnName = columnLength == 1 ? columns[0] : CharSequenceUtil.toUnderlineCase(fieldName);
|
||||
parse(queryType, columnName, fieldValue, consumers);
|
||||
return consumers;
|
||||
}
|
||||
// 解析多列查询
|
||||
for (String column : columns) {
|
||||
parse(queryType, column, fieldValue, consumers);
|
||||
}
|
||||
return consumers;
|
||||
} catch (BadRequestException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("Build query wrapper occurred an error: {}. Query: {}, Field: {}.", e
|
||||
.getMessage(), query, field, e);
|
||||
} finally {
|
||||
field.setAccessible(accessible);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析查询条件
|
||||
*
|
||||
* @param queryType 查询类型
|
||||
* @param columnName 列名
|
||||
* @param fieldValue 字段值
|
||||
* @param <R> 查询数据类型
|
||||
*/
|
||||
private static <R> void parse(QueryType queryType,
|
||||
String columnName,
|
||||
Object fieldValue,
|
||||
List<Consumer<QueryWrapper<R>>> consumers) {
|
||||
switch (queryType) {
|
||||
case EQ -> consumers.add(q -> q.eq(columnName, fieldValue));
|
||||
case NE -> consumers.add(q -> q.ne(columnName, fieldValue));
|
||||
case GT -> consumers.add(q -> q.gt(columnName, fieldValue));
|
||||
case GE -> consumers.add(q -> q.ge(columnName, fieldValue));
|
||||
case LT -> consumers.add(q -> q.lt(columnName, fieldValue));
|
||||
case LE -> consumers.add(q -> q.le(columnName, fieldValue));
|
||||
case BETWEEN -> {
|
||||
List<Object> between = new ArrayList<>((List<Object>)fieldValue);
|
||||
ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", columnName);
|
||||
consumers.add(q -> q.between(columnName, between.get(0), between.get(1)));
|
||||
}
|
||||
case LIKE -> consumers.add(q -> q.like(columnName, fieldValue));
|
||||
case LIKE_LEFT -> consumers.add(q -> q.likeLeft(columnName, fieldValue));
|
||||
case LIKE_RIGHT -> consumers.add(q -> q.likeRight(columnName, fieldValue));
|
||||
case IN -> {
|
||||
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", columnName);
|
||||
consumers.add(q -> q.in(columnName, (Collection<Object>)fieldValue));
|
||||
}
|
||||
case NOT_IN -> {
|
||||
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", columnName);
|
||||
consumers.add(q -> q.notIn(columnName, (Collection<Object>)fieldValue));
|
||||
}
|
||||
case IS_NULL -> consumers.add(q -> q.isNull(columnName));
|
||||
case IS_NOT_NULL -> consumers.add(q -> q.isNotNull(columnName));
|
||||
default -> throw new IllegalArgumentException("暂不支持 [%s] 查询类型".formatted(queryType));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
top.continew.starter.data.mp.autoconfigure.MybatisPlusAutoConfiguration
|
@@ -0,0 +1,17 @@
|
||||
--- ### MyBatis Plus 配置(https://baomidou.com/pages/56bac0/#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE)
|
||||
mybatis-plus:
|
||||
# 启动时是否检查 MyBatis XML 文件的存在(默认:false 不检查)
|
||||
check-config-location: true
|
||||
## MyBatis 原生支持配置
|
||||
configuration:
|
||||
# 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名)到经典 Java 属性名 aColumn(驼峰命名)的类似映射
|
||||
# 此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将用于生成最终的 SQL 的 select body,如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名
|
||||
map-underscore-to-camel-case: true
|
||||
# MyBatis 自动映射时未知列或未知属性处理策略,通过该配置可指定 MyBatis 在自动映射过程中遇到未知列或者未知属性时如何处理
|
||||
# NONE:不做任何处理 (默认值);WARNING:以日志的形式打印相关警告信息;FAILING:当作映射失败处理,并抛出异常和详细信息
|
||||
auto-mapping-unknown-column-behavior: NONE
|
||||
# 日志配置
|
||||
# 默认:org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
# 更详细(会有性能损耗):org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
# 关闭(可单纯使用 p6spy 分析):org.apache.ibatis.logging.nologging.NoLoggingImpl
|
||||
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
|
@@ -0,0 +1,30 @@
|
||||
############################################################################
|
||||
# P6Spy 配置(SQL 性能分析组件) #
|
||||
############################################################################
|
||||
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
|
||||
# 自定义日志打印
|
||||
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
|
||||
#日志输出到控制台
|
||||
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
|
||||
# 使用日志系统记录 SQL
|
||||
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
|
||||
# 设置 P6Spy Driver 代理
|
||||
deregisterdrivers=true
|
||||
# 取消 JDBC URL 前缀
|
||||
useprefix=true
|
||||
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
|
||||
excludecategories=info,debug,result,commit,resultset
|
||||
# 日期格式
|
||||
dateformat=yyyy-MM-dd HH:mm:ss
|
||||
# SQL语句打印时间格式
|
||||
databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
|
||||
# 实际驱动可多个
|
||||
#driverlist=org.h2.Driver
|
||||
# 是否启用慢 SQL 记录
|
||||
outagedetection=true
|
||||
# 慢 SQL 记录标准 2 秒
|
||||
outagedetectioninterval=2
|
||||
# 是否过滤 Log
|
||||
filter=true
|
||||
# 过滤 Log 时所排除的 SQL 关键字,以逗号分隔
|
||||
exclude=SELECT 1
|
Reference in New Issue
Block a user