论坛首页 Java企业应用论坛

查询框架

浏览 9257 次
锁定老帖子 主题:查询框架
精华帖 (2) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (2)
作者 正文
   发表时间:2010-12-23   最后修改:2010-12-23
先定义一个枚举,配置条件查询是什么类型的,like = 还是between and。目前实现的是这三种

-------------------------------------------------------------------------

public enum CType {
    like,equal,between
}


-------------------------------------------------------------------------

定义annotation,用于注解在字段上面


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConditionType {
    CType value();
    String andField() default "";
    String queryField() default "";
}

-------------------------------------------------------------------------

根据bean的字段注解生成查询语句


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;


public class HqlCreator {

   
    public static void createHql(StringBuilder hql,Object object,List<Object> params)
    {
        try {
            //加载class
            Class clazz=object.getClass();
           
            //获取私有字段
            Field[] fields=clazz.getDeclaredFields();
           
            //遍历字段
            for (Field field : fields) {
               
                //如果字段上有 ConditionType 的注解
                if(field.isAnnotationPresent(ConditionType.class))
                {
                    //获取注解的value值
                    ConditionType conditionType=field.getAnnotation(ConditionType.class);
                    CType ct=conditionType.value();
                   
                    //调用get方法
                    Object objValue=invokeGetMethodByFieldName(field.getName(), object);
                   
                   
                    //获取字段类型
                    Class typeClass=field.getType();
                   
                    if(objValue==null)
                        continue;
                   
                    //检查字段是否为空
                    if(!checkTypeNull(typeClass,objValue)){
                        continue;
                    }
                   
                    //根据注解类型生成相应的语句和参数
                    if(ct.equals(CType.equal))
                    {   
                        hql.append(" and "+ field.getName() +" = ?");
                        params.add(objValue);
                    }
                    else if(ct.equals(CType.like))
                    {
                        hql.append(" and "+ field.getName() +" like ?");
                        params.add(Utils.returnLikeString(objValue.toString()));
                    }   
                    else if(ct.equals(CType.between))
                    {
                        hql.append(" and " +conditionType.queryField()+ " between ? and ?");
                        params.add(objValue);
                        Object andValue=invokeGetMethodByFieldName(conditionType.andField(), object);
                        params.add(andValue);
                    }
                   
                }
                System.out.println("生成hql语句为:"+hql.toString());
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
    }
   
   
    //调用get方法
    public static Object invokeGetMethodByFieldName(String fieldName,Object object)
    {
        fieldName=fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
        Method m=null;
        try {
            m = object.getClass().getMethod("get"+fieldName, null);
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Object objValue=null;
        try {
            objValue = m.invoke(object, null);
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return objValue;
    }
   
   
       private static boolean checkTypeNull(Class typeClass,Object objValue)
    {
        boolean flag=true;
       
        if(typeClass.equals(String.class))
        {
            if(objValue==null || Utils.isEmpty(objValue+""))
                flag=false;
        }
       
        if(typeClass.equals(Long.class))
        {
            if(objValue==null || Long.parseLong(objValue.toString())==0L)
                flag=false;
        }
       
        //后续如果出现类型判断有误,在此添加
       
        return flag;
    }

}


-------------------------------------------------------------------------

这个是用户查询时必要的几个参数,封转成bean啦


import java.util.List;

public class Paging {
    private String hql;
    private List<Object> params;
    private int start;
    private int limit;
   
   
    省略get、set   
}




-------------------------------------------------------------------------

这个就是吧 paging 这个bean进行查询的


public class CommonsDAO extends HibernateDaoSupport{
    private static final Logger log = Logger.getLogger(CommonsDAO.class);

    public List findByPageBean(final Paging page){
        if(page==null){
            return null;
        }
        List list = null;
        log.debug("分页查询");
        try {
            list = this.getHibernateTemplate().executeFind(
                    new HibernateCallback() {

                        public Object doInHibernate(Session session)
                                throws HibernateException, SQLException {
                            Query query = session.createQuery(page.getHql());
                            if(page.getParams()!=null)
                            {
                            for (int i = 0; i < page.getParams().size(); i++) {
                                query.setParameter(i, page.getParams().get(i));
                            }
                            }
                            if(page.getLimit()!=0)
                            {
                            query.setFirstResult(page.getStart());
                            query.setMaxResults(page.getLimit());
                            }
                            List list = query.list();
                            return list;
                        }
                    });
            log.debug("分页查询成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("分页查询失败",e);
            throw new RuntimeException("findByPageBean");
        }
        return list;
    }




public int findTotal(final Paging page) {
        int total=0;
        if(page==null)
        {
            return total;
        }
        log.debug("查询记录总数");
        try {
            total = Integer.parseInt((this.getHibernateTemplate().execute(
                    new HibernateCallback() {
                        public Object doInHibernate(Session session)
                                throws HibernateException, SQLException {
                            Query query = session.createQuery(page.getHql());
                            if(page.getParams()!=null)
                            {
                            for (int i = 0; i < page.getParams().size(); i++) {
                                query.setParameter(i, page.getParams().get(i));
                               
                            }
                            }
                            Object o=query.uniqueResult();
                            if(o!=null){
                                return Integer.parseInt(o.toString());
                            }
                            return 0;
                        }
                    }).toString()));
            log.debug("查询记录总数成功");
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询记录总数失败",e);
            throw new RuntimeException("findTotal");
        }
        return total;
    }

-------------------------------------------------------------------------


现在我们写一个封装查询条件的bean


import java.util.Date;

public class ZcjzclBean {


    /**
    * @Fields cphm : 车牌号码
    */
    @ConditionType(CType.like)
    private String cphm;
   
    /**
    * @Fields jg : 价格
    */
    @ConditionType(value=CType.between,andField="jgEnd",queryField="jg")
    private Double jgStart;
    private Double jgEnd;
   
    /**
    * @Fields lc : 里程
    */
    @ConditionType(value=CType.between,andField="lcEnd",queryField="lc")
    private Long lcStart;
    private Long lcEnd;
   
    /**
    * @Fields lcdj : 里程单价
    */
    @ConditionType(value=CType.between,andField="lcdjEnd",queryField="lcdj")
    private Double lcdjStart;
    private Double lcdjEnd;
   
    /**
    * @Fields bylc : 保养里程
    */
    @ConditionType(value=CType.between,andField="bylcEnd",queryField="bylc")
    private Long bylcStart;
    private Long bylcEnd;
   
    /**
    * @Fields fzrid : 负责人id
    */
    @ConditionType(CType.equal)
    private Long fzrid;
   
    /**
    * @Fields sjid : 司机id
    */
    @ConditionType(CType.equal)
    private Long sjid;
   
    /**
    * @Fields gg : 规格
    */
    @ConditionType(CType.like)
    private String gg;
   
    /**
    * @Fields xh : 型号
    */
    @ConditionType(CType.like)
    private String xh;
   
    /**
    * @Fields zws : 座位数
    */
    @ConditionType(value=CType.between,andField="zwsEnd",queryField="zws")
    private Long zwsStart;
    private Long zwsEnd;
   
    /**
    * @Fields ys : 颜色
    */
    @ConditionType(CType.equal)
    private String ys;

    /**
    * @Fields gmrq : 购买日期
    */
    @ConditionType(value=CType.between,andField="gmrqEnd",queryField="gmrq")
    private Date gmrqStart;
    private Date gmrqEnd;
   
    /**
    * @Fields jzrq : 建账日期
    */
    @ConditionType(value=CType.between,andField="jzrqEnd",queryField="jzrq")
    private Date jzrqStart;
    private Date jzrqEnd;
   
    /**
    * @Fields zcjzrid : 资产建账人id
    */
    @ConditionType(CType.equal)
    private Long zcjzrid;

  省略get、set
-------------------------------------------------------------------------

编写查询代码



import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;


public class ZcjzclServiceImpl implements ZcjzclService {
    public static final Logger log=Logger.getLogger(ZcjzclServiceImpl.class);
    private CommonsDAO commonsDAO;
   
    public List<TZcjzcl> queryByCondition(ZcjzclBean bean,int start,int limit)
    {
        try {
            log.debug(" ");
            Paging page=getPage( bean, start, limit, false);
            List<TZcjzcl> cls=commonsDAO.findByPageBean(page);
            return cls;
        } catch (RuntimeException e) {
            log.error(" 异常");
            throw e;
        }
       
    }
   
   
    public int queryTotalByCondition(ZcjzclBean bean, int start, int limit) {
        try {
           
            log.debug(" ");
            Paging page=getPage( bean, start, limit, true);
            int total=commonsDAO.findTotal(page);
            return total;
        } catch (RuntimeException e) {
            log.error(" 异常",e);
            throw e;
        }
    }
   
   
    private Paging getPage(ZcjzclBean bean, int start, int limit,boolean isTotal)
    {
        try {
            log.debug("组装查询语句及条件");
            List<Object> params=new ArrayList<Object>();
            StringBuilder hql=new StringBuilder();
            if(isTotal)
                hql.append("select count(*) from TZcjzcl where 1=1 ");
            else
                hql.append("from TZcjzcl where 1=1 ");
           
            if(bean!=null)
            {
                HqlCreator.createHql(hql, bean, params);
            }
           
            Paging page=new Paging();
            page.setHql(hql.toString());
            page.setStart(start);
            page.setLimit(limit);
            page.setParams(params);
           
            return page;
        } catch (RuntimeException e) {
            log.error("组装查询语句及条件异常",e);
            throw e;
        }
    }
   
  
     省略get、set
}




-------------------------------------------------------------------------

要加什么条件直接在查询条件bean里面加就完啦。








   发表时间:2010-12-23  
遇到 条件联动的,日期选择的,怎么处理?
0 请登录后投票
   发表时间:2010-12-23  
zb7503 写道
遇到 条件联动的,日期选择的,怎么处理?

页面把添加传好就可以啊,日期用between and
0 请登录后投票
   发表时间:2010-12-24  
那不是每个查询都得写一个查询bean,这样bean膨胀是不是太厉害了
0 请登录后投票
   发表时间:2010-12-24   最后修改:2010-12-24
和我的一样的代码,我写的更全面,还有就是使用DetachedCriteria(在组合查询条件时候相当的简单),在Service通过生成一个DetachedCriteria,利用注解将Form中的值传入DetachedCriteria,到DAO层使用hibernateTemplate.findByCriteria(criteria, page.getStart(), page.getLimit());搞定,这样如果无法满足查询,则可以在Action中提前生成DetachedCriteria,做一定的操作,再传给Service。
对于一个数据库设计良好的的系统,bean是不会膨胀的,这种方式专门处理多条件查询(一般大于5个),其他的可以另行设计,bean设计好继承关系,将公有的查询条件抽象到父类,bean文件也不会很大

还有改进下 @ConditionType,还可以直接生成页面
0 请登录后投票
   发表时间:2010-12-24  
jackerxff 写道
和我的一样的代码,我写的更全面,还有就是使用DetachedCriteria(在组合查询条件时候相当的简单),在Service通过生成一个DetachedCriteria,利用注解将Form中的值传入DetachedCriteria,到DAO层使用hibernateTemplate.findByCriteria(criteria, page.getStart(), page.getLimit());搞定,这样如果无法满足查询,则可以在Action中提前生成DetachedCriteria,做一定的操作,再传给Service。
对于一个数据库设计良好的的系统,bean是不会膨胀的,这种方式专门处理多条件查询(一般大于5个),其他的可以另行设计,bean设计好继承关系,将公有的查询条件抽象到父类,bean文件也不会很大

还有改进下 @ConditionType,还可以直接生成页面

你说的DetachedCriteria ,有时间研究下。真能慢慢做,把增删改查都能做出来,包括页面。那就爽了额,但是最大的瓶颈是 遇到联表就束手无策了额…… 
0 请登录后投票
   发表时间:2010-12-24  
请不要耦合hibernate,谢谢。
0 请登录后投票
   发表时间:2010-12-24  
yangguo 写道
请不要耦合hibernate,谢谢。

有些人总是说分层,但是dao接口里总是有具体化的东西(比如hibernate的东西)。搞形式玩。
0 请登录后投票
   发表时间:2010-12-24  
woding
0 请登录后投票
   发表时间:2010-12-24  
可以重写DetachedCriteria,底层通过jdbcTemplate实现,完全使用jdbcTemplate实现一套和Hibernate Criteria相当的查询,CRUD我已经全部实现了,当然查询时候还是依赖实体类,实现可以利用JPA注解,将JDBC返回的List<Map<String,Object>>装入实体类中。
   再更进一步,不用实体类,利用Javassist动态的生产实体类对象,再将数据装入,唯一不爽的是返回的是Object,由于EL,OGNL,FreeMarker,JSON-lib等都是利用反射获取相应的字段数据,这个不是问题(利用Javasssist动态生成field和相应的getter,不需setter,因为只能通过反射设置取值,只是上面的得利用getter方法,这样就像JavaScript 中可以动态修改prototype一样),这样就可以建立一个与具体表无关的查询,再利用重写的DetachedCriteria将查询表单中的字段与数据库表中的字段进行如楼主一样的适配,挺完美的通用查询解决方案,代码我已经实现,有需要可以贴上
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics