搭建SSH框架的集成开发环境

本文介绍如何搭建Java Web项目中的Struts2, Hibernate和Spring集成开发环境。

SSH框架的简单了解

首先我们要理解Struts2? , Hibernate, Spring 这些框架的在我们开发JavaEE项目中所起的作用。

Struts2是一个MVC框架,它的重点在于Controller层,可以控制Action处理后,根据返回的字符串,跳到指定的视图(带着数据)。 Struts2 的默认拦截器栈,在我们处理前台传递的数据之前,帮我们做了许多事情。包括前台表单传到后台的数据,这使我们不用像Servlet一样写 request.getParameter(“ ”),还有数据校验和数据类型的转换等。Struts2 还定义了一些前台显示数据很方便的许多UI标签。

Hibernate 是一个ORM 框架,Hibernate 管理着JavaEE项目中的实体类与关系数据库中的表的关系。Hibernate 中的 Session 对象提供的API使我们代码中的增删改查代码很简单。更重要是的是,它是我们的项目很容易在Hibernate方言支持的的数据库中切换数据库部署。我们开发的项目不仅是跨操作系统平台,而且是跨数据库平台的。

Spring 我一直认为是SSH中最重要的一个框架,如果你想是自己的项目高度解耦,Spring是必不可少的。Spring主要提供两大功 能,IOC(Inversion of Control)管理着我们项目之中的所有对象的生命周期,以及AOP(Aspect Oriented Programming)。Spring中通过AOP实现了声明式事务管理,这个也是开发web项目常用的功能。Spring在SSH框架中就像一条线把 三个框架集成,三个框架的集成也就是Spring与Hibernate和Struts2 的集成。Spring文档中提供了集成其他的框架的方法。

以上就是我对ssh框架的简单理解,下面我一步一步的将三个框架集成,搭建项目的开发环境。以上就是我对ssh框架的简单理解,下面我一步一步的将三个框架集成,搭建项目的开发环境。

集成方案的选择

对于Struts2的配置其实也是有注解方式实现的,只不过用的相当少,所以对于Struts2的配置我们理所当然的采用xml配置。

对于Hibernate,以前的ORM框架都采用XML配置,但现在jdk1.5后提够了注解的功能,注解配置的方式以其简单优雅的方式,流行起来 了。并且在JavaEE 5的规范中 已经包含了JPA 的规范。Hibernate也对JPA的规范提供了良好的实现。所以我们打算采用JPA的规范,使用注解配置。这样我们可以很容易地在实现了与 Hibernate的解耦,只要采用实现了JPA的规范的框架即可。

对于Spring也提供了xml和注解配置两种方式。我们采用XML配置。有些人觉得注解配置很方便,其实Spring注解中使用到的类,大多是不 包含在JavaEE的规范中的。你使用的spring注解其实与Spring 框架深度耦合了。还有 ?AOP 的配置,如果采用注解,你需要在项目中需要切入的每个类上面都添加注解,例如声明式事务管理的配置,采用注解的话,就要在需要事务管理的每个类上面添加 @Transactional 注解,而且这个类是spring中特有的。所以spring的配置使用XML为宜。

许多人喜欢先把Struts2 和Hibernate集成,然后再将Spring框架集成。我习惯是先将Spring引入项目,然后引进Struts2 ,最后引进Hibernate 完成实际的增删改查。本次项目的开发本着学习的目的打算采用最新版本集成。分别采用struts-2.2.1, hibernate-3.6.1,spring-3.0.4。

三个框架的集成步骤

我一步一步的将环境中需要的jar包导入,让你知道每一个包的来历。每一个配置文件的来历和写法。这样才会对各个文件熟悉起来。

第一大步,准备工作

以User 的登录操作为例,搭建项目的基本骨架。

在src目录新建User类。Package 为com.ssh.po。

代码如下:

package com.ssh.po;    

