mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 22:57:19 +08:00 
			
		
		
		
	refactor(data): mybatis-plus => mp,mybatis-flex => mf
This commit is contained in:
		| @@ -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.mf.autoconfigure; | ||||
|  | ||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||||
| import top.continew.starter.core.constant.PropertiesConstants; | ||||
|  | ||||
| import java.lang.annotation.*; | ||||
|  | ||||
| /** | ||||
|  * 是否启用数据权限注解 | ||||
|  * | ||||
|  * @author hellokaton | ||||
|  * @since 2.0.2 | ||||
|  */ | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Target({ElementType.TYPE, ElementType.METHOD}) | ||||
| @Documented | ||||
| @ConditionalOnProperty(prefix = "mybatis-flex.extension.data-permission", name = PropertiesConstants.ENABLED, havingValue = "true") | ||||
| public @interface ConditionalOnEnabledDataPermission { | ||||
| } | ||||
| @@ -0,0 +1,162 @@ | ||||
| /* | ||||
|  * 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.mf.autoconfigure; | ||||
|  | ||||
| import com.mybatisflex.core.dialect.DbType; | ||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
|  | ||||
| /** | ||||
|  * MyBatis Plus 扩展配置属性 | ||||
|  * | ||||
|  * @author Charles7c | ||||
|  * @since 1.0.0 | ||||
|  */ | ||||
| @ConfigurationProperties("mybatis-flex.extension") | ||||
| public class MyBatisFlexExtensionProperties { | ||||
|  | ||||
|     /** | ||||
|      * 是否启用扩展 | ||||
|      */ | ||||
|     private boolean enabled = false; | ||||
|  | ||||
|     /** | ||||
|      * Mapper 接口扫描包(配置时必须使用:mapper-package 键名) | ||||
|      * <p> | ||||
|      * e.g. com.example.**.mapper | ||||
|      * </p> | ||||
|      */ | ||||
|     private String mapperPackage; | ||||
|  | ||||
|     /** | ||||
|      * 数据权限插件配置 | ||||
|      */ | ||||
|     private DataPermissionProperties dataPermission; | ||||
|  | ||||
|     /** | ||||
|      * 分页插件配置 | ||||
|      */ | ||||
|     private PaginationProperties pagination; | ||||
|  | ||||
|     /** | ||||
|      * 数据权限插件配置属性 | ||||
|      */ | ||||
|     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 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; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,61 @@ | ||||
| /* | ||||
|  * 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.mf.autoconfigure; | ||||
|  | ||||
| import com.mybatisflex.core.dialect.DbType; | ||||
| import com.mybatisflex.core.dialect.DialectFactory; | ||||
| import jakarta.annotation.PostConstruct; | ||||
| import jakarta.annotation.Resource; | ||||
| 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.ConditionalOnProperty; | ||||
| import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||||
| 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.mf.datapermission.DataPermissionDialect; | ||||
| import top.continew.starter.data.mf.datapermission.DataPermissionFilter; | ||||
|  | ||||
| /** | ||||
|  * MyBatis Flex 自动配置 | ||||
|  * | ||||
|  * @author hellokaton | ||||
|  * @since 2.0.2 | ||||
|  */ | ||||
| @AutoConfiguration | ||||
| @MapperScan("${mybatis-flex.extension.mapper-package}") | ||||
| @EnableTransactionManagement(proxyTargetClass = true) | ||||
| @EnableConfigurationProperties(MyBatisFlexExtensionProperties.class) | ||||
| @ConditionalOnProperty(prefix = "mybatis-flex.extension", name = PropertiesConstants.ENABLED, havingValue = "true") | ||||
| @PropertySource(value = "classpath:default-data-mybatis-flex.yml", factory = GeneralPropertySourceFactory.class) | ||||
| public class MybatisFlexAutoConfiguration { | ||||
|  | ||||
|     private static final Logger log = LoggerFactory.getLogger(MybatisFlexAutoConfiguration.class); | ||||
|  | ||||
|     @Resource | ||||
|     private DataPermissionFilter dataPermissionFilter; | ||||
|  | ||||
|     @PostConstruct | ||||
|     public void postConstruct() { | ||||
|         log.debug("[ContiNew Starter] - Auto Configuration 'MyBatis Flex' completed initialization."); | ||||
|         DialectFactory.registerDialect(DbType.MYSQL, new DataPermissionDialect(dataPermissionFilter)); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * 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.mf.base; | ||||
|  | ||||
| import cn.hutool.core.util.ClassUtil; | ||||
| import com.mybatisflex.core.query.QueryWrapper; | ||||
| import com.mybatisflex.core.row.Db; | ||||
|  | ||||
| import java.util.Collection; | ||||
|  | ||||
| /** | ||||
|  * Mapper 基类 | ||||
|  * | ||||
|  * @param <T> 实体类 | ||||
|  * @author hellokaton | ||||
|  * @since 1.0.0 | ||||
|  */ | ||||
| public interface BaseMapper<T> extends com.mybatisflex.core.BaseMapper<T> { | ||||
|  | ||||
|     /** | ||||
|      * 批量更新记录 | ||||
|      * | ||||
|      * @param entityList 实体列表 | ||||
|      * @return 是否成功 | ||||
|      */ | ||||
|     default boolean updateBatchById(Collection<T> entityList) { | ||||
|         return Db.updateEntitiesBatch(entityList) > 0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 链式查询 | ||||
|      * | ||||
|      * @return QueryWrapper 的包装类 | ||||
|      */ | ||||
|     default QueryWrapper query() { | ||||
|         return QueryWrapper.create(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 链式查询 | ||||
|      * | ||||
|      * @return QueryWrapper 的包装类 | ||||
|      */ | ||||
|     default QueryWrapper query(T entity) { | ||||
|         return QueryWrapper.create(entity); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取实体类 Class 对象 | ||||
|      * | ||||
|      * @return 实体类 Class 对象 | ||||
|      */ | ||||
|     default Class<T> currentEntityClass() { | ||||
|         return (Class<T>)ClassUtil.getTypeArgument(this.getClass(), 0); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
|  * 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.mf.base; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 枚举接口 | ||||
|  * | ||||
|  * @param <T> value 类型 | ||||
|  * @author hellokaton | ||||
|  * @since 1.0.0 | ||||
|  */ | ||||
| public interface IBaseEnum<T extends Serializable> { | ||||
|  | ||||
|     /** | ||||
|      * 枚举描述 | ||||
|      * | ||||
|      * @return 枚举描述 | ||||
|      */ | ||||
|     String getDescription(); | ||||
|  | ||||
|     /** | ||||
|      * 枚举数据库存储值 | ||||
|      */ | ||||
|     T getValue(); | ||||
|  | ||||
|     /** | ||||
|      * 颜色 | ||||
|      * | ||||
|      * @return 颜色 | ||||
|      */ | ||||
|     default String getColor() { | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -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.mf.datapermission; | ||||
|  | ||||
| import java.lang.annotation.*; | ||||
|  | ||||
| /** | ||||
|  * 数据权限注解 | ||||
|  * | ||||
|  * @author hellokaton | ||||
|  * @since 2.0.2 | ||||
|  */ | ||||
| @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,50 @@ | ||||
| /* | ||||
|  * 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.mf.datapermission; | ||||
|  | ||||
| import org.aspectj.lang.annotation.*; | ||||
|  | ||||
| @Aspect | ||||
| public class DataPermissionAspect { | ||||
|  | ||||
|     // ThreadLocal用于存储注解信息 | ||||
|     private static final ThreadLocal<DataPermission> THREAD_LOCAL = new ThreadLocal<>(); | ||||
|  | ||||
|     @Pointcut("@annotation(dataPermission)") | ||||
|     public void dataPermissionPointcut(DataPermission dataPermission) { | ||||
|     } | ||||
|  | ||||
|     @Before("dataPermissionPointcut(dataPermission)") | ||||
|     public void beforeMethod(DataPermission dataPermission) { | ||||
|         THREAD_LOCAL.set(dataPermission); | ||||
|     } | ||||
|  | ||||
|     @AfterThrowing(pointcut = "dataPermissionPointcut(dataPermission)") | ||||
|     public void afterThrowingMethod(DataPermission dataPermission) { | ||||
|         THREAD_LOCAL.remove(); | ||||
|     } | ||||
|  | ||||
|     @After("dataPermissionPointcut(dataPermission)") | ||||
|     public void afterMethod(DataPermission dataPermission) { | ||||
|         THREAD_LOCAL.remove(); | ||||
|     } | ||||
|  | ||||
|     public static DataPermission currentDataPermission() { | ||||
|         return THREAD_LOCAL.get(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -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.mf.datapermission; | ||||
|  | ||||
| import java.util.Set; | ||||
|  | ||||
| /** | ||||
|  * 当前用户信息 | ||||
|  * | ||||
|  * @author hellokaton | ||||
|  * @since 2.0.2 | ||||
|  */ | ||||
| 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,161 @@ | ||||
| /* | ||||
|  * 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.mf.datapermission; | ||||
|  | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import com.mybatisflex.core.dialect.impl.CommonsDialectImpl; | ||||
| import com.mybatisflex.core.query.QueryWrapper; | ||||
|  | ||||
| import java.util.Set; | ||||
|  | ||||
| /** | ||||
|  * 数据权限处理器实现类 | ||||
|  * | ||||
|  * @author <a href="https://mybatis-flex.com/zh/core/data-permission.html">数据权限</a> | ||||
|  * @author hellokaton | ||||
|  * @since 2.0.2 | ||||
|  */ | ||||
| public class DataPermissionDialect extends CommonsDialectImpl { | ||||
|  | ||||
|     private final DataPermissionFilter dataPermissionFilter; | ||||
|  | ||||
|     public DataPermissionDialect(DataPermissionFilter dataPermissionFilter) { | ||||
|         this.dataPermissionFilter = dataPermissionFilter; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String forSelectByQuery(QueryWrapper queryWrapper) { | ||||
|         if (!dataPermissionFilter.isFilter()) { | ||||
|             return super.buildSelectSql(queryWrapper); | ||||
|         } | ||||
|         DataPermission dataPermission = DataPermissionAspect.currentDataPermission(); | ||||
|         if (null == dataPermission) { | ||||
|             return super.buildSelectSql(queryWrapper); | ||||
|         } | ||||
|         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 super.buildSelectSql(queryWrapper); | ||||
|             } | ||||
|             switch (dataScope) { | ||||
|                 case DEPT_AND_CHILD -> this.buildDeptAndChildExpression(dataPermission, currentUser, queryWrapper); | ||||
|                 case DEPT -> this.buildDeptExpression(dataPermission, currentUser, queryWrapper); | ||||
|                 case SELF -> this.buildSelfExpression(dataPermission, currentUser, queryWrapper); | ||||
|                 case CUSTOM -> this.buildCustomExpression(dataPermission, role, queryWrapper); | ||||
|                 default -> throw new IllegalArgumentException("暂不支持 [%s] 数据权限".formatted(dataScope)); | ||||
|             } | ||||
|         } | ||||
|         return super.buildSelectSql(queryWrapper); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建自定义数据权限表达式 | ||||
|      * | ||||
|      * <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 queryWrapper   查询条件 | ||||
|      * @return 处理完后的表达式 | ||||
|      */ | ||||
|     private void buildCustomExpression(DataPermission dataPermission, | ||||
|                                        DataPermissionCurrentUser.CurrentUserRole role, | ||||
|                                        QueryWrapper queryWrapper) { | ||||
|         QueryWrapper subQueryWrapper = QueryWrapper.create(); | ||||
|         subQueryWrapper.select(dataPermission.deptId()).from(dataPermission.roleDeptTableAlias()); | ||||
|         subQueryWrapper.eq(dataPermission.roleId(), role.getRoleId()); | ||||
|         queryWrapper.in(buildColumn(dataPermission.tableAlias(), dataPermission.deptId()), subQueryWrapper); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建仅本人数据权限表达式 | ||||
|      * | ||||
|      * <p> | ||||
|      * 处理完后的 SQL 示例:<br /> select t1.* from table as t1 where t1.create_user = xxx; | ||||
|      * </p> | ||||
|      * | ||||
|      * @param dataPermission 数据权限 | ||||
|      * @param currentUser    当前用户 | ||||
|      * @param queryWrapper   处理前的表达式 | ||||
|      */ | ||||
|     private void buildSelfExpression(DataPermission dataPermission, | ||||
|                                      DataPermissionCurrentUser currentUser, | ||||
|                                      QueryWrapper queryWrapper) { | ||||
|         queryWrapper.eq(buildColumn(dataPermission.tableAlias(), dataPermission.userId()), currentUser.getUserId()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建本部门数据权限表达式 | ||||
|      * | ||||
|      * <p> | ||||
|      * 处理完后的 SQL 示例:<br /> select t1.* from table as t1 where t1.dept_id = xxx; | ||||
|      * </p> | ||||
|      * | ||||
|      * @param dataPermission 数据权限 | ||||
|      * @param currentUser    当前用户 | ||||
|      * @param queryWrapper   查询条件 | ||||
|      */ | ||||
|     private void buildDeptExpression(DataPermission dataPermission, | ||||
|                                      DataPermissionCurrentUser currentUser, | ||||
|                                      QueryWrapper queryWrapper) { | ||||
|         queryWrapper.eq(buildColumn(dataPermission.tableAlias(), dataPermission.deptId()), currentUser.getDeptId()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建本部门及以下数据权限表达式 | ||||
|      * | ||||
|      * <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 queryWrapper   查询条件 | ||||
|      */ | ||||
|     private void buildDeptAndChildExpression(DataPermission dataPermission, | ||||
|                                              DataPermissionCurrentUser currentUser, | ||||
|                                              QueryWrapper queryWrapper) { | ||||
|         QueryWrapper subQueryWrapper = QueryWrapper.create(); | ||||
|         subQueryWrapper.select(dataPermission.id()).from(dataPermission.deptTableAlias()); | ||||
|         subQueryWrapper.and(qw -> { | ||||
|             qw.eq(dataPermission.id(), currentUser.getDeptId()) | ||||
|                 .or("find_in_set(" + currentUser.getDeptId() + ",ancestors)"); | ||||
|         }); | ||||
|         queryWrapper.in(buildColumn(dataPermission.tableAlias(), dataPermission.deptId()), subQueryWrapper); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建 Column | ||||
|      * | ||||
|      * @param tableAlias 表别名 | ||||
|      * @param columnName 字段名称 | ||||
|      * @return 带表别名字段 | ||||
|      */ | ||||
|     private String buildColumn(String tableAlias, String columnName) { | ||||
|         if (StrUtil.isNotEmpty(tableAlias)) { | ||||
|             return "%s.%s".formatted(tableAlias, columnName); | ||||
|         } | ||||
|         return columnName; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -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.mf.datapermission; | ||||
|  | ||||
| /** | ||||
|  * 数据权限过滤器接口 | ||||
|  * | ||||
|  * @author hellokaton | ||||
|  * @since 2.0.2 | ||||
|  */ | ||||
| public interface DataPermissionFilter { | ||||
|  | ||||
|     /** | ||||
|      * 是否过滤 | ||||
|      * | ||||
|      * @return true:过滤;false:不过滤 | ||||
|      */ | ||||
|     boolean isFilter(); | ||||
|  | ||||
|     /** | ||||
|      * 获取当前用户信息 | ||||
|      * | ||||
|      * @return 当前用户信息 | ||||
|      */ | ||||
|     DataPermissionCurrentUser getCurrentUser(); | ||||
| } | ||||
| @@ -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.mf.datapermission; | ||||
|  | ||||
| /** | ||||
|  * 数据权限枚举 | ||||
|  * | ||||
|  * @author hellokaton | ||||
|  * @since 2.0.2 | ||||
|  */ | ||||
| public enum DataScope { | ||||
|  | ||||
|     /** | ||||
|      * 全部数据权限 | ||||
|      */ | ||||
|     ALL, | ||||
|  | ||||
|     /** | ||||
|      * 本部门及以下数据权限 | ||||
|      */ | ||||
|     DEPT_AND_CHILD, | ||||
|  | ||||
|     /** | ||||
|      * 本部门数据权限 | ||||
|      */ | ||||
|     DEPT, | ||||
|  | ||||
|     /** | ||||
|      * 仅本人数据权限 | ||||
|      */ | ||||
|     SELF, | ||||
|  | ||||
|     /** | ||||
|      * 自定义数据权限 | ||||
|      */ | ||||
|     CUSTOM, | ||||
| } | ||||
| @@ -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.mf.service; | ||||
|  | ||||
| /** | ||||
|  * 通用业务接口 | ||||
|  * | ||||
|  * @param <T> 实体类型 | ||||
|  * @author hellokaton | ||||
|  * @since 1.2.0 | ||||
|  */ | ||||
| public interface IService<T> extends com.mybatisflex.core.service.IService<T> { | ||||
| } | ||||
| @@ -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.mf.service.impl; | ||||
|  | ||||
| import top.continew.starter.core.util.ClassUtils; | ||||
| import top.continew.starter.data.mf.base.BaseMapper; | ||||
| import top.continew.starter.data.mf.service.IService; | ||||
|  | ||||
| /** | ||||
|  * 通用业务实现类 | ||||
|  * | ||||
|  * @param <M> Mapper 接口 | ||||
|  * @param <T> 实体类型 | ||||
|  * @author hellokaton | ||||
|  * @since 1.5.0 | ||||
|  */ | ||||
| public class ServiceImpl<M extends BaseMapper<T>, T> extends com.mybatisflex.spring.service.impl.ServiceImpl<M, T> implements IService<T> { | ||||
|  | ||||
|     protected final Class<?>[] typeArguments = ClassUtils.getTypeArguments(this.getClass()); | ||||
|     protected final Class<T> entityClass = currentModelClass(); | ||||
|  | ||||
|     protected Class<T> currentModelClass() { | ||||
|         return (Class<T>)this.typeArguments[1]; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,222 @@ | ||||
| /* | ||||
|  * 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.mf.util; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.text.CharSequenceUtil; | ||||
| import cn.hutool.core.util.ArrayUtil; | ||||
| import cn.hutool.core.util.ObjectUtil; | ||||
| import com.mybatisflex.core.query.QueryWrapper; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 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.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| import java.util.function.Consumer; | ||||
|  | ||||
| /** | ||||
|  * QueryWrapper 助手 | ||||
|  * | ||||
|  * @author hellokaton | ||||
|  * @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>   查询条件数据类型 | ||||
|      * @return QueryWrapper | ||||
|      */ | ||||
|     public static <Q> QueryWrapper build(Q query) { | ||||
|         QueryWrapper queryWrapper = QueryWrapper.create(); | ||||
|         // 没有查询条件,直接返回 | ||||
|         if (null == query) { | ||||
|             return queryWrapper; | ||||
|         } | ||||
|         // 获取查询条件中所有的字段 | ||||
|         List<Field> fieldList = ReflectUtils.getNonStaticFields(query.getClass()); | ||||
|         return build(query, fieldList, queryWrapper); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建 QueryWrapper | ||||
|      * | ||||
|      * @param query 查询条件 | ||||
|      * @param sort  排序条件 | ||||
|      * @param <Q>   查询条件数据类型 | ||||
|      * @return QueryWrapper | ||||
|      * @since 2.5.2 | ||||
|      */ | ||||
|     public static <Q> QueryWrapper build(Q query, Sort sort) { | ||||
|         QueryWrapper queryWrapper = QueryWrapper.create(); | ||||
|         // 没有查询条件,直接返回 | ||||
|         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(field, order.isAscending()); | ||||
|             } | ||||
|         } | ||||
|         // 获取查询条件中所有的字段 | ||||
|         List<Field> fieldList = ReflectUtils.getNonStaticFields(query.getClass()); | ||||
|         return build(query, fieldList, queryWrapper); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建 QueryWrapper | ||||
|      * | ||||
|      * @param query        查询条件 | ||||
|      * @param fields       查询条件字段列表 | ||||
|      * @param queryWrapper QueryWrapper | ||||
|      * @param <Q>          查询条件数据类型 | ||||
|      * @return QueryWrapper | ||||
|      */ | ||||
|     public static <Q> QueryWrapper build(Q query, List<Field> fields, QueryWrapper queryWrapper) { | ||||
|         // 没有查询条件,直接返回 | ||||
|         if (null == query) { | ||||
|             return queryWrapper; | ||||
|         } | ||||
|         // 解析并拼接查询条件 | ||||
|         for (Field field : fields) { | ||||
|             List<Consumer<QueryWrapper>> consumers = buildWrapperConsumer(query, field); | ||||
|             if (CollUtil.isNotEmpty(consumers)) { | ||||
|                 consumers.forEach(queryWrapper::and); | ||||
|             } | ||||
|         } | ||||
|         return queryWrapper; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建 QueryWrapper Consumer | ||||
|      * | ||||
|      * @param query 查询条件 | ||||
|      * @param field 查询条件字段 | ||||
|      * @param <Q>   查询条件数据类型 | ||||
|      * @param <R>   查询数据类型 | ||||
|      * @return QueryWrapper Consumer | ||||
|      */ | ||||
|     private static <Q, R> List<Consumer<QueryWrapper>> 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>> 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>> 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.mf.autoconfigure.MybatisFlexAutoConfiguration | ||||
| @@ -0,0 +1,22 @@ | ||||
| --- ### MyBatis Flex 配置(https://mybatis-flex.com/zh/base/configuration.html) | ||||
| mybatis-flex: | ||||
|   # 启动时是否检查 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 | ||||
|   global-config: | ||||
|     key-config: | ||||
|       key-type: generator | ||||
|       # flexId 主键生成器 com.mybatisflex.core.keygen.impl.FlexIDKeyGenerator | ||||
|       value: flexId | ||||
		Reference in New Issue
	
	Block a user