SpringBoot中如何基于配置库规范分组请求字段并解析子规则
问题描述
在SpringBoot微服务中,接口会接收一个List<String>类型的Solr字段名列表,需要按照配置库中的规则将这些字段分组(例如gender_s、age_f、job_s需要归到demography分组),但不想用冗余的if-else代码实现分组逻辑;同时需要解析包含subrules的字段,展示对应的view-name。目前用@Value注解读取配置库内容,但因配置数据量较大,希望有更简洁高效的实现方案。
配置库内容如下:
project.search.categories: sms: view-name: Sms rules: sms: view-name: operator tarafindan atilan aylik atilan sms sayisi solr-name: sms_count_f view-type: NUMERIC solr-type: BIGINT min-value: 0 max-value: 150 max-range: 50 demography: view-name: Demografi rules: gender: view-name: Cinsiyet solr-name: gender_s view-type: SINGLE_SELECT solr-type: STRING age: view-name: Yas solr-name: age_f view-type: NUMERIC solr-type: BIGINT min-value: 0 max-value: 150 max-range: 50 job: view-name: Meslek solr-name: job_s view-type: MULTI_SELECT solr-type: STRING values: JOBS citizenship: view-name: Uyruk solr-name: citizenship_s view-type: MULTI_SELECT solr-type: STRING values: ROAMING_COUNTRY interest: view-name: Ilgi Alanlari rules: betting: view-name: Spor Bahisleri ile ilgilenen solr-name: betting__sports_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır career: view-name: Kariyer solr-name: career_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır coupons: view-name: İndirimler ile ilgilenen solr-name: coupons__discount_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır device_site: view-name: Teknoloji ile ilgilenen solr-name: device_site__technology_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır e-commerce: view-name: E-ticaret ile ilgilenen solr-name: ecommerce_interest_f view-type: MULTISELECT_TINYINT solr-type: TINYINT values: 1@Evet, 0@Hayır subrules: home_furniture: view-name: Ev dekorasyonu ile ilgilenen solr-name: ecommerce__home_furniture_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır clothing: view-name: Tekstil ile ilgilenen solr-name: ecommerce__clothing_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır automobiles: view-name: Otomobil ile ilgilenen solr-name: ecommerce__automobiles_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır market_place: view-name: Online Market Place Alısveris ile ilgilenen solr-name: ecommerce__market_place_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır sports: view-name: Spor Alışverişi ile ilgilenen solr-name: ecommerce__sports_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır technology: view-name: Teknoloji Alışverişi ile ilgilenen solr-name: ecommerce__technology_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır books: view-name: Kitap Alışverisi ile ilgilenen solr-name: ecommerce__books_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır kids: view-name: Çocuk için Alışveriş yapan solr-name: ecommerce__kids_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır comparison: view-name: Fiyat Karşılaştırma # convert solr-name: ecommerce__comparison_interest_f view-type: SINGLE_SELECT solr-type: TINYINT values: 1@Evet, 0@Hayır
解决方案
1. 用@ConfigurationProperties绑定配置,替代@Value
创建对应的实体类,让Spring自动将配置映射为Java对象,避免手动用@Value逐个读取:
实体类定义
// 根配置类 @ConfigurationProperties(prefix = "project.search") @Data public class SearchConfig { private Map<String, Category> categories; @Data public static class Category { private String viewName; // 对应配置里的view-name private Map<String, Rule> rules; } @Data public static class Rule { private String viewName; private String solrName; private String viewType; private String solrType; private Integer minValue; private Integer maxValue; private Integer maxRange; private String values; private Map<String, Rule> subrules; // 处理子规则 } }
启用配置绑定
在启动类或配置类上添加@EnableConfigurationProperties(SearchConfig.class):
@SpringBootApplication @EnableConfigurationProperties(SearchConfig.class) public class SearchServiceApplication { public static void main(String[] args) { SpringApplication.run(SearchServiceApplication.class, args); } }
2. 预构建缓存映射,避免重复遍历配置
在服务启动时,将Solr字段名与所属分组、规则信息构建成全局缓存,这样请求到来时直接查询缓存,无需遍历整个配置结构:
@Component public class SolrFieldMappingCache { private final Map<String, String> solrFieldToCategory = new HashMap<>(); private final Map<String, Rule> solrFieldToRule = new HashMap<>(); public SolrFieldMappingCache(SearchConfig searchConfig) { // 遍历所有分组和规则,构建缓存 searchConfig.getCategories().forEach((categoryKey, category) -> { // 处理主规则 category.getRules().forEach((ruleKey, rule) -> { solrFieldToCategory.put(rule.getSolrName(), categoryKey); solrFieldToRule.put(rule.getSolrName(), rule); // 处理子规则 if (rule.getSubrules() != null) { rule.getSubrules().forEach((subRuleKey, subRule) -> { solrFieldToCategory.put(subRule.getSolrName(), categoryKey); solrFieldToRule.put(subRule.getSolrName(), subRule); }); } }); }); } // 获取字段所属分组 public String getCategoryBySolrField(String solrField) { return solrFieldToCategory.get(solrField); } // 获取字段对应的规则(含view-name) public Rule getRuleBySolrField(String solrField) { return solrFieldToRule.get(solrField); } }
3. 业务逻辑实现
在业务类中直接注入缓存,处理字段分组和view-name解析,完全不需要if-else:
@Service public class SearchFieldService { private final SolrFieldMappingCache mappingCache; @Autowired public SearchFieldService(SolrFieldMappingCache mappingCache) { this.mappingCache = mappingCache; } // 对输入的Solr字段列表进行分组 public Map<String, List<String>> groupSolrFields(List<String> solrFields) { Map<String, List<String>> result = new HashMap<>(); solrFields.forEach(field -> { String category = mappingCache.getCategoryBySolrField(field); if (category != null) { result.computeIfAbsent(category, k -> new ArrayList<>()).add(field); } // 可添加字段不存在时的默认处理逻辑 }); return result; } // 获取字段对应的view-name,包括子规则 public Map<String, String> getViewNames(List<String> solrFields) { Map<String, String> result = new HashMap<>(); solrFields.forEach(field -> { Rule rule = mappingCache.getRuleBySolrField(field); if (rule != null) { result.put(field, rule.getViewName()); } }); return result; } }
优势说明
- 完全消除if-else冗余代码,配置变更时无需修改业务逻辑,只需调整配置文件
- 缓存预构建在启动阶段,请求处理时直接查Map,性能高效
- 配置与代码解耦,符合Spring Boot最佳实践
- 天然支持子规则的解析,无需额外递归处理
内容的提问来源于stack exchange,提问作者pasaklikukuli
相关产品推荐
相关产品推荐

