SpringSide学习笔记

HelloWorld
1.了解HSQL数据库
配置:
第一步,导入jar包
第二步,编写helloworld.properties和helloworld.script
第三步,数据库url设为:jdbc.url=jdbc:hsqldb:res:/hsqldb/helloworld即可.
2.HelloWorld中的Hibernate Annotation

HelloWorld中的Annotation还是比较简单的.

持久化类只需要声明@Entity并且为ID配上@Id及相应的生成器就行了.

可以看到,在spring的配置文件中,Hibernate Session已经由LocalSessionFactory改成org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean,

下面是持久化类的配置

   

在HelloWorld中,还给出了一个更为详细的User Hibernate Annotation配置

package org.springside.helloworld.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

/**
 * 用户.
 *
{@UniqueConstraint(columnNames = {"name"})})
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@BatchSize(size = 5)
public class UserFullVersion {
 private Integer id;


 * 这是一个Hibernate Annotation 式配置的详细版本.
 * 包含JDK1.4下的JavaDoc式配置 与JDK5.0的annotation配置
 *
 * @author Schweigen
 * @hibernate.class table="user"
 */
@Entity
@org.hibernate.annotations.Entity(dynamicInsert = true, dynamicUpdate = true)
@Table(name = "user", uniqueConstraints =

 private String name;

 private String email;

 private String descn;

 /**
  * @hibernate.id generator-class="native"
  * column="id"
  */
 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 /**
  * @hibernate.property column="name"
  */
 @Column(updatable = false, name = "name", nullable = false, length = 50)
 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 /**
  * @hibernate.property column="email"
  */
 @Column(name = "email", nullable = true, length = 50)
 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 /**
  * @hibernate.property column="descn"
  */
 @Column(name = "descn", nullable = true, length = 200)
 public String getDescn() {
  return descn;
 }

 public void setDescn(String descn) {
  this.descn = descn;
 }
}

与简化版相比只是将一些默认的东西添上,并做了一些详细调整,比如动态添加和动态更新的设置,主键的设置等.

3.利用Spring mock进行单元测试

Hello World中有一个测试类UserManagerTest,它继承DaoTestCase,而DaoTestCase又继承自Spring mock包中的org.springframework.test.AbstractTransactionalDataSourceSpringContextTests,DaoTestCase重写了该类的getConfigLocations方法,设置了spring配置文件中的位置 .从而UserManagerTest便可以对spring配置后的pojo进行单元测试.

4.分析SpringSide Core的org.springside.core.dao包

该包一共5个类,如下

EntityDao是一个DAO接口,提供了一组DAO方法,HibernateEntityDao实现它,HibernateGenericDao继承了Spirng的HibernateDaoSupport,HibernateDaoSupport最有用的莫过于getSession(),以及getHibernateTemplate(),前者可以用来获得Critera,后者可以用来事务性的对持久化类进行增删改.

IBatis的处理和Hibernate的差不多,目前我只关心后者.

HibernateGenericDao:

其中,isUnique,getId,getIdName是辅助方法,get,getAll,save,remove,removeById,flush,clear,find,findBy,findUniqueBy均是对getHibernateTemplate方法基于范型进行简单封装,createQuery,createCriteria两个方法是为分页供分页函数调用获取Query和Criteria对象,pagedQuery是分页函数重载,其中后两个调用第二个,第一个是根据Query进行分页,第二个是根据Criteria进行分页.在实现时,真正进行分页的语句其实都很简单,

Query query = createQuery(hql, values);
  List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();

List list = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();

费点劲的在于在分页时要得到totalCount--数据库中的记录总数,从而将这个参数传给page(org.springside.core.dao.support)构造器,totalCount在page中的作用是根据用户当前显示页来判断是否有下一页.而且这个参数对EC也是必须的.所以在分页时,才费劲的找到这个值:

在pagedQuery(String hql, int pageNo, int pageSize, Object... values)中,

  String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));//清空hql中多余的order和select
  List countlist = getHibernateTemplate().find(countQueryString, values);
  long totalCount = (Long) countlist.get(0);

