今天花了N个小时做了一个现在看来十分简单明了的重构,目的是少写点代码,原因嘛,自然是万恶的需求变更。
原始代码(操作的是mongo,使用spring-data):
public static void buildCountryChannelCriteria(String country, String channel, Query q) { //查询推广至全球以及包含参数country的app Criteria countryC = new Criteria(); if (!StringUtils.isBlank(country)) { countryC.orOperator(Criteria.where("countries").exists(false),Criteria.where("countries." + (country.toUpperCase())).exists(true)); } else {//国家未知 则只查询推广至全球的 countryC.and("countries").exists(false); } Criteria channelC = new Criteria(); //查找推荐至全部渠道以及指定渠道的app if (!StringUtils.isBlank(channel)) { channelC.orOperator(Criteria.where("channels").exists(false), Criteria.where("channels." + channel).exists(true)); } else {//渠道未知 则只查询推广至全渠道的 channelC.and("channels").exists(false); } q.addCriteria(new Criteria().andOperator(countryC, channelC)); }
代码很简单,拼接country和channel的Criteria,二者都有可能包含或操作(orOperator),跟sql中or查询使用括号括起or操作来避免错误的查询一样,这里使用new Criteria().andOperator来对两个or操作进行and。
该方法被多个外部方法调用,新需求中,外部方法也有类似or之类的操作,最开始自己设想是这样的:
public static void buildCountryChannelCriteria(String country, String channel, Query q) { //...ommit buildCountryChannelCriteria(String country, String channel, Query q, null);//调用重构后的方法 } public static void buildCountryChannelCriteria(String country, String channel, Query q, Criteria existedAndCriteria) { //...ommit q.addCriteria(existedAndCriteria.andOperator(countryC, channelC)); }
可不幸的是:Due to limitations of the com.mongodb.BasicDBObject, you can't add a second 'null' criteria. Mongo查询中貌似只允许存在一个"$and"查询属性,上面的代码中existedAndCriteria在外部方法中已经有了一个$and查询属性,再次调用andOperator时就报错了.......
纠结N就之后,决定把外部包含or操作的Criteria传递进来,然后在该方法中将外部的Criteria一并传递给andOperator方法,于是问题又来了,andOperator这货接受的参数是可变参数Criteria...,不过可变参数自己平时用的也很少,所以在究竟如何传参和类型转换上纠结了下。
最终还是重构完成了。对于可变参数主要丰富了以下两点:
①外部调用的时候可以传入list,然后使用list.toArray(new Criteria[list.size()])将list转换为数组,数组可以直接作为可变参数对象传递给andOperator方法(andOperator(new Criteria[]{})这样调用是ok的)。
②自己在最终实现时,外部调用传入的也是可变参数,可变参数转换成list可以使用java.util.Arrays.asList(Object[])方法,可以将传入的可变参数直接当做数组传递进去(可变参数和数组可以直接互转?这点还需要深入了解下)。这样做还有个明显的好处就是,不需要保留旧的接口了,直接调用新接口时可变参数部分可以不指定,也就是说外部方法什么都不用改了。甚好。
不过需要注意的是,asList返回的是固定长度的list,不能add,所以需要将其返回值赋给一个新array
最终代码:
/** * 拼接country和channel的查询语句<br> * @param country * @param channel * @param q * @param criterias4And 其他需要添加至andOperator的语句子句 */ public static void buildCountryChannelCriteria(String country, String channel, Query q, Criteria... criterias4And) { //查询推广至全球以及包含参数country的app Criteria countryC = new Criteria(); if (!StringUtils.isBlank(country)) { countryC.orOperator(Criteria.where("countries").exists(false),Criteria.where("countries." + (country.toUpperCase())).exists(true)); } else {//国家未知 则只查询推广至全球的 countryC.and("countries").exists(false); } Criteria channelC = new Criteria(); //查找推荐至全部渠道以及指定渠道的app if (!StringUtils.isBlank(channel)) { channelC.orOperator(Criteria.where("channels").exists(false), Criteria.where("channels." + channel).exists(true)); } else {//渠道未知 则只查询推广至全渠道的 channelC.and("channels").exists(false); } //组合外部条件和内部条件 List<Criteria> cList = new ArrayList<Criteria>(0); if (null!=criterias4And && criterias4And.length>0) { cList.addAll(Arrays.asList(criterias4And));//Arrays.asList 长度不可变 所以addAll } cList.add(countryC); cList.add(channelC); q.addCriteria(new Criteria().andOperator(cList.toArray(new Criteria[cList.size()]))); } //外部调用依旧是: buildCountryChannelCriteria(country, channel, q);
相关错误链接参考:http://www.mkyong.com/java/due-to-limitations-of-the-basicdbobject-you-cant-add-a-second-and/
相关推荐
成为顶尖Javaer - Java工程师成神之路 主要版本 更新时间 备注 v4.0 2022-05-20 知识体系完善,知识点补充 v3.0 2020-03-31 知识体系完善,在v2.0的基础上,新增20%左右的知识点 调整部分知识的顺序及结构,方便...
toBeTopJavaer,成为Javaer-JavaSouthType.zip
javaer-roadmap Github上已经有很多 java及周边技术的优秀项目,发现深度有余,广度不足。所以本项目不在深度上继续扩展,而在广度上给大家分享一些当前职场火热的技术导航。其中包括相关的、书籍、资料、网站等。...
讲述如何在程序中避免程序缺陷和程序陷阱的,解惑的过程中,介绍了一些Java编程语言中许多不易被掌握的知识点,其阅读价值非常高,适合具有Java知识的学习者和有编程经验的Java程序员阅读。
8. **搜索邮件**:使用查询参数进行高级搜索,如`from:example@example.com subject:example`。 9. **邮件元数据**:获取邮件的ID、主题、发件人、收件人、日期等信息。 10. **邮件处理**:删除、移动邮件到特定...
【软工1503-Javaer 集-信息盾-用户需求说明书-V1-201909281】文档描述了一个旨在保护快递业务中用户隐私的项目——"信息盾"。该项目主要关注如何在快递过程中保护用户的个人隐私信息,如姓名、电话和地址等,以防止...
语音日记功能则让记录变得更加方便,只需录入语音即可完成日记撰写。分享功能让用户能将日记轻松分享到微信、微博、QQ等社交平台,增进人际交流。 此外,日记的云端存储确保了数据的安全,用户可通过登录账户同步...
成为Javaer的榜首-Java工程师成神之路主要版本更新时间备注v3.0 2020-03-31知识体系完善,在v2.0的基础上,再增加20%左右的知识点调整部分知识的顺序及结构,方便阅读和理解通过GitHub Page构建,方便阅读v2.0 2019...
互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术...
在当今数字化时代,电子日记本逐渐取代了传统的纸质日记,成为人们记录生活、表达情感的新选择。本文档详细阐述了一个专为安卓用户设计的电子日记本软件的开发需求,旨在提供一个集文字记录、图片插入、心情标注、...
服务器提供信息存储和管理服务,用户通过身份验证后可操作其日记信息。 综上所述,这个电子日记本系统旨在提供一个安全、便捷、个性化的日记记录和分享平台,满足现代用户记录生活、表达情感的需求。开发团队需要...
点击关注及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。 作者的其他开源项目推荐: : 适合新手入门以及有经验的开发人员查阅的 Spring Boot 教程(业余时间维护...
通用语言 Java程序员编写的类似common-lang工具包包名就是要用大驼峰,不想改成go规范的包名。... string)布尔IsAnyEmpty(list ... string)布尔IsAnyNoneEmpty(list ... string)布尔IsBlank(str字符串)bool ...
后端javaer的福音!这是一个基于vue-element-admin的基础模板vue-admin-template改造+简化而来(例如,加入了标签导航,国际化等等),可以让非专业前端的javaer快速上手的前后端分离项目(前端部分),相信你在日常开发...
2. **Java并发编程**:随着多核处理器的普及,Java并发编程变得尤为重要。这个主题会讲解线程、同步机制(如synchronized、Lock接口)、并发工具类(如ExecutorService、Semaphore、CountDownLatch)、并发集合(如...
此外,了解行业动态和最新技术趋势,如Java 8及以上版本的新特性,能帮助你在面试中脱颖而出。 通过这个压缩包的学习,你将能够系统地掌握Java编程,理解并应用并发编程,优化JVM,参与企业级项目开发,并具备应对...
JarClassSearch class 文件搜索工具,可以查找出指定名称的class出现了那些jar包中 对jar包上了数量的工程特别有用,而且是GUI界面的 真是人见人爱,见人爱人,javaer 的居家旅行必备
产品设计主要工作流程是任何成功产品背后不可或缺的一部分。这一流程旨在确保从概念到最终产品的转换过程中,用户体验、功能性和效率得到充分的关注。以下是对产品设计流程的详细解释: 首先,产品经理(PM)负责...
欢迎新老Javaer一同交流. 如果感觉有用, 请star支持一下~ 意见和建议请开issue交流. 欢迎fork并提出pr共同建设 :) 本项目使用方法 本项目以文件形式组织, 请直接下载对应的xmind文件到本地. 后续会陆续完善文件组织...
oo,面向对象,通过继承代码量显著减少 JXTree里的... } 目前只能设计为16px,浏览器默认的大小 望高手解答,感激不尽 演示地址:http://javaer.3322.org/phy/jxtree.html[局域网上网,不知道能不能连上] 文件下载:JXTr