diff --git a/README.md b/README.md index 85f1a44..77be4db 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

Build Status Coverage Status - Downloads + Downloads

## SpringBlade微服务开发平台 @@ -45,7 +45,8 @@ blade-tool * 交流二群:`751253339`(满) * 交流三群:`784729540`(满) * 交流四群:`1034621754`(满) -* 交流五群:`946350912` +* 交流五群:`946350912`(满) +* 交流六群: `511624269` ## 在线演示 * Sword演示地址:[https://sword.bladex.vip](https://sword.bladex.vip) @@ -166,10 +167,4 @@ LGPL是GPL的一个为主要为类库使用设计的开源协议。和GPL要求 ## 鸣谢 * mica([Mica](https://github.com/lets-mica/mica)) * 如梦技术([DreamLu](https://www.dreamlu.net/)) -* pigx([Pig Microservice](https://www.pig4cloud.com/zh-cn/)) -* avue([avue](https://avue.top/)) -* gitee.ltd([gitee.ltd](https://gitee.ltd/)) -* 鲸宵(鲸宵) - -## 关注我们 -![](https://images.gitee.com/uploads/images/2019/0330/065148_f0ada806_410595.jpeg) \ No newline at end of file +* avue([avue](https://avuejs.com/)) diff --git a/blade-core-boot/pom.xml b/blade-core-boot/pom.xml index e13582a..5d5f497 100644 --- a/blade-core-boot/pom.xml +++ b/blade-core-boot/pom.xml @@ -5,7 +5,7 @@ org.springblade blade-tool - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-boot/src/main/java/org/springblade/core/boot/tenant/BladeTenantInterceptor.java b/blade-core-boot/src/main/java/org/springblade/core/boot/tenant/BladeTenantInterceptor.java new file mode 100644 index 0000000..a4e8f83 --- /dev/null +++ b/blade-core-boot/src/main/java/org/springblade/core/boot/tenant/BladeTenantInterceptor.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.boot.tenant; + +import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 租户拦截器 + * + * @author Chill + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class BladeTenantInterceptor extends TenantLineInnerInterceptor { + + /** + * 租户处理器 + */ + private TenantLineHandler tenantLineHandler; + + @Override + public void setTenantLineHandler(TenantLineHandler tenantLineHandler) { + super.setTenantLineHandler(tenantLineHandler); + this.tenantLineHandler = tenantLineHandler; + } + +} diff --git a/blade-core-boot/src/main/java/org/springblade/core/boot/tenant/TenantConfiguration.java b/blade-core-boot/src/main/java/org/springblade/core/boot/tenant/TenantConfiguration.java index 7693888..32831fe 100644 --- a/blade-core-boot/src/main/java/org/springblade/core/boot/tenant/TenantConfiguration.java +++ b/blade-core-boot/src/main/java/org/springblade/core/boot/tenant/TenantConfiguration.java @@ -16,13 +16,15 @@ package org.springblade.core.boot.tenant; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import lombok.AllArgsConstructor; -import org.springblade.core.boot.config.MybatisPlusConfiguration; +import org.springblade.core.mp.config.MybatisPlusConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; /** * 多租户配置类 @@ -36,19 +38,29 @@ import org.springframework.context.annotation.Configuration; public class TenantConfiguration { /** - * 多租户配置类 - */ - private final BladeTenantProperties properties; - - /** - * 自定义租户处理器 + * 自定义多租户处理器 * + * @param tenantProperties 多租户配置类 * @return TenantHandler */ @Bean - @ConditionalOnMissingBean(TenantLineHandler.class) - public TenantLineHandler bladeTenantHandler() { - return new BladeTenantHandler(properties); + @Primary + public TenantLineHandler bladeTenantHandler(BladeTenantProperties tenantProperties) { + return new BladeTenantHandler(tenantProperties); + } + + /** + * 自定义租户拦截器 + * + * @param tenantHandler 多租户处理器 + * @return BladeTenantInterceptor + */ + @Bean + @Primary + public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantLineHandler tenantHandler) { + BladeTenantInterceptor tenantInterceptor = new BladeTenantInterceptor(); + tenantInterceptor.setTenantLineHandler(tenantHandler); + return tenantInterceptor; } /** diff --git a/blade-core-boot/src/main/resources/bootstrap.yml b/blade-core-boot/src/main/resources/bootstrap.yml index 86a5f48..1fbd7e4 100644 --- a/blade-core-boot/src/main/resources/bootstrap.yml +++ b/blade-core-boot/src/main/resources/bootstrap.yml @@ -101,7 +101,7 @@ mybatis-plus: swagger: title: SpringBlade 接口文档系统 description: SpringBlade 接口文档系统 - version: 3.1.0 + version: 3.2.0 license: Powered By SpringBlade licenseUrl: https://bladex.vip terms-of-service-url: https://bladex.vip diff --git a/blade-core-cloud/pom.xml b/blade-core-cloud/pom.xml index 04851dd..c22e16f 100644 --- a/blade-core-cloud/pom.xml +++ b/blade-core-cloud/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-datascope/pom.xml b/blade-core-datascope/pom.xml new file mode 100644 index 0000000..79524fc --- /dev/null +++ b/blade-core-datascope/pom.xml @@ -0,0 +1,37 @@ + + + + blade-tool + org.springblade + 3.2.0 + + 4.0.0 + + blade-core-datascope + ${project.artifactId} + ${blade.tool.version} + jar + + + + + org.springblade + blade-core-mybatis + ${blade.tool.version} + + + + org.springframework.boot + spring-boot-starter-jdbc + + + tomcat-jdbc + org.apache.tomcat + + + + + + diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/annotation/DataAuth.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/annotation/DataAuth.java new file mode 100644 index 0000000..d0da7c5 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/annotation/DataAuth.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.annotation; + +import org.springblade.core.datascope.constant.DataScopeConstant; +import org.springblade.core.datascope.enums.DataScopeEnum; + +import java.lang.annotation.*; + +/** + * 数据权限定义 + * + * @author Chill + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface DataAuth { + + /** + * 资源编号 + */ + String code() default ""; + + /** + * 数据权限对应字段 + */ + String column() default DataScopeConstant.DEFAULT_COLUMN; + + /** + * 数据权限规则 + */ + DataScopeEnum type() default DataScopeEnum.ALL; + + /** + * 可见字段 + */ + String field() default "*"; + + /** + * 数据权限规则值域 + */ + String value() default ""; + +} + diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/config/DataScopeConfiguration.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/config/DataScopeConfiguration.java new file mode 100644 index 0000000..f6a73ab --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/config/DataScopeConfiguration.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.config; + +import lombok.AllArgsConstructor; +import org.springblade.core.datascope.handler.BladeDataScopeHandler; +import org.springblade.core.datascope.handler.BladeScopeModelHandler; +import org.springblade.core.datascope.handler.DataScopeHandler; +import org.springblade.core.datascope.handler.ScopeModelHandler; +import org.springblade.core.datascope.interceptor.DataScopeInterceptor; +import org.springblade.core.datascope.props.DataScopeProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * 数据权限配置类 + * + * @author Chill + */ +@Configuration(proxyBeanMethods = false) +@AllArgsConstructor +@EnableConfigurationProperties(DataScopeProperties.class) +public class DataScopeConfiguration { + + private final JdbcTemplate jdbcTemplate; + + @Bean + @ConditionalOnMissingBean(ScopeModelHandler.class) + public ScopeModelHandler scopeModelHandler() { + return new BladeScopeModelHandler(jdbcTemplate); + } + + @Bean + @ConditionalOnBean(ScopeModelHandler.class) + @ConditionalOnMissingBean(DataScopeHandler.class) + public DataScopeHandler dataScopeHandler(ScopeModelHandler scopeModelHandler) { + return new BladeDataScopeHandler(scopeModelHandler); + } + + @Bean + @ConditionalOnBean(DataScopeHandler.class) + @ConditionalOnMissingBean(DataScopeInterceptor.class) + public DataScopeInterceptor interceptor(DataScopeHandler dataScopeHandler, DataScopeProperties dataScopeProperties) { + return new DataScopeInterceptor(dataScopeHandler, dataScopeProperties); + } + +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/constant/DataScopeConstant.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/constant/DataScopeConstant.java new file mode 100644 index 0000000..5631dd5 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/constant/DataScopeConstant.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.constant; + +import org.springblade.core.tool.utils.StringUtil; + +/** + * 数据权限常量 + * + * @author Chill + */ +public interface DataScopeConstant { + + String DEFAULT_COLUMN = "create_dept"; + + /** + * 获取部门数据 + */ + String DATA_BY_DEPT = "select id from blade_dept where ancestors like concat(concat('%', ?),'%') and is_deleted = 0"; + + /** + * 根据resourceCode获取数据权限配置 + */ + String DATA_BY_CODE = "select resource_code, scope_column, scope_field, scope_type, scope_value from blade_scope_data where resource_code = ?"; + + /** + * 根据mapperId获取数据权限配置 + * + * @param size 数量 + * @return String + */ + static String dataByMapper(int size) { + return "select resource_code, scope_column, scope_field, scope_type, scope_value from blade_scope_data where scope_class = ? and id in (select scope_id from blade_role_scope where role_id in (" + buildHolder(size) + "))"; + } + + /** + * 获取Sql占位符 + * + * @param size 数量 + * @return String + */ + static String buildHolder(int size) { + StringBuilder builder = StringUtil.builder(); + for (int i = 0; i < size; i++) { + builder.append("?,"); + } + return StringUtil.removeSuffix(builder.toString(), ","); + } + + +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/enums/DataScopeEnum.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/enums/DataScopeEnum.java new file mode 100644 index 0000000..4931ec0 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/enums/DataScopeEnum.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据权限类型 + * + * @author lengleng, Chill + */ +@Getter +@AllArgsConstructor +public enum DataScopeEnum { + /** + * 全部数据 + */ + ALL(1, "全部"), + + /** + * 本人可见 + */ + OWN(2, "本人可见"), + + /** + * 所在机构可见 + */ + OWN_DEPT(3, "所在机构可见"), + + /** + * 所在机构及子级可见 + */ + OWN_DEPT_CHILD(4, "所在机构及子级可见"), + + /** + * 自定义 + */ + CUSTOM(5, "自定义"); + + /** + * 类型 + */ + private final int type; + /** + * 描述 + */ + private final String description; + + public static DataScopeEnum of(Integer dataScopeType) { + if (dataScopeType == null) { + return null; + } + DataScopeEnum[] values = DataScopeEnum.values(); + for (DataScopeEnum scopeTypeEnum : values) { + if (scopeTypeEnum.type == dataScopeType) { + return scopeTypeEnum; + } + } + return null; + } +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/exception/DataScopeException.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/exception/DataScopeException.java new file mode 100644 index 0000000..bf95845 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/exception/DataScopeException.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.exception; + +/** + * 数据权限异常 + * + * @author L.cm + */ +public class DataScopeException extends RuntimeException { + + public DataScopeException() { + } + + public DataScopeException(String message) { + super(message); + } + + public DataScopeException(Throwable cause) { + super(cause); + } +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/BladeDataScopeHandler.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/BladeDataScopeHandler.java new file mode 100644 index 0000000..9ae41c2 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/BladeDataScopeHandler.java @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.handler; + +import lombok.RequiredArgsConstructor; +import org.springblade.core.datascope.enums.DataScopeEnum; +import org.springblade.core.datascope.model.DataScopeModel; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.tool.constant.RoleConstant; +import org.springblade.core.tool.utils.BeanUtil; +import org.springblade.core.tool.utils.Func; +import org.springblade.core.tool.utils.PlaceholderUtil; +import org.springblade.core.tool.utils.StringUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * 默认数据权限规则 + * + * @author Chill + */ +@RequiredArgsConstructor +public class BladeDataScopeHandler implements DataScopeHandler { + + private final ScopeModelHandler scopeModelHandler; + + @Override + public String sqlCondition(String mapperId, DataScopeModel dataScope, BladeUser bladeUser, String originalSql) { + + //数据权限资源编号 + String code = dataScope.getResourceCode(); + + //根据mapperId从数据库中获取对应模型 + DataScopeModel dataScopeDb = scopeModelHandler.getDataScopeByMapper(mapperId, bladeUser.getRoleId()); + + //mapperId配置未取到则从数据库中根据资源编号获取 + if (dataScopeDb == null && StringUtil.isNotBlank(code)) { + dataScopeDb = scopeModelHandler.getDataScopeByCode(code); + } + + //未从数据库找到对应配置则采用默认 + dataScope = (dataScopeDb != null) ? dataScopeDb : dataScope; + + //判断数据权限类型并组装对应Sql + Integer scopeRule = Objects.requireNonNull(dataScope).getScopeType(); + DataScopeEnum scopeTypeEnum = DataScopeEnum.of(scopeRule); + List ids = new ArrayList<>(); + String whereSql = "where scope.{} in ({})"; + if (DataScopeEnum.ALL == scopeTypeEnum || StringUtil.containsAny(bladeUser.getRoleName(), RoleConstant.ADMIN)) { + return null; + } else if (DataScopeEnum.CUSTOM == scopeTypeEnum) { + whereSql = PlaceholderUtil.getDefaultResolver().resolveByMap(dataScope.getScopeValue(), BeanUtil.toMap(bladeUser)); + } else if (DataScopeEnum.OWN == scopeTypeEnum) { + ids.add(bladeUser.getUserId()); + } else if (DataScopeEnum.OWN_DEPT == scopeTypeEnum) { + ids.addAll(Func.toLongList(bladeUser.getDeptId())); + } else if (DataScopeEnum.OWN_DEPT_CHILD == scopeTypeEnum) { + List deptIds = Func.toLongList(bladeUser.getDeptId()); + ids.addAll(deptIds); + deptIds.forEach(deptId -> { + List deptIdList = scopeModelHandler.getDeptAncestors(deptId); + ids.addAll(deptIdList); + }); + } + return StringUtil.format("select {} from ({}) scope " + whereSql, Func.toStr(dataScope.getScopeField(), "*"), originalSql, dataScope.getScopeColumn(), StringUtil.join(ids)); + } + +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/BladeScopeModelHandler.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/BladeScopeModelHandler.java new file mode 100644 index 0000000..8666432 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/BladeScopeModelHandler.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.handler; + +import lombok.RequiredArgsConstructor; +import org.springblade.core.datascope.constant.DataScopeConstant; +import org.springblade.core.datascope.model.DataScopeModel; +import org.springblade.core.tool.utils.*; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.springblade.core.tool.utils.CacheUtil.SYS_CACHE; + + +/** + * BladeScopeModelHandler + * + * @author Chill + */ +@RequiredArgsConstructor +public class BladeScopeModelHandler implements ScopeModelHandler { + + private static final String SCOPE_CACHE_CODE = "dataScope:code:"; + private static final String SCOPE_CACHE_CLASS = "dataScope:class:"; + private static final String DEPT_CACHE_ANCESTORS = "dept:ancestors:"; + private static final DataScopeModel SEARCHED_DATA_SCOPE_MODEL = new DataScopeModel(Boolean.TRUE); + + private final JdbcTemplate jdbcTemplate; + + /** + * 获取数据权限 + * + * @param mapperId 数据权限mapperId + * @param roleId 用户角色集合 + * @return DataScopeModel + */ + @Override + public DataScopeModel getDataScopeByMapper(String mapperId, String roleId) { + List args = new ArrayList<>(Collections.singletonList(mapperId)); + List roleIds = Func.toLongList(roleId); + args.addAll(roleIds); + // 增加searched字段防止未配置的参数重复读库导致缓存击穿 + // 后续若有新增配置则会清空缓存重新加载 + DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, DataScopeModel.class); + if (dataScope == null || !dataScope.getSearched()) { + List list = jdbcTemplate.query(DataScopeConstant.dataByMapper(roleIds.size()), args.toArray(), new BeanPropertyRowMapper<>(DataScopeModel.class)); + if (CollectionUtil.isNotEmpty(list)) { + dataScope = list.iterator().next(); + dataScope.setSearched(Boolean.TRUE); + } else { + dataScope = SEARCHED_DATA_SCOPE_MODEL; + } + CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CLASS, mapperId + StringPool.COLON + roleId, dataScope); + } + return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null; + } + + /** + * 获取数据权限 + * + * @param code 数据权限资源编号 + * @return DataScopeModel + */ + @Override + public DataScopeModel getDataScopeByCode(String code) { + DataScopeModel dataScope = CacheUtil.get(SYS_CACHE, SCOPE_CACHE_CODE, code, DataScopeModel.class); + // 增加searched字段防止未配置的参数重复读库导致缓存击穿 + // 后续若有新增配置则会清空缓存重新加载 + if (dataScope == null || !dataScope.getSearched()) { + List list = jdbcTemplate.query(DataScopeConstant.DATA_BY_CODE, new Object[]{code}, new BeanPropertyRowMapper<>(DataScopeModel.class)); + if (CollectionUtil.isNotEmpty(list)) { + dataScope = list.iterator().next(); + dataScope.setSearched(Boolean.TRUE); + } else { + dataScope = SEARCHED_DATA_SCOPE_MODEL; + } + CacheUtil.put(SYS_CACHE, SCOPE_CACHE_CODE, code, dataScope); + } + return StringUtil.isNotBlank(dataScope.getResourceCode()) ? dataScope : null; + } + + /** + * 获取部门子级 + * + * @param deptId 部门id + * @return deptIds + */ + @Override + public List getDeptAncestors(Long deptId) { + List ancestors = CacheUtil.get(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, List.class); + if (CollectionUtil.isEmpty(ancestors)) { + ancestors = jdbcTemplate.queryForList(DataScopeConstant.DATA_BY_DEPT, new Object[]{deptId}, Long.class); + CacheUtil.put(SYS_CACHE, DEPT_CACHE_ANCESTORS, deptId, ancestors); + } + return ancestors; + } +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/DataScopeHandler.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/DataScopeHandler.java new file mode 100644 index 0000000..b5ddab6 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/DataScopeHandler.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.handler; + +import org.springblade.core.datascope.model.DataScopeModel; +import org.springblade.core.secure.BladeUser; + +/** + * 数据权限规则 + * + * @author Chill + */ +public interface DataScopeHandler { + + /** + * 获取过滤sql + * + * @param mapperId 数据查询类 + * @param dataScope 数据权限类 + * @param bladeUser 当前用户信息 + * @param originalSql 原始Sql + * @return sql + */ + String sqlCondition(String mapperId, DataScopeModel dataScope, BladeUser bladeUser, String originalSql); + +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/ScopeModelHandler.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/ScopeModelHandler.java new file mode 100644 index 0000000..daa579c --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/handler/ScopeModelHandler.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.handler; + +import org.springblade.core.datascope.model.DataScopeModel; + +import java.util.List; + +/** + * 获取数据权限模型统一接口 + * + * @author Chill + */ +public interface ScopeModelHandler { + + /** + * 获取数据权限 + * + * @param mapperId 数据权限mapperId + * @param roleId 用户角色集合 + * @return DataScopeModel + */ + DataScopeModel getDataScopeByMapper(String mapperId, String roleId); + + /** + * 获取数据权限 + * + * @param code 数据权限资源编号 + * @return DataScopeModel + */ + DataScopeModel getDataScopeByCode(String code); + + /** + * 获取部门子级 + * + * @param deptId 部门id + * @return deptIds + */ + List getDeptAncestors(Long deptId); + +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/interceptor/DataScopeInterceptor.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/interceptor/DataScopeInterceptor.java new file mode 100644 index 0000000..2b7aa28 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/interceptor/DataScopeInterceptor.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.interceptor; + +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.core.toolkit.StringPool; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.mapping.StatementType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springblade.core.datascope.annotation.DataAuth; +import org.springblade.core.datascope.handler.DataScopeHandler; +import org.springblade.core.datascope.model.DataScopeModel; +import org.springblade.core.datascope.props.DataScopeProperties; +import org.springblade.core.mp.intercept.QueryInterceptor; +import org.springblade.core.secure.BladeUser; +import org.springblade.core.secure.utils.SecureUtil; +import org.springblade.core.tool.utils.ClassUtil; +import org.springblade.core.tool.utils.SpringUtil; +import org.springblade.core.tool.utils.StringUtil; + +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + + +/** + * mybatis 数据权限拦截器 + * + * @author L.cm, Chill + */ +@Slf4j +@RequiredArgsConstructor +@SuppressWarnings({"rawtypes"}) +public class DataScopeInterceptor implements QueryInterceptor { + + private final ConcurrentMap dataAuthMap = new ConcurrentHashMap<>(8); + + private final DataScopeHandler dataScopeHandler; + private final DataScopeProperties dataScopeProperties; + + @Override + public void intercept(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { + //未启用则放行 + if (!dataScopeProperties.getEnabled()) { + return; + } + + //未取到用户则放行 + BladeUser bladeUser = SecureUtil.getUser(); + if (bladeUser == null) { + return; + } + + if (SqlCommandType.SELECT != ms.getSqlCommandType() || StatementType.CALLABLE == ms.getStatementType()) { + return; + } + + String originalSql = boundSql.getSql(); + + //查找注解中包含DataAuth类型的参数 + DataAuth dataAuth = findDataAuthAnnotation(ms); + + //注解为空并且数据权限方法名未匹配到,则放行 + String mapperId = ms.getId(); + String className = mapperId.substring(0, mapperId.lastIndexOf(StringPool.DOT)); + String mapperName = ClassUtil.getShortName(className); + String methodName = mapperId.substring(mapperId.lastIndexOf(StringPool.DOT) + 1); + boolean mapperSkip = dataScopeProperties.getMapperKey().stream().noneMatch(methodName::contains) + || dataScopeProperties.getMapperExclude().stream().anyMatch(mapperName::contains); + if (dataAuth == null && mapperSkip) { + return; + } + + //创建数据权限模型 + DataScopeModel dataScope = new DataScopeModel(); + + //若注解不为空,则配置注解项 + if (dataAuth != null) { + dataScope.setResourceCode(dataAuth.code()); + dataScope.setScopeColumn(dataAuth.column()); + dataScope.setScopeType(dataAuth.type().getType()); + dataScope.setScopeField(dataAuth.field()); + dataScope.setScopeValue(dataAuth.value()); + } + + //获取数据权限规则对应的筛选Sql + String sqlCondition = dataScopeHandler.sqlCondition(mapperId, dataScope, bladeUser, originalSql); + if (!StringUtil.isBlank(sqlCondition)) { + PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql); + mpBoundSql.sql(sqlCondition); + } + } + + /** + * 获取数据权限注解信息 + * + * @param mappedStatement mappedStatement + * @return DataAuth + */ + private DataAuth findDataAuthAnnotation(MappedStatement mappedStatement) { + String id = mappedStatement.getId(); + return dataAuthMap.computeIfAbsent(id, (key) -> { + String className = key.substring(0, key.lastIndexOf(StringPool.DOT)); + String mapperBean = StringUtil.firstCharToLower(ClassUtil.getShortName(className)); + Object mapper = SpringUtil.getBean(mapperBean); + String methodName = key.substring(key.lastIndexOf(StringPool.DOT) + 1); + Class[] interfaces = ClassUtil.getAllInterfaces(mapper); + for (Class mapperInterface : interfaces) { + for (Method method : mapperInterface.getDeclaredMethods()) { + if (methodName.equals(method.getName()) && method.isAnnotationPresent(DataAuth.class)) { + return method.getAnnotation(DataAuth.class); + } + } + } + return null; + }); + } + +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java new file mode 100644 index 0000000..8859a21 --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.model; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springblade.core.datascope.constant.DataScopeConstant; +import org.springblade.core.datascope.enums.DataScopeEnum; + +import java.io.Serializable; + +/** + * 数据权限实体类 + * + * @author Chill + */ +@Data +@NoArgsConstructor +public class DataScopeModel implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 构造器创建 + */ + public DataScopeModel(Boolean searched) { + this.searched = searched; + } + + /** + * 是否已查询 + */ + private Boolean searched = Boolean.FALSE; + /** + * 资源编号 + */ + private String resourceCode; + /** + * 数据权限字段 + */ + private String scopeColumn = DataScopeConstant.DEFAULT_COLUMN; + /** + * 数据权限规则 + */ + private Integer scopeType = DataScopeEnum.ALL.getType(); + /** + * 可见字段 + */ + private String scopeField; + /** + * 数据权限规则值 + */ + private String scopeValue; +} diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/props/DataScopeProperties.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/props/DataScopeProperties.java new file mode 100644 index 0000000..3664e2e --- /dev/null +++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/props/DataScopeProperties.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.datascope.props; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * 数据权限参数配置类 + * + * @author Chill + */ +@Data +@ConfigurationProperties(prefix = "blade.data-scope") +public class DataScopeProperties { + + /** + * 开启数据权限 + */ + private Boolean enabled = true; + /** + * mapper方法匹配关键字 + */ + private List mapperKey = Arrays.asList("page", "Page", "list", "List"); + + /** + * mapper过滤 + */ + private List mapperExclude = Collections.singletonList("FlowMapper"); + +} diff --git a/blade-core-develop/pom.xml b/blade-core-develop/pom.xml index ef29980..1354111 100644 --- a/blade-core-develop/pom.xml +++ b/blade-core-develop/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-launch/pom.xml b/blade-core-launch/pom.xml index 4aa9651..5fbb75c 100644 --- a/blade-core-launch/pom.xml +++ b/blade-core-launch/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java index a781d10..0589676 100644 --- a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java +++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java @@ -25,7 +25,7 @@ public interface AppConstant { /** * 应用版本 */ - String APPLICATION_VERSION = "3.1.0"; + String APPLICATION_VERSION = "3.2.0"; /** * 基础包 diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java index 39d9da6..1cb3364 100644 --- a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java +++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java @@ -33,6 +33,7 @@ public interface TokenConstant { String ACCOUNT = "account"; String USER_ID = "user_id"; String ROLE_ID = "role_id"; + String DEPT_ID = "dept_id"; String USER_NAME = "user_name"; String ROLE_NAME = "role_name"; String TENANT_ID = "tenant_id"; diff --git a/blade-core-log/pom.xml b/blade-core-log/pom.xml index ecbf3d6..8f40f57 100644 --- a/blade-core-log/pom.xml +++ b/blade-core-log/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-mybatis/pom.xml b/blade-core-mybatis/pom.xml index 954c352..a327edc 100644 --- a/blade-core-mybatis/pom.xml +++ b/blade-core-mybatis/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-boot/src/main/java/org/springblade/core/boot/config/MybatisPlusConfiguration.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/config/MybatisPlusConfiguration.java similarity index 50% rename from blade-core-boot/src/main/java/org/springblade/core/boot/config/MybatisPlusConfiguration.java rename to blade-core-mybatis/src/main/java/org/springblade/core/mp/config/MybatisPlusConfiguration.java index d81d8c2..645216d 100644 --- a/blade-core-boot/src/main/java/org/springblade/core/boot/config/MybatisPlusConfiguration.java +++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/config/MybatisPlusConfiguration.java @@ -13,21 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springblade.core.boot.config; +package org.springblade.core.mp.config; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; -import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; import lombok.AllArgsConstructor; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.StringValue; import org.mybatis.spring.annotation.MapperScan; -import org.springblade.core.boot.props.MybatisPlusProperties; +import org.springblade.core.mp.intercept.QueryInterceptor; +import org.springblade.core.mp.plugins.BladePaginationInterceptor; import org.springblade.core.mp.plugins.SqlLogInterceptor; +import org.springblade.core.mp.props.MybatisPlusProperties; +import org.springblade.core.secure.utils.SecureUtil; +import org.springblade.core.tool.constant.BladeConstant; +import org.springblade.core.tool.utils.Func; +import org.springblade.core.tool.utils.ObjectUtil; +import org.springframework.beans.factory.ObjectProvider; 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.core.annotation.AnnotationAwareOrderComparator; /** * mybatisplus 配置 @@ -40,22 +49,48 @@ import org.springframework.context.annotation.Configuration; @EnableConfigurationProperties(MybatisPlusProperties.class) public class MybatisPlusConfiguration { - private final TenantLineHandler tenantLineHandler; + + /** + * 租户拦截器 + */ + @Bean + @ConditionalOnMissingBean(TenantLineInnerInterceptor.class) + public TenantLineInnerInterceptor tenantLineInnerInterceptor() { + return new TenantLineInnerInterceptor(new TenantLineHandler() { + @Override + public Expression getTenantId() { + return new StringValue(Func.toStr(SecureUtil.getTenantId(), BladeConstant.ADMIN_TENANT_ID)); + } + + @Override + public boolean ignoreTable(String tableName) { + return true; + } + }); + } /** * mybatis-plus 拦截器集合 */ @Bean @ConditionalOnMissingBean(MybatisPlusInterceptor.class) - public MybatisPlusInterceptor mybatisPlusInterceptor(MybatisPlusProperties mybatisPlusProperties) { + public MybatisPlusInterceptor mybatisPlusInterceptor(ObjectProvider queryInterceptors, + TenantLineInnerInterceptor tenantLineInnerInterceptor, + MybatisPlusProperties mybatisPlusProperties) { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 配置租户拦截器 - interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(tenantLineHandler)); + interceptor.addInnerInterceptor(tenantLineInnerInterceptor); // 配置分页拦截器 - PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); - paginationInnerInterceptor.setMaxLimit(mybatisPlusProperties.getPageLimit()); - paginationInnerInterceptor.setOverflow(mybatisPlusProperties.getOverflow()); - interceptor.addInnerInterceptor(paginationInnerInterceptor); + BladePaginationInterceptor paginationInterceptor = new BladePaginationInterceptor(); + // 配置自定义查询拦截器 + QueryInterceptor[] queryInterceptorArray = queryInterceptors.getIfAvailable(); + if (ObjectUtil.isNotEmpty(queryInterceptorArray)) { + AnnotationAwareOrderComparator.sort(queryInterceptorArray); + paginationInterceptor.setQueryInterceptors(queryInterceptorArray); + } + paginationInterceptor.setMaxLimit(mybatisPlusProperties.getPageLimit()); + paginationInterceptor.setOverflow(mybatisPlusProperties.getOverflow()); + interceptor.addInnerInterceptor(paginationInterceptor); return interceptor; } diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java new file mode 100644 index 0000000..f101a81 --- /dev/null +++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2028, DreamLu All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: DreamLu 卢春梦 (596392912@qq.com) + */ + +package org.springblade.core.mp.intercept; + +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.core.Ordered; + +/** + * 自定义 mybatis plus 查询拦截器 + * + * @author L.cm + */ +@SuppressWarnings({"rawtypes"}) +public interface QueryInterceptor extends Ordered { + + /** + * 拦截处理 + * + * @param executor + * @param ms + * @param parameter + * @param rowBounds + * @param resultHandler + * @param boundSql + */ + void intercept(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql); + + /** + * 排序 + * + * @return int + */ + @Override + default int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } +} diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/plugins/BladePaginationInterceptor.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/plugins/BladePaginationInterceptor.java new file mode 100644 index 0000000..b511459 --- /dev/null +++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/plugins/BladePaginationInterceptor.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.mp.plugins; + +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import lombok.Setter; +import lombok.SneakyThrows; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springblade.core.mp.intercept.QueryInterceptor; + +/** + * 拓展分页拦截器 + * + * @author Chill + */ +@Setter +public class BladePaginationInterceptor extends PaginationInnerInterceptor { + + /** + * 查询拦截器 + */ + private QueryInterceptor[] queryInterceptors; + + @SneakyThrows + @Override + public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { + QueryInterceptorExecutor.exec(queryInterceptors, executor, ms, parameter, rowBounds, resultHandler, boundSql); + return super.willDoQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql); + } + +} diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/plugins/QueryInterceptorExecutor.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/plugins/QueryInterceptorExecutor.java new file mode 100644 index 0000000..ca829b2 --- /dev/null +++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/plugins/QueryInterceptorExecutor.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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 org.springblade.core.mp.plugins; + +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springblade.core.mp.intercept.QueryInterceptor; +import org.springblade.core.tool.utils.ObjectUtil; + +/** + * 查询拦截器执行器 + * + *

