spring,hibenate,再搭配一个X(就是本文标题中的+x),已经几乎横扫目前的JAVA应用界,好象目前
一讲JAVA应用开发,都必须要懂这三样东西的。最近花了些时间来学习之,发现其实还是有不少模式和规律可以找到的,
现将心得小结之,总结这些带规律的“板斧”类东西,呵呵。
以一个最简单的一对多例子来讲解。比如有目录category,产品类product,目录和产品的关系是一对多关系。于是咱们先来搞个
PO(下面的代码都只是写重点部分,其他的就省略了,学过或看过的,一看就明,只起到提点作用)
1、建好基础:MODEL层
category.java
public class category
{
.......id,description之类的属性
private Set products; //用集合来表示产品
public Set getProducts()
{
return products;
}
/**
* @param products The products to set.
*/
public void setProducts(Set products)
{
this.products = products;
}
}
product实体
public class Product
{
......
private Category category;
public Category getCategory()
{
return category;
}
/**
* @param category The category to set.
*/
public void setCategory(Category category)
{
this.category = category;
}
}
之后我们马上搞映射文件了
catagory.hbm.xml中,要特别注意设置为
<set cascade="none" name="products" inverse="true" order-by="name asc">
<key column="CATEGORY_ID" />
<one-to-many class="cn.liao.model.Product" />
</set>
而products.hbm.xml中,特别注意设置为
<many-to-one column="CATEGORY_ID" name="category"/>
好了,model层搞好了,我们放到cn.liao.model这个包下,这个包我们专放model层的东西
2、接下来,我们来搞持久层了,其实持久层的话,之前我们用传统的JDBC去玩的,现在换了hibernate而已,注意在这层里,我们要把PO持久保存到数据库了,和PO打交道了,接受来自业务层的对象了,这里等于临门一脚了,所以一般我们用DAO模式去搞的,比如搞个工厂之类的东西,可扩展性好,下面的例子里,只是简单给出接口,然后再实现之,实现时,通过getHibernateTemplate()得到spring中所定义的操作模版
Icategory.java(category的DAO接口)
public interface CategoryDao
{
// 保存商品分类
public Category saveCategory( Category category );
// 修改商品分类
public Category updateCategory( Category category );
// 得到所有的商品分类
public List getAllCategorys();
// 得到某个商品分类的信息
public Category getCategory( String categoryId );
// 删除某个商品分类的信息
public void deleteCategory( Category category );
}
而实现呢,我们命名一个叫categoryDaoHibernateImpl的类(注意我们为了规范,一般用impl做名字的后缀)
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;i
mport cn.liao.dao.CategoryDao;
import cn.liao.model.Category;
public class CategoryDaoHibernateImpl
extends HibernateDaoSupport
implements CategoryDao
{
public Category saveCategory(Category category)
{
this.getHibernateTemplate().save( category );
this.getHibernateTemplate().flush();
return category;
}
public List getAllCategorys()
{
String sql = "from Category c order by c.name";
return this.getHibernateTemplate().find( sql );
}
public void deleteCategory(Category category)
{
this.getHibernateTemplate().delete( category );
}
public Category getCategory(String categoryId)
{
Category category = (Category)this.getHibernateTemplate()
.get( Category.class, categoryId );
return category;
}
public Category updateCategory(Category category)
{
this.getHibernateTemplate().update( category );
this.getHibernateTemplate().flush();
return category;
}
}
呵呵,看到了吧,我们在这里,继承了HiberanteDaoSupport,又把很多东西简单化了,完全就是get呀,update呀,delete等傻瓜方法了,
那个sessionfactory哪去了?我们等阵注入给它。注意,这时我们的持久层搞好了,我们把它放到cn.liao.dao包里去,方便管理
3、好了,接下来我们来搞业务层。业务逻辑层是很关键的,它要进行一些实际的运算之类的,处理后再把对象传给持久层进行保存。
为了解藕合,我们依然用接口式编程。比如对category类,如果要增,删,改,查的话,我们依然定义IcategoryService接口:
public Interface IcategorySerivce
{
// 保存商品分类信息
public Category saveCategory( Category category ) throws xxxexcepiton;
// 修改商品分类信息
public Category updateCategory( Category category ) throws xxxexception;
// 得到所有的商品分类信息
public List getAllCategorys();
// 得到某个商品分类的信息
public Category getCategory( String categoryId ) throws xxxexception;
// 删除某个商品分类的信息
public void deleteCategory( String categoryId ) throws xxxexception;
}
}
接下来,真正实现这个业务接口的实现类为
public class CategoryServiceImpl implements CategoryService
{
//要用到DAO层的对象了
private CategoryDao categoryDao;
public CategoryDao getCategoryDao()
{
return categoryDao;
}
public void setCategoryDao(CategoryDao categoryDao)
{
this.categoryDao = categoryDao;
}
// 保存商品分类信息
public Category saveCategory( Category category ) throws xxxexcepiton
{
try
{
//比如这里再进行一些商业逻辑计算
。。。。。。。。
//调用持久层去保存对象了
Category c = this.getCategoryDao().saveCategory( category );
return c;
}
catch (....)
{
}
.........//其他如此类推
}
注意的是,我们在这里要用到的是DAO层的categoryDao对象了,但我们并不在这里硬编码,而是依靠spring里进行注入
4、好了,我们现在来搞前端的控制层了(controller)了。我们这里用jsf+spring+hibernate的,
这里我们先提供一个基类baseaction,提取大家都要用到的一些东西,减少在开发时的代码量,其实换了structs的话,也可以先搞个baseaction的,让它继承自Action。我们的这个JSF的baseaction这样搞
public class BaseBean
{
protected ServiceLocator serviceLocator;
public ServiceLocator getServiceLocator()
{
return this.serviceLocator;
}
public void setServiceLocator(ServiceLocator newServiceLocator)
{
this.serviceLocator = newServiceLocator;
this.init();
}
protected void init()
{
}
}
注意,这里的 ServiceLocator 类,我们接下来会编写,我们再这里,依然是接口编程
public interface ServiceLocator
{
public ICategoryService getCategoryService();
public IUserService getUserService();
。。。。。这里可能还有很多其他的服务
}
记得吧,IcategoryService就是我们刚才已经做好了的处理目录类的业务逻辑接口,这里,还存在很多其他业务相关的逻辑接口的,可以一一列出,这个接口的目的是定义了所有业务层对象实例的方法。
然后又是对其的一个实现类,命名为ServiceLocatorImpl,
public class ServiceLocatorImpl implements ServiceLocator {
private ApplicationContext appContext;
public ServiceLocatorImpl() {
//这里先获得ServletContext
ServletContext context = FacesUtils.getServletContext();
this.appContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(context);
}
public Object lookupService(String serviceBeanName) {
return appContext.getBean(serviceBeanName);
}
public CategoryService getCategoryService() {
return (CategoryService) lookupService(“categoryservice”);
}
}
这里,首先得到getServletContext对象的实例,然后通过spring的WebApplicationContextUtils类的getRequiredWebApplicationContext得到applicationcontext对象的实例,最后通过ApplicationContext对象的实例得到这些业务方法类的实例
这个时候,我们把这些业务层的所有东西,都放到一个统一的包里,比如
cn.liao.services或者叫cn.liao.business。
好了,我们最后看下JSF里的前置bean如何写法,JSF里,其实就是把actionform和action都结合在一起了,用javabean的形式来表达,大概构造为:
public class CategoryBean extends BaseBean
{
。。。。。一系列的SET,GET方法
//增加产品的action
public String createAction()
{
try
{
this.getServiceLocator().getCategoryService().saveCategory( category );
}
return SUCCESS
catch (…..)
{
};
}
private Category convertToCategory()
{
Category category = new Category();
category.setId( this.id );
category.setName( this.name );
category.setDescription( this.description );
return category;
}
在上面的代码中,首先用convertToCategory(),构造出了Category 对象,十分简单,都是用set 的方法(前台的JSF会帮你自动绑定好)。接着在createaction里,就用
this.getServiceLocator().getCategoryService().saveCategory( category );来调用业务层的方法了,调用成功的话返回字符串success,这个success是在JSF的配置文件里去配置去导航的。
5、我们接着要写JSF的faces-managed-beans.xml,这个是其配置前置BEAN的文件,可以看做是一个粘合剂
<managed-bean>
<description>
Service locator of the business services
</description>
<managed-bean-name>serviceLocatorBean</managed-bean-name>
<managed-bean-class>
cn.liao.services.ServiceLocatorImpl
</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
<managed-bean>
<description>
Backing bean that contains category information.
</description>
<managed-bean-name>categoryBean</managed-bean-name>
<managed-bean-class>
cn.liao.services.CategoryBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<value>#{param.categoryId}</value>
</managed-property>
<managed-property>
<property-name>serviceLocator</property-name>
<value>#{serviceLocatorBean}</value>
</managed-property>
</managed-bean>
在上面的配置文件中,首先指出了serviceLocatorBean这个BEAN的实际位置是代表cn.liao.services.ServiceLocatorImpl,接下来我们配置categoryBean
了,由于在categorybean里,需要获得id号,所以用#{param.categoryId}的形式就可以实现了,象需要servicelocator,也在这里通过<value>#{serviceLocatorBean}</value>注入进去了
而在面对最终用户的V层,这里就不详细阐述了,只是提点一下,V层其实和STRUCTS差不多,只不过换了JSF的一些标签,而比如在象提交按钮这里,可以这样写
<h:commandButton value="#{msgs.create}"
action="#{categoryBean.createAction}"/>
这里,留意action="#{categoryBean.createAction}",记得吧,categoryBean就是我们刚才写好的前置控制器的javabean,而这里是调用了其中的createAction方法(见前面的代码)。
我们还要配置faces-navigation.xml文件,这个文件主要是JSF里配置页面的导航,还记得之前我们那个提交成功后的那个success么,其实是来自下面的定义
<navigation-rule>
<from-view-id>/category/categoryCreate.jsp</from-view-id>
<navigation-case>
<description>Create Category Success</description>
<from-outcome>success</from-outcome>
<to-view-id>/category/categoryCreate.jsp</to-view-id>
</navigation-case>
这里,<from-view-id>是说当从/category/categoryCreate.jsp页面进来的请求作如何的处理,<from-outcome>success</from-outcome>就是success了,当success时,要跳转到另外的V层的categorycreate.jsp
6、最后的SPRING大组装
一切都搞好了,就要把它们装配起来,下面给出applicationcontext.xml文件
<beans>
<!-- ============ Start of PERSISTENCE DEFINITIONS =========== -->
<!-- DataSource Definition -->
//设置datasource
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.gjt.mm.mysql.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/show?useUnicode=true&characterEncoding=utf8&autoReconnect=true&autoReconnectForPools=true</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>xxxxx</value>
</property>
</bean>
//spring和hibernate的结合
<!-- Hibernate SessionFactory Definition -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="mappingResources">
<list>
<value>cn/hxex/library/model/Category.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="current_session_context_class">thread</prop>
<prop key="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</prop>
<prop key="connection.pool_size">10</prop>
//这里设置hbm2ddl为auto,则只需要之前在MYSQL里建好数据库,不需要建表,其他都自动在运行时生成表了
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- Spring Data Access Exception Translator Defintion -->
<bean id="jdbcExceptionTranslator"
class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<!-- Hibernate Template Defintion -->
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
<property name="jdbcExceptionTranslator">
<ref bean="jdbcExceptionTranslator"/>
</property>
</bean>
<!-- Category DAO Definition: Hibernate implementation -->
<bean id="categoryDao"
class="cn.hxex.library.dao.hibernate.CategoryDaoHibernateImpl">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
//对事务的定义
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
<bean id="categoryServiceTarget"
class="cn.liao.service.CategoryServiceImpl">
<property name="categoryDao">
<ref local="categoryDao"/>
</property>
</bean>
<bean id="categoryService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager"/>
</property>
<property name="target"><ref local="categoryServiceTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>