public class User {
    private Integer id;
    private String name;
    private String password;
}

  (省略类的setter getter ,请使用eclipse 自动生成)

   现在我们要实现对User 进行增加记录的操作。

   面向接口编程的思想,我们应该先建立User与 持久层 增删改查的接口UserDao。

 

package com.ssh.dao;

import com.ssh.po.User;

public interface UserDao { 
    void insert(User user);
}

接着建立User 类对应的业务层的接口UserService。如下图所示

package com.ssh.service;

import com.ssh.po.User;    

public interface UserService {
    boolean add(User user);
}

现在我们假设我们有两种实现User insert 的方案,一种是默认的实现,一种是以特定格式保存到txt文件中。UserService的实现需要调用 UserDao的实现完成add 操作。

首先建立两种方案实现的代码,现在我们只是简单的打印一条语句,表明方法执行了。

对应的两个UserDaoBean代码如下图所示, 注意它们的包名不同。

package com.ssh.dao.impl;

import com.ssh.dao.UserDao;
import com.ssh.po.User;

public class UserDaoBean implements UserDao {
    @Override
    public void insert(User user) {
        System.out.println("默认的实现:添加了一个用户名为" + user.getName() + "的用户");
    }
}
package com.ss.dao.txt;

import com.ssh.dao.UserDao;
import com.ssh.po.User;

public class UserDaoBean implements UserDao {
    
    @Override
    public void insert(User user) {
        System.out.println("向txt文件末尾写入一个用户名为" + user.getName() + "的用户");
    }
}

现在我们要实现UserService的add方法。这时我们会使用到dao层的UserDao的insert方法,必须持有实现了UserDao接口的对象的引用。

建立UserService的实现类UserServiceBean代码如下:

package com.ssh.service.impl;

import com.ssh.dao.UserDao;
import com.ssh.po.User;    
import com.ssh.service.UserService;  

public class UserServiceBean implements UserService {  
    private UserDao userDao;

    @Override
    public boolean add(User user) {
        userDao.insert(user);
        return true;
    }
}

此时src目录结构如下图所示:

      151539_cO9N_1782822.jpg

为了帮助大家理解此时这几个核心类之间的关系,我画了一个UML类图表示:

151707_Hkms_1782822.jpg

虚线加三角形表示“实现关系”,虚线加箭头表示“依赖关系”。

我们可以看到UserServiceBean只与UserDao接口之间存在依赖,与具体的实现方案无关。我们只要改变UserServiceBean中持有的userDao,就可以在两种实现方案之间实现切换。

接下来建立UserServiceBean 的测试用例:

在工程目录下new 一个 source folder ,注意不是普通的folder。Name为 test。在UserServiceBean上右击弹出菜单 ,new 一个 使用junt4的 junit test case 。

152344_y6o2_1782822.jpg

测试用例代码如下图所示:

package com.ssh.service.impl;

import org.junit.BeforeClass;
import org.junit.Test;

import com.ssh.po.User;
import com.ssh.service.UserService;

public class UserServiceBeanTest {

	private static UserService userService;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		userService = new UserServiceBean();
	}

	@Test
	public void testAdd() {
		User user = new User();
		user.setName("张三");
		user.setPassword("123456");
		userService.add(user);
	}
}

这是我们并未new 一个真正实现了的userDao 的类的对象。Java编译器会默认初始化为null(int类型的成员变量会初始化为0. 局部变量没有初始化会报编译错误),所以此时调用userDao的 insert方法会报 空指针异常。

现在我们将 userDao 初始化为:(注意观察我选择的哪个包的实现)

private UserDao userDao = new com.ssh.dao.impl.UserDaoBean();

再次运行测试用例,一切正常。观察控制台打印的字符串,发现调用的是子类的insert 方法。这就是面向对象的 “多态” 特征。当父类(包括接口)的引用指向子类时,会调用具体的子类的方法。依据这个特性,我们很容易的在两种实现方案直接切换。假如我们将userDao 实例化的代码改为:

