本文目录导读:

- 基于MyBatis-Plus的插件实现(最常见)
- 基于ShardingSphere的联邦查询过滤
- 使用Spring Data JPA的Specification
- 基于Redis缓存的范围过滤
- Elasticsearch范围过滤
- MongoDB范围过滤
- 最佳实践建议
在Java分布式系统中,实现数据范围API的过滤通常涉及以下几种主流方案和技术选型:
基于MyBatis-Plus的插件实现(最常见)
自定义拦截器
@Component
@Intercepts({@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}
)})
public class RangeFilterInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = MetaObject.forObject(statementHandler,
SystemMetaObject.DEFAULT_OBJECT_FACTORY,
SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
new DefaultReflectorFactory());
// 获取原始SQL
String originalSql = statementHandler.getBoundSql().getSql();
// 动态拼接范围过滤条件
String filteredSql = addRangeFilter(originalSql);
// 设置修改后的SQL
metaObject.setValue("delegate.boundSql.sql", filteredSql);
return invocation.proceed();
}
private String addRangeFilter(String sql) {
// 从上下文获取当前用户的权限范围
UserContext userContext = UserContextHolder.get();
String rangeCondition = buildRangeCondition(userContext);
// 在WHERE条件后追加范围过滤
if (sql.toUpperCase().contains("WHERE")) {
return sql + " AND " + rangeCondition;
} else {
return sql + " WHERE " + rangeCondition;
}
}
}
注解驱动模式
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataRange {
String fieldName() default "org_id";
Class<? extends RangeHandler> handler() default DefaultRangeHandler.class;
}
// 使用时
@Service
public class UserService {
@DataRange(fieldName = "dept_id", handler = DeptRangeHandler.class)
public List<User> queryUsers(QueryParam param) {
// 正常查询逻辑,拦截器自动追加范围过滤
}
}
基于ShardingSphere的联邦查询过滤
// 配置数据分片策略,自动实现范围路由
@Configuration
public class ShardingConfig {
@Bean
public ShardingRuleConfiguration shardingRuleConfig() {
ShardingRuleConfiguration config = new ShardingRuleConfiguration();
// 按组织ID范围分片
TableRuleConfiguration orderRule = new TableRuleConfiguration("t_order");
orderRule.setTableShardingStrategyConfig(
new StandardShardingStrategyConfiguration("org_id",
new OrgRangeShardingAlgorithm()));
config.getTableRuleConfigs().add(orderRule);
return config;
}
}
public class OrgRangeShardingAlgorithm
implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(
Collection<String> availableTargetNames,
RangeShardingValue<Long> shardingValue) {
Range<Long> range = shardingValue.getValueRange();
// 根据范围计算实际需要查询的分片
return calculateTargetTables(range);
}
}
使用Spring Data JPA的Specification
@Service
public class UserDataService {
public Page<User> queryUsersWithRange(Pageable pageable) {
Specification<User> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
// 获取当前用户的数据权限范围
DataRange range = SecurityUtils.getCurrentUserDataRange();
// 如果是部门范围
if (range.getType().equals(DataRangeType.DEPT)) {
predicates.add(cb.equal(
root.get("departmentId"), range.getDeptId()));
}
// 如果是自定义范围
if (range.getType().equals(DataRangeType.CUSTOM)) {
predicates.add(root.get("orgId").in(range.getOrgIds()));
}
// 如果是所有数据,不添加任何条件
return cb.and(predicates.toArray(new Predicate[0]));
};
return userRepository.findAll(spec, pageable);
}
}
基于Redis缓存的范围过滤
@Component
public class RangeCacheFilter {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 构建数据权限缓存
public void buildUserDataRangeCache(Long userId) {
List<Long> accessibleOrgIds = getAccessibleOrgs(userId);
// 存储到Redis,设置过期时间
String key = "data:range:" + userId;
redisTemplate.opsForSet().add(key, accessibleOrgIds.toArray());
redisTemplate.expire(key, 1, TimeUnit.HOURS);
}
// 使用缓存进行过滤
public <T> List<T> filterByRange(List<T> dataList,
Function<T, Long> idExtractor, Long userId) {
Set<Object> accessibleIds = redisTemplate.opsForSet()
.members("data:range:" + userId);
return dataList.stream()
.filter(item -> accessibleIds.contains(idExtractor.apply(item)))
.collect(Collectors.toList());
}
}
Elasticsearch范围过滤
@Service
public class ESDocumentService {
@Autowired
private ElasticsearchRestTemplate esTemplate;
public SearchHits<Document> searchWithRangeFilter(
String keyword, Long orgId, Pageable pageable) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加关键词搜索
if (StringUtils.hasText(keyword)) {
queryBuilder.withQuery(QueryBuilders.matchQuery("content", keyword));
}
// 添加组织范围过滤
queryBuilder.withFilter(QueryBuilders.termQuery("orgId", orgId));
// 或者范围查询
queryBuilder.withFilter(QueryBuilders.rangeQuery("createTime")
.gte("2024-01-01")
.lte("2024-12-31"));
queryBuilder.withPageable(pageable);
return esTemplate.search(queryBuilder.build(), Document.class);
}
}
MongoDB范围过滤
@Service
public class MongoDataService {
@Autowired
private MongoTemplate mongoTemplate;
public List<Product> getProductsWithRange(ProductQuery query) {
Criteria criteria = new Criteria();
// 价格范围过滤
if (query.getMinPrice() != null && query.getMaxPrice() != null) {
criteria.and("price").gte(query.getMinPrice())
.lte(query.getMaxPrice());
}
// 数据权限范围过滤
UserContext user = UserContextHolder.get();
if (user.getDataScope() == DataScope.DEPT) {
criteria.and("deptId").is(user.getDeptId());
} else if (user.getDataScope() == DataScope.ORG) {
criteria.and("orgId").in(user.getAccessibleOrgIds());
}
Query mongoQuery = new Query(criteria);
return mongoTemplate.find(mongoQuery, Product.class);
}
}
最佳实践建议
- 分层设计:范围过滤应在Service层统一处理,DAO层保持纯净
- 缓存策略:频繁使用的范围规则应缓存,避免重复计算
- 性能监控:对大规模数据的范围过滤要进行性能监控和优化
- 兼容性处理:考虑MySQL、Elasticsearch、MongoDB等异构数据源的统一过滤逻辑
- 熔断机制:当范围过滤导致查询性能下降时,应有降级策略
选择具体的实现方案时,需要根据:
- 数据量规模
- 实时性要求
- 系统复杂度
- 团队技术栈
来权衡选择最适合的方案。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播