2026/1/2 8:41:36
网站建设
项目流程
织梦 网站标题,邯郸做网站的地方,厦门seo蜘蛛屯,做股东变更要上哪个网站在 Spring Boot 项目中#xff0c;处理列表查询时往往难以避免“复杂搜索”这一核心挑战。典型场景包括#xff1a;用户管理#xff1a;需支持按姓名、手机号、状态、注册时间等多个字段组合筛选。商品搜索#xff1a;涉及分类、多选标签、价格区间、关键词匹配及排序等复杂…在 Spring Boot 项目中处理列表查询时往往难以避免“复杂搜索”这一核心挑战。典型场景包括用户管理需支持按姓名、手机号、状态、注册时间等多个字段组合筛选。商品搜索涉及分类、多选标签、价格区间、关键词匹配及排序等复杂条件。实际上复杂搜索的实现本身并不困难真正的难点在于如何使搜索逻辑保持清晰、可维护且易于扩展。本文将提供一套可在日常项目中直接复用的动态查询模板其核心流程为SearchDTO → Service 层动态 Wrapper → Mapper → SearchVO一、复杂搜索代码混乱的根源通常存在以下几类典型问题1. DTO 字段设计混乱所有条件堆积于同一对象示例javaString name;String phone;Integer status;String keyword;ListLong categoryIds;BigDecimal minPrice;BigDecimal maxPrice;String startTime;String endTime;随着字段不断增加Service 层中的条件判断也随之膨胀最终导致代码难以维护。2. Wrapper 中充斥大量条件判断语句例如javaif (dto.getName() ! null)wrapper.like(User::getName, dto.getName());if (dto.getStatus() ! null)wrapper.eq(User::getStatus, dto.getStatus());if (dto.getStartTime() ! null)wrapper.ge(User::getCreateTime, dto.getStartTime());// ...数十行条件判断并列呈现可读性与可维护性均较差。3. 相同查询逻辑在多处重复实现相似的“模糊搜索 多选 区间筛选”逻辑可能在多个接口中重复编写缺乏抽象与复用。4. 条件逻辑难以扩展若新增一个“标签筛选”条件需从 Controller 至 SQL 逐层修改变更成本高。最终导致的结果是搜索接口往往成为项目中维护难度最高的部分之一。二、复杂搜索的核心难点其本质在于查询条件的动态性与组合不确定性1.部分字段为可选条件传则查询不传则忽略2.部分字段需支持区间查询3.部分字段为多选值IN 查询4.部分字段需进行模糊匹配5.部分条件需动态组合 AND/OR 逻辑6.部分查询涉及关联表筛选。这些组合可能随时变化因此代码必须保持结构清晰、易于调整。解决思路应为将所有搜索逻辑通过统一方式进行封装并嵌入 Wrapper 中使其具备可配置、可扩展、可复用的特性。三、SearchDTO构建结构化的查询入参设计良好的搜索接口应从规范的数据传输对象开始。示例javaDatapublic class UserSearchDTO extends PageRequest {private String keyword; // 统一关键字匹配姓名/手机号private Integer status; // 精确匹配private ListLong roleIds; // 多选条件IN 查询private LocalDateTime beginTime; // 时间区间起点private LocalDateTime endTime; // 时间区间终点}设计要点1. 关键字统一为 keyword 字段避免为每个可模糊查询的字段单独定义提升接口简洁性。2. 时间区间字段成对出现采用 beginTime 与 endTime 的规范命名便于统一处理。3. 多选条件使用集合类型便于直接应用于 IN 查询。4. DTO 仅承担查询条件载体职责不参与具体业务逻辑。四、Service 层实现动态 Wrapper 模板Service 层应负责组合查询条件并保持代码清晰。示例模板javapublic PageVOUserVO page(UserSearchDTO dto) {LambdaQueryWrapperUser wrapper new LambdaQueryWrapper();// 1. 关键字多字段搜索if (StringUtils.isNotBlank(dto.getKeyword())) {wrapper.and(w w.like(User::getName, dto.getKeyword()).or().like(User::getPhone, dto.getKeyword()));}// 2. 状态精确匹配wrapper.eq(dto.getStatus() ! null, User::getStatus, dto.getStatus());// 3. 多选角色查询wrapper.in(CollectionUtils.isNotEmpty(dto.getRoleIds()),User::getRoleId, dto.getRoleIds());// 4. 时间区间查询wrapper.ge(dto.getBeginTime() ! null, User::getCreateTime, dto.getBeginTime());wrapper.le(dto.getEndTime() ! null, User::getCreateTime, dto.getEndTime());// 5. 执行分页查询PageUser page userMapper.selectPage(dto.toPage(), wrapper);return PageVO.of(page, UserVO.class);}此模板结构清晰覆盖大部分常见查询场景并具有良好的扩展性。五、通用查询工具类封装为提升代码复用性可将常用查询条件封装为工具类1. 模糊查询封装javapublic static T void like(LambdaQueryWrapperT wrapper,boolean condition,SFunctionT, ? column,String value) {if (condition StringUtils.isNotBlank(value)) {wrapper.like(column, value);}}调用方式javaWrapperHelper.like(wrapper, true, User::getName, dto.getName());2. 多字段关键字查询封装javapublic static T void keyword(LambdaQueryWrapperT wrapper,String keyword,SFunctionT, ?... columns) {if (StringUtils.isBlank(keyword)) return;wrapper.and(w {for (int i 0; i columns.length; i) {if (i 0) {w.like(columns[i], keyword);} else {w.or().like(columns[i], keyword);}}});}调用方式javaWrapperHelper.keyword(wrapper, dto.getKeyword(),User::getName,User::getPhone);3. 区间查询封装javapublic static T, R extends ComparableRvoid range(LambdaQueryWrapperT wrapper,R begin, R end,SFunctionT, R column) {wrapper.ge(begin ! null, column, begin);wrapper.le(end ! null, column, end);}调用方式javaWrapperHelper.range(wrapper, dto.getBeginTime(), dto.getEndTime(), User::getCreateTime);4. 集合条件查询封装javapublic static T void in(LambdaQueryWrapperT wrapper,List? list,SFunctionT, ? column) {wrapper.in(CollectionUtils.isNotEmpty(list), column, list);}最终效果Service 层代码将变得极为简洁javaWrapperHelper.keyword(wrapper, dto.getKeyword(), User::getName, User::getPhone);WrapperHelper.eq(wrapper, dto.getStatus(), User::getStatus);WrapperHelper.in(wrapper, dto.getRoleIds(), User::getRoleId);WrapperHelper.range(wrapper, dto.getBeginTime(), dto.getEndTime(), User::getCreateTime);六、典型业务场景示例场景一商品多条件搜索含排序SearchDTOjavaString keyword;ListLong categoryIds;ListInteger statusList;BigDecimal minPrice;BigDecimal maxPrice;String sortField;String sortOrder;Service 实现javaWrapperHelper.keyword(wrapper, dto.getKeyword(), Goods::getName, Goods::getDesc);WrapperHelper.in(wrapper, dto.getCategoryIds(), Goods::getCategoryId);WrapperHelper.in(wrapper, dto.getStatusList(), Goods::getStatus);WrapperHelper.range(wrapper, dto.getMinPrice(), dto.getMaxPrice(), Goods::getPrice);SortHelper.applySort(wrapper, dto.getSortField(), dto.getSortOrder());场景二用户复合条件筛选OR 逻辑javawrapper.and(w {w.eq(dto.getGender() ! null, User::getGender, dto.getGender());w.or(dto.getIsVip() ! null).eq(User::getIsVip, dto.getIsVip());});场景三多表关联筛选如标签过滤javawrapper.inSql(User::getId,SELECT user_id FROM user_tag WHERE tag_id IN convertToSql(dto.getTagIds()));七、动态查询模板的收益采用统一模板后代码结构将呈现以下优势1.Controller 层保持简洁仅负责参数传递与结果返回。2.Service 层逻辑统一、可读性强、易于维护通过工具类方法组合条件避免重复代码。3.DTO 设计规范清晰采用 keyword List range 的标准化结构。查询逻辑高度复用、可灵活组合、易于扩展新增条件或调整逻辑时只需在工具类或 DTO 中集中修改。自此您将彻底告别满屏的 if/else 条件判断搜索逻辑在不同接口中的重复实现因单个字段变更引发的连锁式修改。通过统一的动态查询模板任何复杂搜索场景均可从容应对。总结复杂搜索的难点并非技术实现而在于1.查询条件不断累积导致字段膨胀2.业务逻辑分散且重复难以维护3.每次开发均从零开始效率低下4.代码逐渐演变为难以管理的条件判断堆砌。通过本文介绍的动态查询模板您可将搜索逻辑标准化、模块化从而显著提升代码质量与开发效率。来源小程序app开发|ui设计|软件外包|IT技术服务公司-木风未来科技-成都木风未来科技有限公司