private UserDao userDao = new com.ssh.dao.txt.UserDaoBean();

运行测试用例发现,调用的insert方案也切换到了两外一种实现。这就是面向对象通过多态的方式实现对象之间的解耦。

虽然我们通过这种方式实现了解耦,但你会发现仍然有两大不足的地方。首先,如果想改变实现方式我们仍然需要改动代码,这意味着,整个项目都需要重新编译,打包,上传,部署。其次,userDao 的对象应该采用单例模式,我们的代码里每次都new 一个对象。

这两个不足就是spring 的 ioc 为我们 解决的,我们可以把每个对象都配置在xml文件中,spring在项目启动时,会初始化所有的类,并且为需要setter 的成员变量,提供 依赖注入。

去掉UserServiceBean 中 初始化 userDao 的代码,只为为userDao 生成getter 和 setter方法。我们将使用spring 提供的 ioc 通过getter实现 依赖注入。再次运行测试用例,空指针异常。修改UserServiceBeanTest为:

public class UserServiceBeanTest {
	private static ApplicationContext context;
	private static UserService userService;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		context = new ClassPathXmlApplicationContext("beans.xml");
		userService = context.getBean("userService", UserService.class);
	}

	@Test
	public void testAdd() {
		User user = new User();
		user.setName("张三");
		user.setPassword("123456");
		userService.add(user);
	}
}

只要我们能通过这个测试用例,证明spring 已经成功引入项目。

第二大步,引入spring框架

前面的任何操作,我们并未使用SSH任何框架。下面我们首先引进spring,然后引进hibernate,并将spring和hibernate集成,最后完成Struts2的集成,就像用一根线(spring)将hibernate和struts2穿起来。

解压我们下载的spring 3.0.4 的包 我发现它与我之前使用的 2.5差别很大。我将3.0 的文档又浏览了一遍。3.0 之后将spring.jar 依据功能模块分成了独立的几个模块,这样可以根据项目需要,添加自己需要的jar包。到底哪些jar包是使用ioc 必须添加的jar包呢?

对照spring-framework-reference.html 中的说明,我们参考文档3.2.1 Configuration metadata 中的配置bean的例子。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beas-3.0.xsd">

	<bean id="…" class="…">
	<!– collaborations and configuration for this bean go here–>
	</bean>

	<bean id="…" class="…">
	<!– collaborations and configuration for this bean go here–>
	</bean>

	<!– more bean definitions go here –>

</beans>

在src目录下新建beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beas-3.0.xsd">

	<bean id="userDao" class="com.ssh.dao.impl.UserDaoBean">

	<bean id="userService" class="com.ssh.service.impl.UserServiceBean">
		<property name="userDao" ref="userDao"></property>
	</bean>

</beans>

我们发现此时UserServiceBeanTest中的ApplicationContext无法识别,这是因为我们还没有引入spring的jar 包,现在的问题就是引入哪些jar包是使用ioc 所需的最少的jar包。有两种思路,你可以先把所有的jar文件都copy到lib下面,运行junit,你会发现仍然有个类找不到,这个jar包是 spring中没有的,spring记录日志用到了这个jar包,自己将异常信息做关键字,在网上搜,你会很容易找到缺的jar包。解决这个后,运行 junit,一切正常,修改beans.xml 中的实现类,发现我们不要修改代码,实现的类也跟着切换了。但是现在jar包肯定有多的,你可以一个一个的删除,也可以一次多删几个,运行junit不报 错的话,那么说明此事这个jar包是多余的。注意jar包一定不要引入不需要的。最后你会发现只需要7个就够了。还有另一种方案,就是一个一个的添加 jar包,直到junit不报错为止。首先要想让ApplicationContext类可以识别,必须导入context的两个包,你观察spring 的结构图

    160158_dsoI_1782822.jpg