在 pagedQuery(Criteria criteria, int pageNo, int pageSize)中,

CriteriaImpl impl = (CriteriaImpl) criteria;

  // 先把Projection和OrderBy条件取出来,清空两者来执行Count操作
  Projection projection = impl.getProjection();
  List orderEntries;
  try {
   orderEntries = (List) BeanUtils.forceGetProperty(impl, "orderEntries");
   BeanUtils.forceSetProperty(impl, "orderEntries", new ArrayList());
  } catch (Exception e) {
   throw new InternalError(" Runtime Exception impossibility throw ");
  }

  // 执行查询
  long totalCount = (Long) criteria.setProjection(Projections.rowCount()).uniqueResult();

  // 将之前的Projection和OrderBy条件重新设回去
  criteria.setProjection(projection);
  if (projection == null) {
   criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
  }

  try {
   BeanUtils.forceSetProperty(impl, "orderEntries", orderEntries);
  } catch (Exception e) {
   throw new InternalError(" Runtime Exception impossibility throw ");
  }

getIdName方法动态获得某个pojo的主键,想想也知道要用Hibernate 的org.hibernate.metadata.ClassMetadata

* 取得对象的主键名,辅助函数.
  */
 public String getIdName(Class clazz) {
  Assert.notNull(clazz);
  ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
  Assert.notNull(meta, "Class " + clazz + " not define in hibernate session factory.");
  String idName = meta.getIdentifierPropertyName();
  Assert.hasText(idName, clazz.getSimpleName() + " has no identifier property define.");
  return idName;
 }

 

HibernateEntityDao:

HibernateEntityDao继承自HibernateGenericDao并实现EntityDao,它大部分的方法均是对HibernateGenericDao的二次封装,与其说它是为了封装HibernateGenericDao,不如说是为了封装一次范型,从而子类DAO仅仅需要继承该类,并指定该DAO是哪个持久化类的DAO,像这样public class UserManager extends HibernateEntityDao ,对于这个类,主要是构造器里的反射部分:

protected Class entityClass;// DAO所管理的Entity类型.

 /**
  * 在构造函数中将泛型T.class赋给entityClass.
  */
 public HibernateEntityDao() {
  entityClass = GenericsUtils.getSuperClassGenricType(getClass());
 }
GenericsUtils是个工具类,里面就有个getSuperClassGenricType的重载方法,我们来关心一下

package org.springside.core.utils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Generics的util类.
 *
 * @author sshwsfc
 */
public class GenericsUtils {
 private static final Log log = LogFactory.getLog(GenericsUtils.class);

 private GenericsUtils() {
 }

 /**
  * 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager
  *
  * @param clazz The class to introspect
  * @return the first generic declaration, or Object.class if cannot be determined
  */
 public static Class getSuperClassGenricType(Class clazz) {
  return getSuperClassGenricType(clazz, 0);
 }

 /**
  * 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager
  *
  * @param clazz clazz The class to introspect
  * @param index the Index of the generic ddeclaration,start from 0.
  * @return the index generic declaration, or Object.class if cannot be determined
  */
 public static Class getSuperClassGenricType(Class clazz, int index) {

  Type genType = clazz.getGenericSuperclass();
   if (!(genType instanceof ParameterizedType)) {
   log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
   return Object.class;
  }

  Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

  if (index >= params.length || index < 0) {
   log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
     + params.length);
   return Object.class;
  }
  if (!(params[index] instanceof Class)) {
   log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
   return Object.class;
  }
  return (Class) params[index];
 }
}

在getSuperClassGenricType(Class clazz,int index)中,此时穿过来的clazz是你的DAO对象,比如UserManager,开始先取得父对象实例,也就是org.springside.core.dao.HibernateEntityDao ,随后返回它的范型参数.这里就是User类字面常量.

可以看到,SS对DAO采用了两层封装,一级接口的战术,底1层封装只关注与Spring-Hibernate的集成,底2层封装利用范型搭建了底1层与用户DAO的桥梁,并且通过继承EntityDao接口,在设计其它类时(比如StrutsAction),还可以在使用DAO的时候进行解偶.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值