使用java反射优化Spring自动生成的DAO实现类!
来源:互联网 发布:淘宝和天猫是一家吗 编辑:程序博客网 时间:2024/05/18 02:56
在使用Struts+Hibernate+Spring框架时,发现Spring为应用程序生成的数据访问层的代码都非常的重复,这样给人的感觉非常的不爽,基本上有多少个DAO,每个DAO都是重复的方法,无非就是换了一下具体的相对应的pojo类而已,这样感觉非常违背java代码重用的原则,因此想对此做一下改进,以便让代码的重用率更高一些,真实体现java在方法重用上的优雅性, 我想到了用java反射机制来实现,下面就是具体的代码片段了(关于java反射机制不懂的朋友,可以参考我原来写的关于java反射机制的文章)。
看下面一端代码,它是用来保存Diary这个对象的方法,如果你有一个User,或者Department,或者更多需要保存的对象的话,那么在你的相应的UserDAO,DepartmentDAO类里面下面的方法仍然会再出现一遍,不知道你看着爽不爽,至少我的感觉是非常冗余。
log.debug("saving Diary instance");
try ...{
getHibernateTemplate().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) ...{
log.error("save failed", re);
throw re;
}
}
接着我来进行改进,我让所有的具体的DAO类都去实现一个BaseDAO类,在BaseDAO类里面上述方法将如下所示:
* 保存对象
*
* @param object
*/
public void save(Object object) ...{
log.info("保存 " + object.getClass().getName() + " 实例");
try ...{
getHibernateTemplate().save(object);
log.info("保存 " + object.getClass().getName() + " 实例成功");
} catch (RuntimeException re) ...{
log.info("保存 " + object.getClass().getName() + " 实例失败", re);
throw re;
}
}
上述方法还没真正的使用java反射机制,只是在打印保存对象时,用了一点点,那么接着看下面的代码吧,你就会感受到java反射机制所带来的好处!
按照Id查询对象:
* 按照id查询对象
*
* @param object
* @param id
* @return
*/
public Object findById(Class object, java.lang.Integer id) {
log.info("通过: " + id + " 查询" + object.getCanonicalName() + "实例");
try {
Object instance = (Object) getHibernateTemplate().get(
object.getCanonicalName(), id);
return instance;
} catch (RuntimeException re) {
log.info("通过: " + id + " 查询" + object.getCanonicalName() + "实例失败",
re);
throw re;
}
}
一直记得hibernate按照id来查询对象的方式,如 get("Teacher",new Integer(1)),这样如此硬编码的方式在java反射机制面前居然也变的如此灵活,真的是爱上java反射机制没的说。
接着往下看吧
按照example查询对象,这没什么好说的,就算没有java的反射照样可以完成,只是有了反射之后,更便于我们知道哪里出了问题
* 按照example查询
*
* @param instance
* @return
*/
public List findByExample(Object instance) {
log.info("使用Example查询 " + instance.getClass().getName() + " 实例");
try {
List results = getHibernateTemplate().findByExample(instance);
log.info("使用Example查询 " + instance.getClass().getName()
+ " 实例成功, 查询出的记录数为: " + results.size());
return results;
} catch (RuntimeException re) {
log.info("使用Example查询 " + instance.getClass().getName() + " 实例失败",
re);
throw re;
}
}
接下来就是一个使用反射的最好的案例了
按照属性查询:按照这种方式做查询的再普通不过了,要使用jdbc的话不知道我们要写多少条String版的sql语句,现在有了spring帮着管理,真的轻松很多,看看吧
认真揣摩这个方法,发现这个方法的代码写的还是相当流畅和优雅,至少我写的话,绝对会非常累赘,里面使用了java反射机制,从而使这个方法变的更通用,在做项目的时候,我在根据不同条件求count的时候,没有认真看这个方法,因为当时遇到的问题是如果使用Hql来做查询时,如果条件有中文出现的话,中文条件将被当作乱码,后来被逼的没办法,居然写成下面的代码:
String hql="select count(*) from Student as s";
query=session.createQuery(hql);
if(stu.getStatuId()!=null)...{
hql=hql+" where s.studentStatu.statuId="+stu.getStatuId();
query=session.createQuery(hql);
}
if(stu.getClassId()!=null)...{
hql=hql+" and s.classes.classesId="+stu.getClassId();
query=session.createQuery(hql);
}
if(stu.getTeacherByDegreeTeacherId()!=null)...{
hql=hql+" and s.teacherByDegreeTeacherId.teacherId="+stu.getTeacherByDegreeTeacherId().getTeacherId();
query=session.createQuery(hql);
}
if(stu.getStuNo()!=null)...{
hql=hql+" and s.stuNo='"+stu.getStuNo()+"'";
query=session.createQuery(hql);
}
if(stu.getEmployeWay()!=null)...{
hql=hql+" and s.employeWay='"+stu.getEmployeWay()+"'";
query=session.createQuery(hql);
}
if(stu.getCreateDate()!=null)...{
String date=stu.getCreateDate().toString();
hql=hql+" and s.createDate='"+date+"'";
query=session.createQuery(hql);
}
if(stu.getIsObtain()!=null)...{
hql=hql+" and s.isObtain=?";
query=session.createQuery(hql);
query.setString(0, stu.getIsObtain());
}
if(stu.getWorkIntentCity()!=null )...{
hql=hql+" and s.workIntentCity=?";
query=session.createQuery(hql);
query.setString(0, stu.getWorkIntentCity());
}
if(stu.getAddress()!=null )...{
hql=hql+" and s.address like ?";
query=session.createQuery(hql);
query.setString(0, "%"+stu.getWorkIntentCity()+"%");
}
if(stu.getStuName()!=null)...{
hql=hql+" and s.stuName=?";
query=session.createQuery(hql);
if(stu.getWorkIntentCity()!=null)...{
query.setString(0, stu.getWorkIntentCity());
query.setString(1, stu.getStuName());
}else...{
query.setString(0, stu.getStuName());
}
}
System.out.println("-----------hql----------------------:"+hql);
return query.list();
只所以把代码写的如此愚蠢,就是因为一个原因:query.setString()这个方法,因为通过它把中文加入查询条件的话,就不会出现乱码了,而为了达到这一目的,代码就被我写成这种模样,想想当时我还自以为是的样子真是可笑,我都没把hibernate里面的方法整明白就乱写一通,为什么就不知道find(String,Object [] values)这个方法已经存在了呢?我只想到有find(String,object value),晕!
不过幸好后来意识到这样写的坏处,根据条件求count的方法又变成下面的这种方式
* 根据DetachedCriteria来获取符合条件的人数
* @param s
* @return int对象所在的集合
*/
public int getTotalCountByDetachedCriteria(Student s)
...{
log("根据DetachedCriteria来获取符合条件的人数");
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
/**//*ProjectionList proList = Projections.projectionList();
proList.add(Projections.count("stuId"));
dc.setProjection(proList);
*/
//设置要查询的属性,即count
dc.setProjection(Projections.count("stuId"));
//设置查询条件
//如果直接根据Example来创建的话,无法把stu里面的非空属性赋为查询条件,所以只有根据是否非空一步步加入
//这一点没有criteria做的好,因为是criteria的话,根据dc.add(Example.create(s))会自动把非空属性加入where条件里面,
//不知道为什么DetachedCriteria里面没有这种方法呢?浪费那么多时间编些没有意义的代码
//dc.add(Example.create(s));
if(s.getStuName()!=null)
dc.add(Expression.eq("stuName", s.getStuName()));
if(s.getStatuId()!=null)
dc.add(Expression.eq("statuId", s.getStatuId()));
if(s.getClasses()!=null)
dc.add(Expression.eq("classes", s.getClasses()));
if(s.getWorkIntentCity()!=null)
dc.add(Expression.eq("workIntentCity", s.getWorkIntentCity()));
if(s.getStuNo()!=null)
dc.add(Expression.eq("stuNo", s.getStuNo()));
if(s.getEmployeWay()!=null)
dc.add(Expression.eq("employeWay",s.getEmployeWay()));
if(s.getIsObtain()!=null)
dc.add(Expression.eq("isObtain", s.getIsObtain()));
if(s.getTeacherByDegreeTeacherId()!=null)
dc.add(Expression.eq("teacherByDegreeTeacherId", s.getTeacherByDegreeTeacherId()));
List list = stuDAO.findCountByDetachedCriteria(dc);
log("---------------根据DetachedCriteria来获取totalcount-----"+ Integer.valueOf(list.get(0).toString()));
return list.size() == 0 ? null : Integer.valueOf(list.get(0).toString());
}
这样写的方式比上面写的方式稍微改进了一点点,至少把业务逻辑写在了业务层,而不像上面的那种方式在持久层做判断,但缺点似乎还是没有被改进—没法做为公共方法,这样造成的结果求不同类别的count这种方法都得重新写一遍,造成代码太过冗余,试着优化一下吧,优化后的方式如下:
try
{
return (Integer) getHibernateTemplate().execute(new HibernateCallback()
{
public Object doInHibernate(Session session) throws HibernateException
{
log.info("o.getClass()"+o.getClass().toString());
Field [] f=o.getClass().getFields();
for(int i=0;i<f.length;i++)
System.out.println(f[i].getName()+"-oo");
Criteria criteria=session.createCriteria(o.getClass());
criteria.add(Example.create(o));
log.info(criteria.toString());
criteria.setProjection(Projections.count("stuId"));
return criteria.list().get(0);
}
}, true);
}
catch (RuntimeException re)
{
throw re;
}
}
仔细的分析这个代码段,唯一的缺陷就是设置查询的字段这个地方是硬编码的形式,其他的代码几乎都是用反射来实现的,因此这个方法也可以作为一个公有的方法放在BaseDAO中,这样在求类似的count值时就可以避免把相似的代码写N遍,还有一个好处是因为使用了Criteria这个类,因此就不再需要判断哪些条件该加,哪些条件不该加,这样可以减少大部分的无用乃至枯燥的if语句,但这个方法的不足之处就是在设置查询的字段时因为不能写成Projections.count("*")的形式,所以必须得赋你要查询的类的一个字段,如果要使用反射机制的话,这个字段必须是公共的,因为使用getField()方法取得的类变量是public类型的,我们可以让所有的pojo都继承一个类,在这个类中声明一个public类型的变量,这样问题就可以得到解决
好了,这些都是在做项目中遇到的和解决的,仅此拿出来互相分享和讨论,因为一贯欣赏java的开源原则,呵呵,虽然我的代码很乱,甚至丑陋,但毕竟还在学习,所以相信会写出优雅的代码的一天
- 使用java反射优化Spring自动生成的DAO实现类!
- DAO层通用实现,结果集ResultSet转化为javaBean的反射实现,自动生成javaBean
- DaoFactory(使用反射技术创建Dao的实现类)
- [自己动手]用Java的反射实现DAO
- java反射生成DAO【demo】
- Dorado 7 自动生成Dao的类
- java 反射写的 通用DAO 类
- AAAMybatis使用MapperScannerConfigurer实现自动注册dao到spring容器
- 使用Spring的JdbcTemplate实现DAO
- 深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存
- CodeSmith自动生成的Dao文件使用的字符串
- 使用反射技术实现对JDBC dao的简化
- 【MongoDB】Java驱动下,反射实现DAO的写操作
- 利用java的反射机制实现通用dao
- 反射小应用,利用Class自动生成Dao层的部分代码
- 使用MyBatis Generator自动生成DAO以及实体类
- mybatis功能之spring自动代理完成dao的实现类功能
- 利用java反射机制实现自动调用类的方法
- JavaScript简单教程
- 2008-3-28大盘分析
- Factorial 阶乘
- Dynamic Programming
- SEO是什么?与spam有什么区别呢?
- 使用java反射优化Spring自动生成的DAO实现类!
- Oracle Lesson 7 子程序和程序包
- 假药
- DedeCms V5.1(GBK/UTF8)版发布了
- 假药
- 《六人行》难懂笑话分集详解
- 恶搞《卖拐》之QQ自由幻想版
- jsp简介
- Tomcat加载顺序