通过这个图 你会想到 core container中相关的jar也应该是必须的,通过这种思路,如果运行是报错,直接将错误信息当关键字搜索,你一定可以集成spring的任何版本,并且对spring的各个jar包的作用慢慢都有所了解。

第三大步集成hibernate,完成User的真正持久化

事实上我们采用的是JPA的规范配置数据库持久层。所以要集成的是spring与jpa。参考spring-framework-reference.html 第 13.5节 spring 与 jpa的集成。

配置JPA之前你应该对 spring文档中IV. Data Access 有个大体的了解


我们采用第三种集成方式

http://www.markliublog.com/post-ref/07_build-env-integrate-ssh/img05.jpg

依据文档的说明

<beans>
	<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="dataSource" ref="someDataSource" />
		<property name="loadTemeWeaver">
			<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
		</property>
	</bean>
</beans>

我们首先配置一个管理所有实体类的bean。观察这个bean的配置使用到了一个dataSource。所以我们应该先配置一个 dataSource。

参考文档中12.3.1 DataSource配置dataSource。

依据文档我们应该在beans.xml 文件中添加dataSource的配置

<!--
	At runtime, a PropertyPlaceholderConfiguer is applied to the metadata
	that will replace some properties of theDataSource.
	The values to replace are specified as ‘placeholder’ of the form ${property-name}
	which follows the Ant / Log4J / JSP EL style
-->
<context:property-placeholder location="classpath:jdbc.properties" />

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName" value="${jdbc.driverClassName}" />
	<property name="url" value="${jdbc.url}" />
	<property name="username" value="${jdbc.username}" />
	<property name="password" value="${jdbc.password}" />
	<property name="initialSize" value="${jdbc.initialSize}" />
	<property name="maxActive" value="${jdbc.maxActive}" />
	<property name="maxIdle" value="${jdbc.maxIdle}" />
	<property name="minIdle" value="${jdbcminIdle" />
</bean>

并新建jdbc.properties

运行junit,报错。从错误信息the prefix “context” for element “context:property-placeholder” is not bound. 我们发现在beans.xml 中添加xmlns:context=http://www.springframework.org/schema/context的命名空间。文档中有 说明。

再次运行测试又报一个java.lang.ClassNotFoundException:org.apache.commons.dbcp.BasicDataSource
很明显缺数据源的实现。添加commons-dbcp-1.4.jar,再次运行测试。
java.lang.NoClassDefFoundError: org/apache/commons/pool/KeyedObjectPoolFactory
引入commons-pool-1.5.5.jar 再运行,没有报错。此时beans.xml中数据源的配置才算成功。但我们并没有修改任何的insert操作实现。
也没有将实体类映射到数据库。接下来使用JPA完成真正的持久化操作。

接下来添加实体管理器bean配置,依据文档中的例子在beans.xml 中添加

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="dataSource" ref="dataSource"></property>
	<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"></property>
	<property name="loadTimeWeaver">
		<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
	</property>
</bean>

配置这个bean需要的dataSource前面已经配置成功。接下来看到

<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"></property>

它告诉我们要在src下新建META-INF/persistence.xml 文件。在spring文档中你也可以看到。文件内容格式如下:

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"

	version="1.0">
	<persistence-unit name="ssh" transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		<properties>

			<!--
				The classname of a Hibernate org.hibernate.dialect.Dialect which
				allows Hibernate to generate SQL optimized for a particular
				relational database.
			-->
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />

			<!--
				Sets a maximum "depth" for the outer join fetch tree for
				single-ended associations (one-to-one, many-to-one). A 0 disables
				default outer join fetching. e.g. recommended values between 0 and 3
			-->
			<property name="hibernate.max_fetch_depth" value="3" />

			<!--
				Automatically validates or exports schema DDL to the database when
				the SessionFactory is created. With create-drop, the database schema
				will be dropped when the SessionFactory is closed explicitly.
			-->
			<property name="hibernate.hbm2ddl.auto" value="update" />

			<!--
				A non-zero value determines the JDBC fetch size (calls
				Statement.setFetchSize()).
			-->
			<property name="hibernate.jdbc.fetch_size" value="18" />

			<!--
				A non-zero value enables use of JDBC2 batch updates by Hibernate.
				e.g. recommended values between 5 and 30
			-->
			<property name="hibernate.jdbc.batch_size" value="10" />

			<!--
				Write all SQL statements to console. This is an alternative to
				setting the log category org.hibernate.SQL to debug. e.g. true |
				false
			-->
			<property name="hibernate.show_sql" value="true" />

			<!--
				Pretty print the SQL in the log and console. e.g. true | false
			-->
			<property name="hibernate.format_sql" value="true" />

		</properties>
	</persistence-unit>
