文档章节

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

mjhuang
 mjhuang
发布于 2014/06/06 18:01
字数 6305
阅读 211
收藏 3

本文介绍如何搭建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目录结构如下图所示:

     

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

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

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

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

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

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

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 的结构图

   

通过这个图 你会想到 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


本文转载自:http://www.markliublog.com/build-env-integrate-ssh.html

共有 人打赏支持
mjhuang
粉丝 0
博文 28
码字总数 5952
作品 0
广州
程序员
SSH框架总结(框架分析+环境搭建+实例源码下载)

首先,SSH不是一个框架,而是多个框架(struts+spring+hibernate)的集成,是目前较流行的一种Web应用程序开源集成框架,用于构建灵活、易于扩展的多层Web应用程序。 集成SSH框架的系统从职责...

beibugulf
2016/10/08
137
0
SSH2框架搭建. 还有一个springMVC+mybaits框架搭建的代码下载,哪里有?怎么使用一个最新版本的SSH2框架

SSH2框架搭建. 还有一个springMVC+mybaits框架搭建的代码下载,哪里有?怎么使用一个最新版本的SSH2框架,,,最好是基于oracle连接的,网上有成熟的最新的例子吗?spring出到最新版本的,4...

Baclk5
2014/08/05
631
1
SSH框架总结(框架分析+环境搭建+实例源码下载)

首先,SSH不是一个框架,而是多个框架(struts+spring+hibernate)的集成,是目前较流行的一种Web应用程序开源集成框架,用于构建灵活、易于扩展的多层Web应用程序。 集成SSH框架的系统从职责...

亚特兰缇斯
2015/03/04
238
0
关于java的Myeclipse,配置SSH框架的问题 ?

做项目的时候 搭建SSH框架, 可以用Myeclipse自带的jar包吗? 就是用Myeclipse内部集成好的jar文件来搭建ssh 请问这样做有啥好处 和不好处? 各位大神一般搭建框架都是用Myeclipse自带的还是,...

叫_兽
2014/11/05
239
3
Spring Boot从入门到精通课程

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这...

尹吉欢
2017/12/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

js 操作cookie

var cookie = {// 设置cookie方法 set:function(key,val,time){ // 获取当前时间 var date = new Date(); // 将date设置为n天以后的时间 var exp...

小丶二
5分钟前
0
0
限制root远程登录 su和sudo命令

9月21日任务 3.7 su命令 3.8 sudo命令 3.9 限制root远程登录 对于Linux而言,权限的重要性毋庸置疑!对于普通用户而言无法执行那些只有root用户才能有效的命令,导致工作无法有效进行; 系统...

robertt15
7分钟前
0
0
MQTT协议的初浅认识之通讯级别和持久会话

背景 这是我最近了解MQTT协议的最后一部分内容了,MQTT协议里面的QOS和Keep Alive是两个比较重要的内容。QOS的设置,直接影响了订阅客户端与中间件之间的消息交互行为。而Keep Alive直接影响...

亚林瓜子
9分钟前
0
0
calc

width: calc(100% - 30px); 特别注意:减号左右空格,均不能去掉。 width: calc(100% - 30px);

柴高八斗之父
17分钟前
0
0
Spring Cloud Gateway全局过滤器GlobalFilter:返回消息和重定向

Spring Cloud Gateway的全局过滤器GlobalFilter,顾名思义,声明后会对所有的请求生效,可以用来做权限控制,这里简单记录一下拦截到非法请求后如何返回自定义信息和将请求重定向到指定URL。...

夜雨寄北09
19分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部