《跟我一起做J2EE版Blog–jPress》4(搭建marven下的Spring和Hibernate)
jPress使用SSH的最新版本来开发,分别是Struts2.3.1,Spring3.1.1和Hibernate4.1.1,此外还将涉及Freemarker模板引擎来进行显示层的制作。在marven中配置SSH环境只需要编写好pom.xml文件即可,我们利用myeclipse为项目添加SSH特性的时候不要引入任何jar包。marven在build项目时会帮助我们自动引入所需的各种jar包,如果本地库中没有所需jar包,marven会从它的中央库中下载过来保存进本地库。上一章中我已经贴出了我目前的pom.xml文件,随着项目的推进,期间可能需要引入其他jar包,除非有重大的改变,我这里就不再对pom.xml赘述了。JAVA项目的设计层次很重要,层次的引入会降低项目的耦合度,今后开发起别的项目起来会非常顺畅,这一点跟asp和php又很大不同,我不否认PHP的灵活,但是php在国内的开发者手里完全是面向过程的语言,成百上千个全局函数让我很不适应。JAVA项目的开发自始自终散发出一种面向对象和解藕的光辉,这是让我感到愉悦的。
Spring的核心思想是解藕,对象的初始化在xml中描述出来了,应用程序不再需要new出一个对象并对其进行各种初始化,而是从Spring容器中取出这些初始化好的对象。下面来配置Spring,使用myeclipse添加spring特性后会得到一个applicationContext.xml,Spring会读取这个配置文件初始化一些bean以供我们注入。我先贴出我修改过的applicationContext.xml文件:
![]()
今天先写到这里,下一章我们将来设计数据库接口,原则上的构架是:一个数据库model会对应一个DAO,并有一个Impl类来实现这个接口,将这个Impl使用Spring的annotation注解为componet供将来的业务层注入使用。实际操作过程中,我们会首先设计一个通用接口BaseDao,在通用接口中使用JAVA泛型定义一组重用率非常高的增删改查操作,我们会有一个通用接口的通用抽象实现BaseDaoImpl,各个DAO接口继承自这个通用数据接口BaseDao,各个DAO的Impl继承自BaseDaoImpl并实现各自的接口,这样说上去比较绕,下一章实际操作起来其实层次感非常清晰。
Spring的核心思想是解藕,对象的初始化在xml中描述出来了,应用程序不再需要new出一个对象并对其进行各种初始化,而是从Spring容器中取出这些初始化好的对象。下面来配置Spring,使用myeclipse添加spring特性后会得到一个applicationContext.xml,Spring会读取这个配置文件初始化一些bean以供我们注入。我先贴出我修改过的applicationContext.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:content="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 注解扫描包 -->
<content:annotation-config/>
<content:component-scan base-package="com.flyding.jpress"/>
<!-- 使用占位符读取配置信息 -->
<bean id="placeHolder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:config.properties</value>
</property>
</bean>
<!-- 数据源 使用hibernate所建议的c3p0数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.psw}" />
<property name="initialPoolSize"><value>${hibernate.c3p0.initialPoolSize}</value></property>
<property name="minPoolSize"><value>${hibernate.c3p0.minPoolSize}</value></property>
<property name="maxPoolSize"><value>${hibernate.c3p0.maxPoolSize}</value></property>
<property name="maxIdleTime"><value>${hibernate.c3p0.timeout}</value></property>
<property name="maxStatements"><value>${hibernate.c3p0.max_statement}</value></property>
<property name="acquireIncrement"><value>${hibernate.c3p0.acquireIncrement}</value></property>
</bean>
<!-- hibernate4中的LocalSessionFactoryBean直接提供了annotation支持,这一点跟hibernate3有所不同 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
<property name="packagesToScan">
<value>com.flyding.jpress.model</value>
</property>
</bean>
<!-- 事务管理 -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 植入点 -->
<aop:config>
<!-- 定义一个植入点 -->
<aop:pointcut id="daoTransactionPt" expression="execution(public * com.flyding.jpress.dao.impl.*.*(..))"/>
<!-- 配置这个植入点将参考怎样的智者 -->
<aop:advisor pointcut-ref="daoTransactionPt" advice-ref="daoTransactionAdvice"/>
</aop:config>
<!-- 配置事务智者 -->
<tx:advice id="daoTransactionAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 用于注解方式配置事务 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
这份配置文件是我从上一个项目中copy过来的,复用率非常高,稍作修改就能在新的项目中使用。基于SSH的开发流程非常清晰,不会让人无从下手,从Spring的配置文件开始,我们就已经看到是Spring在集成Hibernate了。将经常需要修改的数据源信息分离在独立的config.properties文件中,使用placeHolder占位符读取配置信息并将其填入。下面是一份config.properties文件:jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/jpress jdbc.username=root jdbc.psw=******** hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.show_sql=true; hibernate.c3p0.initialPoolSize=10 hibernate.c3p0.minPoolSize=10 hibernate.c3p0.maxPoolSize=50 hibernate.c3p0.timeout=300 hibernate.c3p0.max_statement=50 hibernate.c3p0.acquireIncrement=5接下来需要着手编写Hibernate的model了,我习惯于使用annotation配置ORM映射关系,数据库中一共有10张表,其中有两个表是多对多的中间表,这两表是不产生模型的。所以我们一共需要生成8个java文件,并在文件中使用注解的方式描述类与数据库表的关系,myeclipse为我们提供了直接生成的工具,下面是一份由myeclipse生成的model:
package com.flyding.jpress.model;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* User entity. @author flyding.com
*/
@Entity
@Table(name = "jp_user", catalog = "jpress")
public class User implements java.io.Serializable {
private static final long serialVersionUID = 9010981240846378504L;
// Fields
private Long id;
private String username;
private String nickname;
private String password;
private String email;
private Timestamp registerDt;
private String userUrl;
private Integer userLevel;
private Set<Entry> entries = new HashSet<Entry>(0);
private Set<UserMeta> userMetas = new HashSet<UserMeta>(0);
// Constructors
/** default constructor */
public User() {
}
/** minimal constructor */
public User(String username, String password, String email,
Timestamp registerDt, Integer userLevel) {
this.username = username;
this.password = password;
this.email = email;
this.registerDt = registerDt;
this.userLevel = userLevel;
}
/** full constructor */
public User(String username, String nickname, String password,
String email, Timestamp registerDt, String userUrl,
Integer userLevel, Set<Entry> entries, Set<UserMeta> userMetas) {
this.username = username;
this.nickname = nickname;
this.password = password;
this.email = email;
this.registerDt = registerDt;
this.userUrl = userUrl;
this.userLevel = userLevel;
this.entries = entries;
this.userMetas = userMetas;
}
// Property accessors
@Id
@GeneratedValue
@Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "username", nullable = false, length = 50)
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
@Column(name = "nickname", length = 50)
public String getNickname() {
return this.nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Column(name = "password", nullable = false, length = 50)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
@Column(name = "email", nullable = false, length = 50)
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
@Column(name = "register_dt", nullable = false, length = 19)
public Timestamp getRegisterDt() {
return this.registerDt;
}
public void setRegisterDt(Timestamp registerDt) {
this.registerDt = registerDt;
}
@Column(name = "user_url", length = 50)
public String getUserUrl() {
return this.userUrl;
}
public void setUserUrl(String userUrl) {
this.userUrl = userUrl;
}
@Column(name = "user_level", nullable = false)
public Integer getUserLevel() {
return this.userLevel;
}
public void setUserLevel(Integer userLevel) {
this.userLevel = userLevel;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
public Set<Entry> getEntries() {
return this.entries;
}
public void setEntries(Set<Entry> entries) {
this.entries = entries;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
public Set<UserMeta> getUserMetas() {
return this.userMetas;
}
public void setUserMetas(Set<UserMeta> userMetas) {
this.userMetas = userMetas;
}
}
生成8个类似的数据层model后,我们的项目工程如图所示:
今天先写到这里,下一章我们将来设计数据库接口,原则上的构架是:一个数据库model会对应一个DAO,并有一个Impl类来实现这个接口,将这个Impl使用Spring的annotation注解为componet供将来的业务层注入使用。实际操作过程中,我们会首先设计一个通用接口BaseDao,在通用接口中使用JAVA泛型定义一组重用率非常高的增删改查操作,我们会有一个通用接口的通用抽象实现BaseDaoImpl,各个DAO接口继承自这个通用数据接口BaseDao,各个DAO的Impl继承自BaseDaoImpl并实现各自的接口,这样说上去比较绕,下一章实际操作起来其实层次感非常清晰。
浙公网安备 33010602011771号