</persistence>

运行测试,根据所报异常,逐个添加所需的jar包。java.lang.ClassNotFoundException:org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean

引入org.springframework.orm-3.0.4.RELEASE.jar

java.lang.ClassNotFoundException: org.springframework.dao.support.PersistenceExceptionTranslator
引入org.springframework.transaction-3.0.4.RELEASE.jar

java.lang.ClassNotFoundException: org.springframework.jdbc.datasource.lookup.DataSourceLookup
引入org.springframework.jdbc-3.0.4.RELEASE.jar

java.lang.ClassNotFoundException: javax.persistence.PersistenceException这个类并不属于spring,而是JPA规范,此规范在 hibernate 安装包里有hibernate-jpa-2.0-api-1.0.0.Final.jar

java.lang.ClassNotFoundException: org.hibernate.ejb.HibernatePersistence此时已经开始进入hibernate的类库了。

关于hibernate框架所需要的jar包。毫无疑问hibernate3.jar 这个是肯定要引入的。Hibernate项目也使用了其他框架的的jar包,这就必须引入hibernate所依赖的jar包。为什么不是简单的三个框架 三个jar包呢,就是因为他们都依赖了其他的jar包所以必须导入很多的包。打开hibernate的lib目录 很明显required目录下的包是必须的。导入hibernate的包后,运行junit发现没有了错误信息。

接下来采用注解配置User实体类。完成数据库的持久化操作。在beanx.xml中添加

<context: component-scan base-package="com.ssh.po" />

安装log4j,此时你在运行测试会发现控制台有找不到slf4j实现包的错误,hibernate默认使用的是slf4j记录日志,这个日志记录框架并 不是最好用的。我们将slf4j转换为目前最流行的log4j 导入slf4j-log4j12-1.6.1.jar(转换器) log4j-1.2.16.jar(日志实现)两个jar包。引入mysql的jdbc驱动包,运行测试此时日志信息非常丰富。通过观察控制台我们更容易 调错了。你发现控制台有下面的片段:

http://www.markliublog.com/post-ref/07_build-env-integrate-ssh/img06.jpg

我们完成了实体类与数据库之间的映射,hibernate帮我们自动建好了所需的表。查看数据库确实已存在user表。集成hibernate我们已成功了一半。因为后面还有事务的配置也是一个很麻烦 的操作。

改变UserDao中的实现,使用EntityManager对象完成insert操作。

在com.ssh.dao.impl包下新建SuperDao,SuperDao持有EntityManager,后面所有的dao实现类都继承该SuperDao,方便使用EntityManager。

package com.ssh.dao.impl;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class SuperDao {

	@PersistenceContext(unitName = "ssh")
	protected EntityManager em;

	public void insert(T entity) {
		em.persist(entity);
	}

}

将UserDaoBean的实现改为(要继承前面的SuperDao)

em.persist(user);
System.out.println("默认实现:添加一个用户名为" + user.getName() + "的用户");

接下来我们单独建立UserDao 的测试类,以确保可以往数据库中添加数据。要想在spring中测试dao是一件麻烦事,你在测试前必须实例化ioc容器。还有获得spring管理的对 象等。幸好,spring框架中,提供了测试dao的框架。文档在9. Testing 中有说明。