+ * 目的:抽取此方法是为了后期方便同步更新 {@link BladePaginationInterceptor} + *

+ * + * @author L.cm + */ +@SuppressWarnings({"rawtypes"}) +public class QueryInterceptorExecutor { + + /** + * 执行查询拦截器 + */ + static void exec(QueryInterceptor[] interceptors, Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws Throwable { + if (ObjectUtil.isEmpty(interceptors)) { + return; + } + for (QueryInterceptor interceptor : interceptors) { + interceptor.intercept(executor, ms, parameter, rowBounds, resultHandler, boundSql); + } + } + +} diff --git a/blade-core-boot/src/main/java/org/springblade/core/boot/props/MybatisPlusProperties.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/props/MybatisPlusProperties.java similarity index 96% rename from blade-core-boot/src/main/java/org/springblade/core/boot/props/MybatisPlusProperties.java rename to blade-core-mybatis/src/main/java/org/springblade/core/mp/props/MybatisPlusProperties.java index 6853135..c8f1495 100644 --- a/blade-core-boot/src/main/java/org/springblade/core/boot/props/MybatisPlusProperties.java +++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/props/MybatisPlusProperties.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springblade.core.boot.props; +package org.springblade.core.mp.props; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/blade-core-oss/pom.xml b/blade-core-oss/pom.xml index 0f77f3e..70e2a34 100644 --- a/blade-core-oss/pom.xml +++ b/blade-core-oss/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-report/pom.xml b/blade-core-report/pom.xml index dc287bf..41bbd51 100644 --- a/blade-core-report/pom.xml +++ b/blade-core-report/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-secure/pom.xml b/blade-core-secure/pom.xml index f649ca9..c065563 100644 --- a/blade-core-secure/pom.xml +++ b/blade-core-secure/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java b/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java index 37647dd..d9958ea 100644 --- a/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java +++ b/blade-core-secure/src/main/java/org/springblade/core/secure/BladeUser.java @@ -45,6 +45,11 @@ public class BladeUser implements Serializable { */ @ApiModelProperty(hidden = true) private String tenantId; + /** + * 部门id + */ + @ApiModelProperty(hidden = true) + private String deptId; /** * 昵称 */ diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java index 553dbfb..e904e60 100644 --- a/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java +++ b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java @@ -48,6 +48,7 @@ public class SecureUtil { private final static String ACCOUNT = TokenConstant.ACCOUNT; private final static String USER_ID = TokenConstant.USER_ID; private final static String ROLE_ID = TokenConstant.ROLE_ID; + private final static String DEPT_ID = TokenConstant.DEPT_ID; private final static String USER_NAME = TokenConstant.USER_NAME; private final static String ROLE_NAME = TokenConstant.ROLE_NAME; private final static String TENANT_ID = TokenConstant.TENANT_ID; @@ -98,6 +99,7 @@ public class SecureUtil { Long userId = Func.toLong(claims.get(SecureUtil.USER_ID)); String tenantId = Func.toStr(claims.get(SecureUtil.TENANT_ID)); String roleId = Func.toStr(claims.get(SecureUtil.ROLE_ID)); + String deptId = Func.toStr(claims.get(SecureUtil.DEPT_ID)); String account = Func.toStr(claims.get(SecureUtil.ACCOUNT)); String roleName = Func.toStr(claims.get(SecureUtil.ROLE_NAME)); String userName = Func.toStr(claims.get(SecureUtil.USER_NAME)); @@ -107,6 +109,7 @@ public class SecureUtil { bladeUser.setTenantId(tenantId); bladeUser.setAccount(account); bladeUser.setRoleId(roleId); + bladeUser.setDeptId(deptId); bladeUser.setRoleName(roleName); bladeUser.setUserName(userName); return bladeUser; diff --git a/blade-core-social/pom.xml b/blade-core-social/pom.xml index 06bd361..611fdee 100644 --- a/blade-core-social/pom.xml +++ b/blade-core-social/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-swagger/pom.xml b/blade-core-swagger/pom.xml index b73ce41..aacf5ca 100644 --- a/blade-core-swagger/pom.xml +++ b/blade-core-swagger/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java b/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java index b437cc2..44862b7 100644 --- a/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java +++ b/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java @@ -55,7 +55,7 @@ public class SwaggerProperties { /** * 版本 **/ - private String version = "3.1.0"; + private String version = "3.2.0"; /** * 许可证 **/ diff --git a/blade-core-test/pom.xml b/blade-core-test/pom.xml index 22d4bbe..39325c9 100644 --- a/blade-core-test/pom.xml +++ b/blade-core-test/pom.xml @@ -5,7 +5,7 @@ org.springblade blade-tool - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-tool/pom.xml b/blade-core-tool/pom.xml index c6516e8..34dd8be 100644 --- a/blade-core-tool/pom.xml +++ b/blade-core-tool/pom.xml @@ -6,7 +6,7 @@ org.springblade blade-tool - 3.1.0 + 3.2.0 4.0.0 diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/config/XssConfiguration.java b/blade-core-tool/src/main/java/org/springblade/core/tool/config/XssConfiguration.java index cf3995a..89c159e 100644 --- a/blade-core-tool/src/main/java/org/springblade/core/tool/config/XssConfiguration.java +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/config/XssConfiguration.java @@ -44,6 +44,8 @@ public class XssConfiguration { /** * 防XSS注入 + * + * @return FilterRegistrationBean */ @Bean public FilterRegistrationBean xssFilterRegistration() { diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/constant/BladeConstant.java b/blade-core-tool/src/main/java/org/springblade/core/tool/constant/BladeConstant.java index 13e957c..4560cb3 100644 --- a/blade-core-tool/src/main/java/org/springblade/core/tool/constant/BladeConstant.java +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/constant/BladeConstant.java @@ -65,6 +65,11 @@ public interface BladeConstant { int DB_ADMIN_NON_LOCKED = 0; int DB_ADMIN_LOCKED = 1; + /** + * 顶级父节点id + */ + Long TOP_PARENT_ID = 0L; + /** * 管理员对应的租户ID */ diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/CacheUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/CacheUtil.java new file mode 100644 index 0000000..8d01329 --- /dev/null +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/CacheUtil.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.core.tool.utils; + +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.lang.Nullable; + +import java.util.concurrent.Callable; + +/** + * 缓存工具类 + * + * @author Chill + */ +public class CacheUtil { + + public static final String SYS_CACHE = "blade:sys"; + + private static CacheManager cacheManager; + + /** + * 获取缓存工具 + * + * @return CacheManager + */ + private static CacheManager getCacheManager() { + if (cacheManager == null) { + cacheManager = SpringUtil.getBean(CacheManager.class); + } + return cacheManager; + } + + /** + * 获取缓存对象 + * + * @param cacheName 缓存名 + * @return Cache + */ + public static Cache getCache(String cacheName) { + return getCacheManager().getCache(cacheName); + } + + /** + * 获取缓存 + * + * @param cacheName 缓存名 + * @param keyPrefix 缓存键前缀 + * @param key 缓存键值 + * @return Cache + */ + @Nullable + public static Object get(String cacheName, String keyPrefix, Object key) { + if (Func.hasEmpty(cacheName, keyPrefix, key)) { + return null; + } + return getCache(cacheName).get(keyPrefix.concat(String.valueOf(key))).get(); + } + + /** + * 获取缓存 + * + * @param cacheName 缓存名 + * @param keyPrefix 缓存键前缀 + * @param key 缓存键值 + * @param type 转换类型 + * @param 类型 + * @return Cache + */ + @Nullable + public static T get(String cacheName, String keyPrefix, Object key, @Nullable Class type) { + if (Func.hasEmpty(cacheName, keyPrefix, key)) { + return null; + } + return getCache(cacheName).get(keyPrefix.concat(String.valueOf(key)), type); + } + + /** + * 获取缓存 + * + * @param cacheName 缓存名 + * @param keyPrefix 缓存键前缀 + * @param key 缓存键值 + * @param valueLoader 重载对象 + * @param 类型 + * @return Cache + */ + @Nullable + public static T get(String cacheName, String keyPrefix, Object key, Callable valueLoader) { + if (Func.hasEmpty(cacheName, keyPrefix, key)) { + return null; + } + try { + Cache.ValueWrapper valueWrapper = getCache(cacheName).get(keyPrefix.concat(String.valueOf(key))); + Object value = null; + if (valueWrapper == null) { + T call = valueLoader.call(); + if (Func.isNotEmpty(call)) { + getCache(cacheName).put(keyPrefix.concat(String.valueOf(key)), call); + value = call; + } + } else { + value = valueWrapper.get(); + } + return (T) value; + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + /** + * 设置缓存 + * + * @param cacheName 缓存名 + * @param keyPrefix 缓存键前缀 + * @param key 缓存键值 + * @param value 缓存值 + */ + public static void put(String cacheName, String keyPrefix, Object key, @Nullable Object value) { + getCache(cacheName).put(keyPrefix.concat(String.valueOf(key)), value); + } + + /** + * 清除缓存 + * + * @param cacheName 缓存名 + * @param keyPrefix 缓存键前缀 + * @param key 缓存键值 + */ + public static void evict(String cacheName, String keyPrefix, Object key) { + if (Func.hasEmpty(cacheName, keyPrefix, key)) { + return; + } + getCache(cacheName).evict(keyPrefix.concat(String.valueOf(key))); + } + + /** + * 清空缓存 + * + * @param cacheName 缓存名 + */ + public static void clear(String cacheName) { + if (Func.isEmpty(cacheName)) { + return; + } + getCache(cacheName).clear(); + } + +} + diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateUtil.java index 2ae2cea..547d78b 100644 --- a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateUtil.java +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DateUtil.java @@ -405,6 +405,7 @@ public class DateUtil { * * @param dateStr 时间字符串 * @param pattern 表达式 + * @param query 移动查询 * @return 时间 */ public static T parse(String dateStr, String pattern, TemporalQuery query) { @@ -453,6 +454,9 @@ public class DateUtil { /** * Converts local date time to Calendar. + * + * @param localDateTime LocalDateTime + * @return Calendar */ public static Calendar toCalendar(final LocalDateTime localDateTime) { return GregorianCalendar.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault())); diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/PlaceholderUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/PlaceholderUtil.java new file mode 100644 index 0000000..e4bbc52 --- /dev/null +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/PlaceholderUtil.java @@ -0,0 +1,143 @@ +package org.springblade.core.tool.utils; + +import java.util.Map; +import java.util.Properties; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * 占位符解析器 + * + * @author meilin.huang, chill + */ +public class PlaceholderUtil { + /** + * 默认前缀占位符 + */ + public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; + + /** + * 默认后缀占位符 + */ + public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; + + /** + * 默认单例解析器 + */ + private static final PlaceholderUtil DEFAULT_RESOLVER = new PlaceholderUtil(); + + /** + * 占位符前缀 + */ + private String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX; + + /** + * 占位符后缀 + */ + private String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; + + + private PlaceholderUtil() { + } + + private PlaceholderUtil(String placeholderPrefix, String placeholderSuffix) { + this.placeholderPrefix = placeholderPrefix; + this.placeholderSuffix = placeholderSuffix; + } + + /** + * 获取默认的占位符解析器,即占位符前缀为"${", 后缀为"}" + * + * @return PlaceholderUtil + */ + public static PlaceholderUtil getDefaultResolver() { + return DEFAULT_RESOLVER; + } + + public static PlaceholderUtil getResolver(String placeholderPrefix, String placeholderSuffix) { + return new PlaceholderUtil(placeholderPrefix, placeholderSuffix); + } + + /** + * 解析带有指定占位符的模板字符串,默认占位符为前缀:${ 后缀:} + * + * @param content 要解析的带有占位符的模板字符串 + * @param values 按照模板占位符索引位置设置对应的值 + * @return {String} + */ + public String resolve(String content, String... values) { + int start = content.indexOf(this.placeholderPrefix); + if (start == -1) { + return content; + } + //值索引 + int valueIndex = 0; + StringBuilder result = new StringBuilder(content); + while (start != -1) { + int end = result.indexOf(this.placeholderSuffix); + String replaceContent = values[valueIndex++]; + result.replace(start, end + this.placeholderSuffix.length(), replaceContent); + start = result.indexOf(this.placeholderPrefix, start + replaceContent.length()); + } + return result.toString(); + } + + /** + * 解析带有指定占位符的模板字符串,默认占位符为前缀:${ 后缀:} + * + * @param content 要解析的带有占位符的模板字符串 + * @param values 按照模板占位符索引位置设置对应的值 + * @return {String} + */ + public String resolve(String content, Object[] values) { + return resolve(content, Stream.of(values).map(String::valueOf).toArray(String[]::new)); + } + + /** + * 根据替换规则来替换指定模板中的占位符值 + * + * @param content 要解析的字符串 + * @param rule 解析规则回调 + * @return {String} + */ + public String resolveByRule(String content, Function rule) { + int start = content.indexOf(this.placeholderPrefix); + if (start == -1) { + return content; + } + StringBuilder result = new StringBuilder(content); + while (start != -1) { + int end = result.indexOf(this.placeholderSuffix, start + 1); + //获取占位符属性值,如${id}, 即获取id + String placeholder = result.substring(start + this.placeholderPrefix.length(), end); + //替换整个占位符内容,即将${id}值替换为替换规则回调中的内容 + String replaceContent = placeholder.trim().isEmpty() ? "" : rule.apply(placeholder); + result.replace(start, end + this.placeholderSuffix.length(), replaceContent); + start = result.indexOf(this.placeholderPrefix, start + replaceContent.length()); + } + return result.toString(); + } + + /** + * 替换模板中占位符内容,占位符的内容即为map key对应的值,key为占位符中的内容 + * + * @param content 模板内容 + * @param valueMap 值映射 + * @return 替换完成后的字符串 + */ + public String resolveByMap(String content, final Map valueMap) { + return resolveByRule(content, placeholderValue -> String.valueOf(valueMap.get(placeholderValue))); + } + + /** + * 根据properties文件替换占位符内容 + * + * @param content 模板内容 + * @param properties 配置 + * @return {String} + */ + public String resolveByProperties(String content, final Properties properties) { + return resolveByRule(content, properties::getProperty); + } + +} diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java index fad31b5..6a86ecd 100644 --- a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/StringUtil.java @@ -1438,5 +1438,40 @@ public class StringUtil extends org.springframework.util.StringUtils { return sb.toString().toLowerCase(); } + + + /** + * 首字母变小写 + * + * @param str 字符串 + * @return {String} + */ + public static String firstCharToLower(String str) { + char firstChar = str.charAt(0); + if (firstChar >= CharPool.UPPER_A && firstChar <= CharPool.UPPER_Z) { + char[] arr = str.toCharArray(); + arr[0] += (CharPool.LOWER_A - CharPool.UPPER_A); + return new String(arr); + } + return str; + } + + /** + * 首字母变大写 + * + * @param str 字符串 + * @return {String} + */ + public static String firstCharToUpper(String str) { + char firstChar = str.charAt(0); + if (firstChar >= CharPool.LOWER_A && firstChar <= CharPool.LOWER_Z) { + char[] arr = str.toCharArray(); + arr[0] -= (CharPool.LOWER_A - CharPool.UPPER_A); + return new String(arr); + } + return str; + } + + } diff --git a/blade-core-transaction/pom.xml b/blade-core-transaction/pom.xml index 8ef2d5b..34a6853 100644 --- a/blade-core-transaction/pom.xml +++ b/blade-core-transaction/pom.xml @@ -5,7 +5,7 @@ blade-tool org.springblade - 3.1.0 + 3.2.0 4.0.0 diff --git a/pom.xml b/pom.xml index a1b49f4..f530163 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springblade blade-tool - 3.1.0 + 3.2.0 pom blade-tool @@ -36,26 +36,26 @@ - 3.1.0 + 3.2.0 1.8 - 3.8.0 + 3.8.1 2.10.5 1.6.2 - 2.0.8 - 3.4.3.1 + 2.0.9 + 3.4.3.4 3.4.1 1.6.0 3.4.2 - 2.3.1 + 2.5.3 1.2.5 2021.1 - 2.0.2 + 2.0.3 1.4.2 2.0.0.RELEASE - 2.5.2 - 2020.0.3 + 2.5.6 + 2020.0.4 Cairo-SR8 UTF-8 @@ -77,6 +77,7 @@ blade-core-oss blade-core-transaction blade-core-report + blade-core-datascope @@ -278,7 +279,7 @@ - +