
1. 项目概述VueSpringBootMyBatis实现动态条件检索去年在开发一个电商后台管理系统时我遇到了一个典型的需求需要根据不同角色运营、客服、管理员配置不同的数据筛选条件。比如运营需要按促销活动筛选商品客服需要按投诉状态筛选订单。这个需求本质上就是要实现动态条件检索功能。经过技术选型最终采用VueSpringBootMyBatis这套经典组合来实现。前端用Vue构建灵活的查询表单后端通过SpringBoot提供RESTful接口MyBatis处理动态SQL生成。这种架构既保持了前后端分离的优势又能充分发挥各框架的特性。2. 技术方案设计2.1 前端Vue组件设计前端采用组合式API写法核心是一个可动态添加条件的查询表单组件template div classquery-builder div v-for(condition, index) in conditions :keyindex select v-modelcondition.field option v-forfield in availableFields :valuefield.value {{ field.label }} /option /select select v-modelcondition.operator option value等于/option option value大于/option option value小于/option option valueLIKE包含/option /select input v-modelcondition.value / button clickremoveCondition(index)删除/button /div button clickaddCondition添加条件/button button clicksubmitQuery查询/button /div /template script setup import { ref } from vue const conditions ref([]) const availableFields ref([ { value: productName, label: 商品名称 }, { value: price, label: 价格 }, { value: stock, label: 库存 } ]) const addCondition () { conditions.value.push({ field: , operator: , value: }) } const removeCondition (index) { conditions.value.splice(index, 1) } const submitQuery async () { const response await fetch(/api/search, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify(conditions.value) }) // 处理返回结果 } /script这个组件实现了动态添加/删除查询条件支持多种运算符选择将查询条件以JSON格式发送到后端2.2 后端SpringBoot接口设计后端接收前端传递的条件数组处理后返回查询结果RestController RequestMapping(/api) public class SearchController { Autowired private ProductMapper productMapper; PostMapping(/search) public ResponseEntityListProduct searchProducts( RequestBody ListSearchCondition conditions) { ListProduct products productMapper.searchByConditions(conditions); return ResponseEntity.ok(products); } } Data public class SearchCondition { private String field; private String operator; private String value; }2.3 MyBatis动态SQL实现MyBatis的XML映射文件中使用动态SQL处理条件组合select idsearchByConditions resultTypeProduct SELECT * FROM products where foreach collectionconditions itemcondition choose when testcondition.operator AND ${condition.field} #{condition.value} /when when testcondition.operator AND ${condition.field} #{condition.value} /when when testcondition.operator AND ${condition.field} #{condition.value} /when when testcondition.operator LIKE AND ${condition.field} LIKE CONCAT(%, #{condition.value}, %) /when /choose /foreach /where /select这里有几个关键点使用where标签自动处理WHERE子句foreach遍历所有条件choose根据运算符生成不同的SQL片段${}用于字段名#{}用于参数值3. 高级功能实现3.1 条件分组与逻辑组合实际项目中我们经常需要实现更复杂的条件组合比如(A AND B) OR (C AND D)。这需要扩展我们的数据结构Data public class ConditionGroup { private String logic; // AND/OR private ListSearchCondition conditions; private ListConditionGroup groups; }对应的MyBatis映射也需要调整select idsearchByConditionGroups resultTypeProduct SELECT * FROM products where foreach collectiongroups itemgroup separator OR trim prefix( suffix) foreach collectiongroup.conditions itemcondition separator AND !-- 条件处理逻辑同上 -- /foreach if testgroup.groups ! null and group.groups.size() 0 !-- 递归处理子组 -- /if /trim /foreach /where /select3.2 安全性考虑直接使用${}拼接字段名存在SQL注入风险。我们可以通过白名单校验来防范public class FieldValidator { private static final SetString ALLOWED_FIELDS Set.of( productName, price, stock, category ); public static boolean isValidField(String field) { return ALLOWED_FIELDS.contains(field); } }在Service层进行校验public ListProduct searchSafely(ListSearchCondition conditions) { for (SearchCondition condition : conditions) { if (!FieldValidator.isValidField(condition.getField())) { throw new IllegalArgumentException(Invalid field: condition.getField()); } } return productMapper.searchByConditions(conditions); }3.3 性能优化当数据量大时动态条件查询可能性能不佳。可以考虑以下优化措施为常用查询字段添加索引使用MyBatis的二级缓存对复杂查询实现分页使用if标签避免生成不必要的条件例如实现分页查询select idsearchByConditionsWithPage resultTypeProduct SELECT * FROM products where !-- 条件处理 -- /where LIMIT #{page.offset}, #{page.size} /select4. 常见问题与解决方案4.1 MyBatis特殊字符转义在MyBatis的XML中像,等符号需要转义when testcondition.operator lt; AND ${condition.field} lt; #{condition.value} /when或者使用CDATA区块when testcondition.operator ![CDATA[ AND ${condition.field} #{condition.value} ]] /when4.2 空值处理当条件值为空时可能需要特殊处理when testcondition.value null or condition.value choose when testcondition.operator AND ${condition.field} IS NULL /when when testcondition.operator ! AND ${condition.field} IS NOT NULL /when /choose /when4.3 日期类型处理对于日期类型的字段需要特殊处理Data public class SearchCondition { private String field; private String operator; private String value; private String valueType; // STRING, NUMBER, DATE }在MyBatis中when testcondition.valueType DATE AND DATE(${condition.field}) ${condition.operator} DATE(#{condition.value}) /when5. 项目扩展思路在实际项目中我们可以进一步扩展这个基础功能保存查询方案允许用户保存常用的查询条件组合字段类型感知根据字段类型自动选择合适的运算符可视化查询构建器提供更友好的界面来构建复杂查询与Vuex/Pinia集成在状态管理中保存查询状态后端缓存对常见查询结果进行缓存例如保存查询方案的实现Entity public class SavedQuery { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String name; private String userId; Column(columnDefinition TEXT) private String conditionJson; // getters and setters }6. 项目部署与测试6.1 前端部署使用Vue CLI构建生产版本npm run build然后将生成的dist目录内容部署到Nginx或其它Web服务器。6.2 后端部署SpringBoot应用可以打包为JAR直接运行mvn package java -jar target/your-application.jar或者使用Docker容器化部署FROM openjdk:17-jdk-slim COPY target/your-application.jar app.jar ENTRYPOINT [java,-jar,/app.jar]6.3 接口测试使用Postman测试接口创建POST请求到/api/search设置HeaderContent-Type: application/jsonBody示例[ { field: productName, operator: LIKE, value: 手机 }, { field: price, operator: , value: 1000 } ]7. 性能监控与优化在实际运行中我们需要监控查询性能使用Spring Boot Actuator暴露指标配置MyBatis日志打印SQL语句使用Prometheus Grafana监控性能在application.properties中配置# 启用MyBatis SQL日志 logging.level.org.mybatisDEBUG # 启用Actuator management.endpoints.web.exposure.includehealth,metrics,prometheus management.metrics.tags.applicationmy-application8. 项目总结与经验分享在实现这个功能的过程中我积累了一些有价值的经验前后端协作定义清晰的数据结构接口非常重要。我们使用TypeScript接口和Java DTO保持一致性。动态SQL复杂度MyBatis的动态SQL能力很强但过于复杂的逻辑会使XML难以维护。可以考虑将特别复杂的逻辑移到Java代码中使用MyBatis Provider注解方式合理拆分Mapper方法分页实现对于大数据量查询分页是必须的。我们最终采用了MyBatis PageHelper插件PageHelper.startPage(pageNum, pageSize); ListProduct products productMapper.searchByConditions(conditions); PageInfoProduct pageInfo new PageInfo(products);前端体验优化添加加载状态指示器实现防抖搜索300ms延迟缓存常用查询结果安全加固对所有前端传入参数进行校验限制最大查询条件数量实现查询超时机制这个自定义条件检索功能虽然不算复杂但涵盖了前后端协作的许多关键点。通过这个项目我对Vue的组合式API、SpringBoot的RESTful设计以及MyBatis的动态SQL有了更深入的理解。特别是在处理复杂条件组合时如何平衡灵活性和安全性是一个需要不断思考的问题。