引入org.springframework.test-3.0.4.RELEASE.jar(这个包和以及junit的包在项目开发完应该删除),以com.ssh.dao.impl.UserDaoBean新建测试用例。代码如下:

@RunWith(SpringJunit4ClassRunner.Class)
@ContextConfiguration(locations = { "classpath:beans.xml" })
@TransactionConfiguration(transactionManager = "txManager")
@Transactional
public class UserDaoBeanTest extends AbstractTransactionalJunit4SpringContextTests {
	@Resource
	private UserDao userDao;

	@Test
	@Rollback(false)
	public void testInsert() {
		User user = new User();
		user.setName("张三");
		user.setPassword("123456");
		userDao.insert(user);
	}
}

运行测试用例。报错 关键信息是‘No bean named ‘txManager’ is defined’,它提示我们还没有配置事务管理的bean,请参考spring文档中对应的10. Transaction Management和10.5. Declarative transaction management 在beans.xml中配置事务。

很简单配置事务我们只需要在beans.xml添加

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
	<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>

再次运行测试用例,发现后台打印了insert 语句,查询数据里面多了一条记录。

现在基本完成了spring与hibernate的集成。但还差一个重要的事务管理,此时userService的add方法不在一个事务中,在前 台界面添加数据时,默认是会回退的,有时我们在测试时,没报任何错误,后台也打印了insert 语句,但是数据库里面就是没有数据,有可能就是没有事务管理,使操作回退了。这里之所以没有回退是因为spring提供的测试框架包含了事务。所以我们应 该在beans.xml中添加声明式事务管理的配置。参考文档10.5.1 Understanding the Spring Framework’s declarative transaction implementation

<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService" />

<!-- the transactional advice(what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
	<!-- the transactional semantics... -->
	<tx:attributes>
	<!-- all methods starting with 'get' are read-only -->
	<tx:methods name="get*" read-only="true"/>
	<!-- other methods user the default transaction setting (see below) -->
	<tx:method name="*">
	</tx:attributes>
</tx:advice>

<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the FooService interface-->
<aop:config>
	<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(...))"/>
	<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>

这里我们先复制一个配置,然后根据项目进行修改。更改后的事务配置如下图

<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService" />

