- 浏览: 118583 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
IAmMrLi:
...
基于HIBERNATE的全自动查询框架(二) -
ganbo:
...
基于HIBERNATE的全自动查询框架(二) -
ganbo:
...
基于HIBERNATE的全自动查询框架(二) -
wanbing1986:
给我一份借鉴下wanbing1986@126.com,谢谢
基于HIBERNATE的全自动查询框架(一) -
Cynthia9023:
博主我也没有权限下载 能否也发我一份?jane9023@163 ...
基于HIBERNATE的全自动查询框架(一)
欢迎加入阿里,有兴趣的发邮件给我fuqu.lgd@alibaba-inc.com, java技术体系好就行,具体要求不再这里发,怕屏蔽
这个框架最重要的代码是自动拼装条件部份,本篇主要对拼装条件工具类入口类的代码进行讲解,首先是本框架的方法调用时序图
下面是自动拼装条件工具类的入口
下面来看看DetachedCriteriaUtil工具类,这是自动封装查询条件的总入口,此工具首先根据POJO类和别名创建出DetachedCriteria对象,然后从请求中循环地分析出需要的查询参数,并格式化成字符串,然后通过“标装条件构造器”拼每个查询条件,最后拼装DetachedCriteria查询器中,本类主要的逻辑在于createDetachedCriteria和getCriterion方法,其它方法只要知道他们是干什么用的就行,代码:
下一篇分析标准条件构造器
这个框架最重要的代码是自动拼装条件部份,本篇主要对拼装条件工具类入口类的代码进行讲解,首先是本框架的方法调用时序图
下面是自动拼装条件工具类的入口
public List findByAutoConditionByLimit(Pagin pagin,Class<? extends BaseModel> pojoClass,String startChar,String[] columName,String[] excludeParameters,List<Criterion> customConditions, String alias) { //框架的核心在这里,自动生成HIBERNATE的查询对象 DetachedCriteria criteria = DetachedCriteriaUtil.createDetachedCriteria(pojoClass,startChar,excludeParameters,alias); ....... //这里开始查询,根据查询对象封装的分页查询 return findByDetachedCriteria(....); }
下面来看看DetachedCriteriaUtil工具类,这是自动封装查询条件的总入口,此工具首先根据POJO类和别名创建出DetachedCriteria对象,然后从请求中循环地分析出需要的查询参数,并格式化成字符串,然后通过“标装条件构造器”拼每个查询条件,最后拼装DetachedCriteria查询器中,本类主要的逻辑在于createDetachedCriteria和getCriterion方法,其它方法只要知道他们是干什么用的就行,代码:
package com.esc.common.util; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.hibernate.FetchMode; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Expression; import org.hibernate.criterion.Projection; import org.hibernate.criterion.ProjectionList; import org.hibernate.criterion.Projections; import org.hibernate.transform.Transformers; import com.esc.common.baseclass.BaseModel; import com.esc.common.hibernate.resulttranformer.EscAliasToBean; import com.esc.common.util.conditionbuilder.ConditionBuilder; import com.esc.common.util.conditionbuilder.StandardConditionBuilder; /** * 拼装Hibernate条件 */ public class DetachedCriteriaUtil { /** 小写字母X */ public static final String MIDDLE_SEPRATOR_CHAR = "x"; /** 两个空格 */ public static final String SEPARATOR_TWO_SPACE = " ";// 两个空格,避免和"日期 // 时间"中的空格混淆 /** 此字符串内容为" <= x <= ",不包括引号 */ public static final String COMPLETE_SEPARATOR = SEPARATOR_TWO_SPACE + Operator.LE + SEPARATOR_TWO_SPACE + MIDDLE_SEPRATOR_CHAR + SEPARATOR_TWO_SPACE + Operator.LT + SEPARATOR_TWO_SPACE; private DetachedCriteriaUtil() { // do not allow to create Object } /** 标准条件构造器,核心中的核心 */ private static final ConditionBuilder cb = new StandardConditionBuilder(); /** * 自动拼装条件 * * @param pojoClazz * 实体类名 * @param startChar * 参数统一的开始字符 * @param alias * 别名 * @return */ public static DetachedCriteria createDetachedCriteria(Class pojoClazz, String startChar, String alias) { return createDetachedCriteria(pojoClazz, startChar, null, alias); } /** * 自动拼装条件 2008-11-3 * * @param pojoClazz * 实体类名 * @param startChar * 参数前辍 * @param excludeParameters * 不作为查询条件的参数 * @param alias * 别名 * @return */ public static DetachedCriteria createDetachedCriteria(Class pojoClazz, String startChar, String[] excludeParameters, String alias) { // 需要回传的参数,前台写成了name="userBean.sysUser.name|userBean.sysUser.realName"的参数, // 通过处理,可出使用第一个名字取回值 Map<String, String> postBackParameters = null; // 这个字符串很重要,它将决定那些以它开头的参数被处理,其它不被处理 String newStartChar = new StringBuilder(startChar).append(POINT) .toString(); // 创建DetachedCriteria DetachedCriteria criteria = DetachedCriteria.forClass(pojoClazz, alias); // 取得当前请求 HttpServletRequest request = SysContext.getRequest(); // 取得所有请求参数 Enumeration parameterNames = request.getParameterNames(); // 创建alias集合,主要不为了不重复创建alias Set<String> aliases = getAliasesFromRequest(); // 查询条件是否包括当前正在处理的参数,如果检测到当前参数被排除了,设为FALSE boolean includeThisParameter = true; // 循环所有参数,拼装条件 while (parameterNames != null && parameterNames.hasMoreElements()) { // 按顺序取得参数名 String propName = parameterNames.nextElement().toString(); // 取得参数值 String[] propValue = request.getParameterValues(propName); // 只处理newStartChar开头的参数 if (propName.startsWith(newStartChar) && !CollectionUtils.isStringArrayEmpty(propValue)) { // 让下面的方法返回Criterion对象,在这里进行拼装 if (propName.contains("|")) {// 组装很多OR String[] keys = propName.split("\\|"); List<Criterion> criterions = new ArrayList<Criterion>( keys.length); for (String key : keys) { // getCriterion返回单个的Criterion对象 criterions.add(getCriterion(key, startChar, propValue, criteria, cb, alias, pojoClazz, aliases)); } addAndToCriteria(criteria, assembleOr(criterions)); if (postBackParameters == null) { // 这里把请求中pojo.bb|pojo.cc参数换个EL表达式能接受的名,传回到REQUEST中,用于回显,AJAX查询的话这里就不需要了 postBackParameters = new HashMap<String, String>(5); } postBackParameters.put(keys[0], StringUtil .getLinkString(propValue)); } else {// 组装单个and // 要先判断此参数是否被用户排除在外了, includeThisParameter = true; if (excludeParameters != null && excludeParameters.length > 0) { for (int i = 0; i < excludeParameters.length; i++) { if (propName != null && propName.equals(excludeParameters[i])) { includeThisParameter = false;// 确实排除了 } } } if (includeThisParameter) // 不被排除的参数名 addAndToCriteria(criteria, getCriterion(propName, startChar, propValue, criteria, cb, alias, pojoClazz, aliases)); } } } // 设置回传参数 setPostBackParameter(postBackParameters); return criteria; } /** * 组装条件 * * @param propName * 带前辍的属性名 * @param startChar * 属性名的前辍 * @param propValue * 属性值 * @param criteria * HIBERNATE条件对象 * @param cb * 条件生成器 * @param alias * 别名 * @param pojoClazz * POJO类 * @return Criterion 条件对象 */ private static Criterion getCriterion(String propName, String startChar, String[] propValue, DetachedCriteria criteria, ConditionBuilder cb, String alias, Class pojoClazz, Set<String> aliases) { //从pojo.aaa.bb参数名中,取出非前辍部份,即aaa.bb String key = propName.substring(startChar.length() + 1, propName .length()); if (key.contains(POINT)) {// 如果还包含点号,即当前pojo属性中的属性,即级联了其它表进行查询 //找个地方记住本次查询不是单表查询,而是级连了其它表的查询,最好的地方是放入请求 setHasJoinTatleToRequest(SysContext.getRequest(), true); //选把别名创建好,HIBERNATE级联其它表进行查询时,对象属性要创建别名才行 String[] keys = key.split("\\."); createAlias(criteria, alias, aliases, keys, 0); } if (propValue.length > 1) {// 一个属性有两个值,即JSP页面有两个输入框采用了同一个名字,如通过创建时间查询时,就需要输入区间了 StringBuilder sb = new StringBuilder(30); //把这两个值拼成 aaa <= x <= bbb的字符串 sb.append(propValue[0].trim()).append(COMPLETE_SEPARATOR).append(propValue[1]); //通过标准条件构造器拼装 return cb.parseToCriterion(key, sb.toString(), pojoClazz, alias); } else {// 一个属性单个值 //通过标准条件构造器拼装 return cb.parseToCriterion(key, propValue[0], pojoClazz, alias); } } private static final String ALIAS_KEY_IN_REQUEST = "ALIAS_KEY_IN_REQUEST"; private static final String HAS_JOIN_TABLE_KEY_IN_REQUEST = "HAS_JOIN_TABLE_KEY_IN_REQUEST"; private static void setAliasToRequest(HttpServletRequest request, Set<String> aliases) { request.setAttribute(ALIAS_KEY_IN_REQUEST, aliases); } public static Set<String> getAliasesFromRequest() { Set<String> aliases = (Set<String>) SysContext.getRequest() .getAttribute(ALIAS_KEY_IN_REQUEST); if (aliases == null) { aliases = new HashSet<String>(5); setAliasToRequest(SysContext.getRequest(), aliases); } return aliases; } /** * 为类似于name="userBean.sysUser.name|userBean.sysUser.realName"的参数设置回传值 * * @param parameters */ private static void setPostBackParameter(Map<String, String> parameters) { if (parameters != null) { Set<String> keySet = parameters.keySet(); HttpServletRequest request = SysContext.getRequest(); for (String key : keySet) { String[] keys = key.split("\\."); request .setAttribute(keys[keys.length - 1], parameters .get(key)); } } } private static void setHasJoinTatleToRequest(HttpServletRequest request, boolean hasJoin) { request.setAttribute(HAS_JOIN_TABLE_KEY_IN_REQUEST, hasJoin); } private static boolean getHasJoinTatleFromRequest() { Boolean hasJoin = (Boolean) SysContext.getRequest().getAttribute( HAS_JOIN_TABLE_KEY_IN_REQUEST); return hasJoin == null ? false : hasJoin; } /** * 把集合里所有条件组装OR * * @param criterions * 待组装成OR的条件集合 * @return 组装好的条件 */ public static Criterion assembleOr(List<Criterion> criterions) { if (criterions == null || criterions.size() == 0) return null; Criterion result = null; for (Criterion criterion : criterions) { if (criterion == null) continue; if (result == null) { result = criterion; } else { result = Expression.or(result, criterion); } } return result; } /** * 增加与条件 * * @param criteria * @param criterion */ public static void addAndToCriteria(DetachedCriteria criteria, Criterion criterion) { if (criterion != null) criteria.add(criterion); } /** * 该方法提供DetachedCriteria对查询字段的封装可支持无限级联取部分字段,如取如下字段 * user.organization.parentOrganization.parentOrganization.orgName 但请注意1点 * ,连接采用内联,级联越多,结果集可能就越少; * * @param columnNames * 字符串数组,以数据的形式接收要查询的字段属性,如String[] column={"属性1","属性2","属性3"}; * @param pojoClass * 实体类的Class,如Mobile.class; * @param aials * 为要查询的POJO对象指定一个别名 * @return DetachedCriteria 的一个对象,如果需要查询条件,在些对象后追加查询条件。 * * @param forJoinTable * 是否多表连接查询 */ public static void selectColumn(DetachedCriteria criteria, String[] columnNames, Class<? extends BaseModel> pojoClass, String rootAlias, boolean forJoinTable) { if (null == columnNames) { return; } // 使用这个临时变量集合,是因为dinstinct关键字要放在最前面,而distinct关键字要在下面才决定放不放, List<Projection> tempProjectionList = new ArrayList<Projection>(); Set<String> aliases = getAliasesFromRequest(); boolean hasJoniTable = false; for (String property : columnNames) { if (property.contains(POINT)) { String[] propertyChain = property.split("\\."); createAlias(criteria, rootAlias, aliases, propertyChain, 0); tempProjectionList .add(Projections.property( getAliasFromPropertyChainString(property)).as( property)); hasJoniTable = true; } else { tempProjectionList.add(Projections.property( rootAlias + POINT + property).as(property)); } } ProjectionList projectionList = Projections.projectionList(); if (hasJoniTable || forJoinTable || getHasJoinTatleFromRequest()) {// 这个一定要放在tempProjectionList的前面,因为distinct要在最前面 projectionList.add(Projections.distinct(Projections.id())); } for (Projection proj : tempProjectionList) { projectionList.add(proj); } criteria.setProjection(projectionList); if (!hasJoniTable) { criteria.setResultTransformer(Transformers.aliasToBean(pojoClass)); } else { criteria.setResultTransformer(new EscAliasToBean(pojoClass)); } } private static final String POINT = "."; /** * 创建别名 * * @param criteria * @param rootAlais * @param aliases * @param columns * @param currentStep */ public static void createAlias(DetachedCriteria criteria, String rootAlais, Set<String> aliases, String[] columns) { if (columns == null) { return; } for (String column : columns) { createAlias(criteria, rootAlais, aliases, column.split("\\."), 0); } } /** * 创建别名 * * @param criteria * @param rootAlais * @param aliases * @param columns * @param currentStep */ private static void createAlias(DetachedCriteria criteria, String rootAlais, Set<String> aliases, String[] columns, int currentStep) { if (currentStep < columns.length - 1) { if (!aliases.contains(converArrayToAlias(columns, currentStep))) { if (currentStep > 0) { criteria.createAlias( converArrayToAlias(columns, currentStep - 1) + POINT + columns[currentStep], converArrayToAlias(columns, currentStep)) .setFetchMode(columns[currentStep], FetchMode.JOIN); } else { criteria.createAlias( rootAlais + POINT + columns[currentStep], converArrayToAlias(columns, currentStep)) .setFetchMode(columns[currentStep], FetchMode.JOIN); } aliases.add(converArrayToAlias(columns, currentStep)); } currentStep++; createAlias(criteria, rootAlais, aliases, columns, currentStep); } } /** * 从"organization.parentOrganization.parentOrganization.parentOrganization.id" * 得到 * "organization_parentOrganization_parentOrganization_parentOrganization.id" * * @param property * @return */ public static String getAliasFromPropertyChainString(String property) { if (property.contains(".")) { return property.substring(0, property.lastIndexOf(POINT)) .replaceAll("\\.", "_") + property.substring(property.lastIndexOf(POINT)); } return property; } /** * 从数组中创建ALIAS * * @param columns * @param currentStep * @return */ private static String converArrayToAlias(String[] columns, int currentStep) { StringBuilder alias = new StringBuilder(); for (int i = 0; i <= currentStep; i++) { if (alias.length() > 0) { alias.append("_"); } alias.append(columns[i]); } return alias.toString(); } }
下一篇分析标准条件构造器
发表评论
-
一个很方便的Hibernate自动拼装条件工具类
2010-03-18 20:43 3510每做一个新的模块都要写一大堆组装查询条件的逻辑代码,不小心有一 ... -
hibernate的一个BUG
2010-03-02 20:03 1717BUG简单描述:在Criteria ... -
基于HIBERNATE的全自动查询框架(四)
2009-10-24 17:51 1898这是全自动查框架最后一篇,主要讲解上一篇中最后提到的各种类型的 ... -
基于HIBERNATE的全自动查询框架(三)
2009-10-13 22:17 3176本篇讲解“标准条件处理器”,此处理器实现了ICondition ... -
如何干预HIBERNATE二级缓存
2009-09-24 21:04 2659此文的目的只是想把HIBERNATE缓存和应用的 ... -
基于HIBERNATE的全自动查询框架(一)
2009-09-23 18:48 2367本文讨论如何实现 ... -
使用HIBERNATE的SQL查询并将结果集自动转换成POJO
2009-09-21 11:08 42045在某些场合下,我们可能想使用HIBERNATE的框架提供的SQ ... -
使用HIBERNATE的DetachedCriteria无限级联取部份字段的查询结果集转换
2009-09-20 23:26 9282--后记,本文所讲的实 ...
相关推荐
在这个物流系统中,Hibernate用于将业务对象(如订单、货物、客户等)映射到数据库表,通过SQL查询操作数据,而无需直接编写大量的SQL语句,提高了开发效率和代码的可维护性。 2. **Spring**:Spring是Java企业级...
【标题】:基于Hibernate和SpringMVC框架的小型书店管理网站S 【描述】:小型书店管理网站是一个常见的Web应用程序示例,它利用了Hibernate和SpringMVC这两个强大的开源框架。Hibernate是Java领域中广泛使用的对象...
本教程将详细阐述如何利用MyEclipse10,一个强大的Java EE集成开发环境,搭建一个基于Struts2.1、Spring3.3和Hibernate3.3的全注解框架。这种框架被称为SSH2,因为它包含了Struts2、Spring和Hibernate这三大主流Java...
14. **第二代API(Hibernate Annotations)**:Hibernate 4.0.0引入了基于Java注解的配置方式,使得代码更加简洁,减少了XML配置文件的依赖。 15. **Hibernate Tools**:包括Hibernate逆向工程工具,可以自动生成...
《基于Hibernate,Spring,Spring MVC,Bootstrap框架的管理系统详解》 在现代企业级应用开发中,选择合适的框架能够显著提高开发效率,降低维护成本。本文将深入探讨一个基于Hibernate、Spring、Spring MVC以及...
**基于Struts+Hibernate的网上问卷调查系统** 在IT领域,构建一个网上问卷调查系统是一项常见的任务,它能够帮助企业、研究机构或者个人收集用户数据,进行统计分析。本项目采用Struts2作为前端MVC框架,Hibernate...
此外,它还可以生成基于Hibernate的DAO(数据访问对象)层,进一步提高了开发效率。 接下来是hibernate-annotations-3.3.0.GA,这是Hibernate 3.x系列的一个版本,包含了Hibernate的注解支持。在Java中,注解是一种...
基于Spring+SpringMVC+Hibernate的全注解开发,允许开发者摆脱传统的XML配置文件,转而使用注解来实现组件的配置,大大简化了开发流程,提高了开发效率。 **Spring框架** 是一个全面的后端应用管理框架,它提供了...
Smart框架是一种基于SpringMVC、Spring和Hibernate的整合框架,旨在简化企业级Web应用的开发工作。这个框架利用了Maven进行项目管理和构建,确保了依赖管理的有效性和一致性。通过集成这些主流的技术栈,Smart提供了...
本项目是一个基于Spring、Spring MVC、Hibernate和Material前端框架构建的简单BBS论坛系统,旨在为初学者提供一个学习和实践这些技术的平台。在这个系统中,你可以看到如何将Java后端技术和现代化的前端设计结合,以...
总的来说,"jsp+Struts+hibernate基本框架搭建demo"是一个典型的Java Web应用开发实践,涵盖了前端展示、后端控制和数据库操作的全过程。通过这样的示例,开发者可以学习到如何在实际项目中有效地组织代码和配置,...
**基于全注解的SSH2框架详解** SSH2框架,即Spring、Struts2和Hibernate的集成,是Java开发Web应用程序的主流框架之一。在这个基于全注解的SSH2框架中,我们将深入探讨如何利用注解来简化配置,提高开发效率,并...
以下将详细阐述这三个框架的核心功能和它们在OA(办公自动化)项目中的应用。 **Struts2框架** Struts2是一个基于MVC(Model-View-Controller)设计模式的Web应用框架,它主要负责控制层。Struts2通过拦截器机制...
**二、Spring:全方位的应用程序框架** Spring是Java领域中最为广泛应用的框架之一,它提供了依赖注入(DI)、面向切面编程(AOP)、MVC、数据访问/集成、事务管理等多种功能。在Jeesite中,Spring扮演着核心的角色...
查询房源则可以使用`Query`或`Criteria` API,通过HQL(Hibernate Query Language)或SQL编写查询语句。 进一步地,租房系统可能需要处理复杂的业务逻辑,比如租赁合同的签订和管理。这可能涉及到多个实体间的关联...
- **自动化的持久化操作**:Hibernate能够自动生成大部分SQL语句,大大减轻了开发者的负担。 - **支持多种数据库**:Hibernate支持多种关系型数据库,包括MySQL、Oracle、SQL Server等,使得迁移变得容易。 - **强大...
【描述】"基于hibernate5 泛型Dao实例,下载后改一下数据库配置直接可以用",意味着这个压缩包文件提供了一个已经实现好的Hibernate5版本的泛型Dao示例项目。用户只需要根据自己的数据库环境修改相应的配置信息,就...
Spring框架则是一个全方位的应用框架,它不仅提供了依赖注入(DI)和面向切面编程(AOP)的功能,还集成了大量的其他框架,如数据访问、事务管理等。在人力资源管理系统中,Spring作为整体的容器,管理着所有bean的...