1 整合Struts2
完成了Spring和Hibernate的整合,最后一步我们将对Struts2和Spring进行整合。编写一个struts.xml的文件,该文件存放在src目录下。
配置由Spring实例化Struts2,需要Spring框架的支持
<constant name="struts.objectFactory" value="spring"></constant>
配置国际化编码
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
配置convention-plugin注解插件,要让Struts2支持注解,这一步是必须的!
<constant name="struts.convention.default.parent.package" value="default" />
完整配置如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="false" />
<constant name="struts.objectFactory" value="spring"></constant>
<!--charset-->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!-- convention-plugin -->
<constant name="struts.convention.default.parent.package" value="default" />
<package name="default" extends="struts-default,json-default">
<interceptors>
<interceptor-stack name="securedStack">
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="securedStack"></default-interceptor-ref>
<global-results>
<result name="error">/error.jsp</result>
<result name="invalid.token">/error.jsp</result>
<result name="login" type="redirect">/login</result>
</global-results>
</package>
</struts>
在web.xml中增加Struts2的过滤器,将Struts2集成到WEB工程中。
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
2 增加日志文件配置
前面我们已经完了SSH架构的整合,为了让程序更容易调试和跟踪问题,我们把log4j加上,以便排查项目开发中出现的各种异常。本配置使用了apache的slf4j框架,slf4j框架对log4j进行了集成,使log4j的使用更简单,slf4j是开源社区中非常火的框架。
log4j.debug=false
log4j.rootLogger=debug,Stdout
# please keep this setting FATAL to avoid questions from users
# why there are stacktraces in the test output. You can turn it
# down if you need to when testing, but don't check it in. (eelco)
# changing back to ERROR. Looks like in some cases the log4j.properties
# in wicket gets picked which results in not printing the exceptions
# and that can be a bit dangerous (matej)
log4j.logger.com.ssh=info
log4j.logger.DBstep=error
log4j.logger.org.hibernate=info
log4j.logger.org.apache.struts2=debug
log4j.logger.org.springframework=debug
log4j.logger.com.opensymphony=info
log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.Stdout.layout.conversionPattern=%-5p - %-26.26c{1} - %m\n
3 如何使用注解
3.1 Spring注解
Spring的注解有很多,我们只介绍在架构中常用到的注解,分别为@Resource、@Autowired、@Service、@Repository、@Component、@Transactional六个注解。
DI注解:
@Resource其实不是Spring中的注解,而是JAVA中的标准注解,是JSR-250中的一个规范,Spring对其进行了实现。使用@Resource注解可以注入JavaBean,默认按照名字注入JavaBean。
@Resource(name="personDao")
IPersonDao personDao;
@Autowired是Spring的一个注解,作用和@Resource是一样的,@Autowired默认按照类型注入。
IOC注解:
@Service用来标注在Service类上,表示让Spring来实例化Service类,也就是我们所说的IOC。
<span style="font-size:14px;">@Service //标注service层
public class PersonService implements IPersonService
</span>
@Repository用来标注在DAO类或是数据访层的类中,作用和@Service一样。
@Repository //标注dao层
public class PersonDao extends GenericReposistoryHibernate implements IPersonDao
@Component用来标注普通的JavaBean,例如POJO和MODEL类等。
@Component("personPojo" )// 把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>
public class PersonPojo extends GenericObject
事务注解:
@Transactional是事务注解,使用该注解可以让Spring代替我们接管事务,不用每次都由程序员来提交和回滚事务。
3.2 JPA与Hibernate注解
之前讲到过Hibernate中使用注解用到的是JPA。JPA其实也是JAVA中的规范之一,是与EJB3一起诞生的产物,全称为Java Persistence API(JAVA持久化API)。使用JPA可以实现Java Bean的ORM映射,包括对象和表、属性和字段、对象依赖和表间关系的映射(例如一对一、一对多、多对多的映射)。下面的示例是JPA的基本使用方法:
<span style="font-size:14px;">@Entity //标注该类为实体类。
@Table(name = "person") //标注对应的数据库表明。
@Component("personPojo" )// 把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>
public class PersonPojo extends GenericObject {
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
@Column(name = "name", unique = true)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
</span>
GenericObject类,该类提供一个父类的ID,所有继承该类的子类都具有一个ID
<span style="font-size:14px;">@MappedSuperclass
public abstract class GenericObject{
private static final long serialVersionUID = 1L;
private String id;
public GenericObject() {
super();
}
@Id
@Column(name = "id", length = 36, nullable = true)
@GeneratedValue(generator = "hibernate-uuid.hex")
@GenericGenerator(name = "hibernate-uuid.hex", strategy = "uuid.hex")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
</span>
使用<prop key="hibernate.hbm2ddl.auto">update</prop>属性可以使Hibernate自动创建和修改表,而不用再手工修改。
关于如何使用JPA,请参考我的另一篇博文《JPA在Hibernate中的使用》。这篇文章详细介绍了JPA的语法和使用方法。
3.1 Struts2注解
Struts2框架的注解是使用convention-plugin插件实现的,关于Struts2插件的使用请参考我的另一篇博文《在Struts2框架中使用注解》。
4 如何在工程中使用Spring切面事务和增删改查
在使用JDBC或者是Hibernate对数据库的进行增删改查操作时,通常都需要使用事务。事务是保证数据一致性和完整性的重要技术,如果使用不当,可能会产生不完整的交易数据,所以在软件开发中对事务的控制一定要认真对待。Spring为我们提供了AOP切面事务,使程序员不用自行控制事务。使用Spring事务我们只需要标注@Transactional注解即可,Spring会自动接管方法中的事务。我们可以定一个数据库访问层的公共类,所有的DAO类都继承至该类,而不用在每个DAO都使用@Transactional注解。
/**
* 持久化基类
*
* @author 山人
*
*/
@Transactional
@Component("repositoryImp")
public class GenericReposistoryHibernate {
@Resource
protected SessionFactory sessionFactory;
private Session session = null;
@Transactional
public <T, PK extends Serializable> PK create(T newInstance) {
PK save = (PK) getSession().save(newInstance);
return save;
}
@Transactional
public <T> void delete(T transientObject) {
getSession().delete(transientObject);
}
@Transactional
public <T> void update(T transientObject) {
getSession().update(transientObject);
}
@Transactional(readOnly=true)
public <T> List<T> findAll(Class<T> type) {
return getSession().createCriteria(type).list();
}
public <T> List<T> findHQLByParam(String hql, int firstResult,
int maxResult, Object... params) {
Query query = getSession().createQuery(hql);
for (int i = 0; i < params.length; i++) {
query.setParameter(i + 1, params[i]);
}
query.setMaxResults(maxResult);
query.setFirstResult(firstResult);
return query.list();
}
@Transactional(readOnly=true)
public <T> List<T> findAllValid(Class<T> clas) {
return getSession().createCriteria(clas).list();
}
@Transactional(readOnly=true)
public <T, PK extends Serializable> T get(Class<T> type, PK id,
boolean block) {
if (block)
return (T) getSession().get(type, id, LockMode.UPGRADE);
else
return (T) getSession().get(type, id);
}
public Session getSession() {
if (sessionFactory.isClosed()) {
sessionFactory.openSession();
} else {
session = sessionFactory.getCurrentSession();
}
return session;
}
}