<!-- the transactional advice(what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
	<!-- the transactional semantics... -->
	<tx:attributes>
	<!-- all methods starting with 'get' are read-only -->
	<tx:methods name="get*" read-only="true"/>
	<tx:methods name="find*" read-only="true"/>
	<!-- other methods user the default transaction setting (see below) -->
	<tx:method name="*">
	</tx:attributes>
</tx:advice>

运行junit 有报错 可以看出我们还应该添加xmlns:tx=http://www.springframework.org/schema/tx和
xmlns:aop=http://www.springframework.org/schema/aop的命名空间 修改后的beans.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:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"

	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/aop


http://www.springframework.org/schema/aop/spring-aop-3.0.xsd


http://www.springframework.org/schema/tx


http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

此处添加了这两个命名空间以后,会报错,这个错误信息很奇怪。schema_reference.4: Failed to read schema document ‘http://www.springframework.org/schema/aop/spring-aop-3.0.xsd’, because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not.

此处还是因为差org.springframework.aop-3.0.4.RELEASE.jar 的jar包。这里并没有包类找不到的错误。

运行测试用例,下一个错误是‘org/aopalliance/intercept/MethodInterceptor’找不到。你可以直接把 这个错误信息当关键字在网上搜索。这里缺少aopalliance.jar(AOP联盟的包)。导入后运行junit org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException找不到,引 入aspectjweaver.jar。运行junit此时已经没有错误,完成了事务管理xml方式的配置。现在我们已经将spring和 hibernate集成了。接下来在项目中引入struts2 框架。

第四大步集成struts2 框架,完成用户登录的功能

现在我们的项目已经引进了spring和hibernate,建好了实体类。并可以完成user的新增操作。接下来我们要使用struts2的 MVC完成用户的登录功能。首先引入struts2-core-2.2.1.1.jar,这个是毫无疑问必须添加进去的。这个包还依赖其他的什么包暂时不 知道。我们来一步一步加入所需引入的最小包,绝不多加一个无用的jar包进项目。接下来修改web.xml 配置struts2 的总过滤器。

<filter>
	<filter-name>struts2</filter-name>
	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>struts2</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

我们可以参考struts2 的 例子项目struts2-blank,这个项目里面配置可以直接copy 进来改。而且这个项目lib里面的jar包很可能就是允许struts2 所需的最小依赖包。

现在我们需要把项目部署到tomcat 发现 后台报java.lang.NoClassDefFoundError: com/opensymphony/xwork2/ActionContext 这是因为缺少struts2.2.1所依赖的包,你在web.xml中配置的filter 依赖这个包xwork-core-2.2.1.1.jar。不断地引入后重新启动tomcat。

org/apache/commons/io/output/NullOutputStream 引入 commons-io-1.3.2.jar org/apache/commons/fileupload/RequestContext 引入commons-fileupload-1.2.1.jar
引入freemarker-2.3.16.jar 和ognl-3.0.jar 。直到tomcat启动时,后台无报错信息。将struts2 例子项目struts2-blank 中的struts.xml 复制到项目的src目录下。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

	<constant name="struts.enable.DynamicMethodInvocation" value="false" />
	<constant name="struts.devMode" value="true" />
	<constant name="struts.i18n.encoding" value="UTF-8" />

	<package name="defalut" namespace="/" extends="struts-default"></package>

</struts>

将index.jsp 修改为登录页面。并新建LoginSuccess.jsp 和 LoginFailure.jsp作为登录操作完成后跳转的页面。

新建LoginAction,并在struts.xml中配置该action。已经可以成功跳转了。但此时只是引入了struts2,并没有将 struts2 与 spring 集成。集成后,struts2 的action 也要交给spring 的ioc容器管理。并且action也可以依靠spring注入需要的对象。
引入struts2-spring-plugin-2.2.1.1.jar,在struts.xml中添加

然后将struts2的action配置到beans.xml中,注意不要配置成单例模式。然后struts.xml中配置action时,class属性写spring配置时用的id。

最后在web.xml中中添加spring有关的配置。内容如下。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<!--
Specifies the spring configuration file, the default root directory
from the web to find the configuration file, we can provide the
classpath by spring : Prefix from the class path in search
-->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:beans.xml</param-value>
	</context-param>

<!-- On the spring container instantiate -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

<!--
Configuration because of the entityManager close to delay loading
exceptions
-->
	<filter>
		<filter-name>OpenEntityManagerInViewFilter</filter-name>
		<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>OpenEntityManagerInViewFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

</web-app>

至此我们基本完成了三个框架的整合。

小结一下

在整合三个框架时,其实里面是有一条线的,抓住这条线,一步一步排除每个错误,不断的引入项目所需要的jar,修改配置文件,最后也就把三个框架集 成进了项目。我采用的方法是先引入spring,然后hibernate,最后struts2。Spring文档中有对每个框架集成的详细说明,以 spring为一条线,集成另外两个框架。在集成的过程中,要搭建好测试环境,根据错误信息不断的完善,集成框架也就是水到渠成了。集成三个框架之后,与 数据库的操作我们只需要了解EntityManager对象提供的方法。与后台的数据交互,我们只需要新建action类,配置到 struts2.xml。这样分层合理,每个人只需要负责一块,不会影响到别的模块。

最后方式项目下载地址:http://www.markliublog.com/post-ref/07_build-env-integrate-ssh/ssh.zip


转载于:https://my.oschina.net/mjhuang/blog/275287

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值