从jsp+servlet学起,一直到如今的SSH框架,有些地方一次没理解,于是反复学了几次,历时近6个月,终于到了可以做到三大框架整合,那么开始吧。
强调:为了避免一些不必要的错误,一定要保证:myeclipse环境、工程环境、tomcat环境的jdk保持一致,具体错误情形可以参考我的另外一篇博客,关于tomcat启动报错的问题
1、新建一个webservice工程,建议将工程的编码改为utf-8
2、把jsp的编码形式改为utf-8,否则默认为ISO-8859-1,在页面中无法添加中文
3、将相关的jar包放入到WEB-INF下的lib中,全部jar包目录如下:
4、建立三个src folder:
src 存放源代码
config 存放配置文件
在config中再分三个包,分别为hibernate,spring和Struts,分别存放各自框架的相关配置文件
test 存放测试文件
提示:三大框架的配置文件都要求存放在classpath下,开发阶段也就是src folder下,因此若像我说的这样在src folder下又建立了其他的包,则需要在配置这些配置文件的路径的时候特别注意
工程结构如下:
5、在src下建立包:
com.tt.domain,用来存放持久化类和映射文件,例如我在这里写一个持久化类Page,代码如下:
package com.tt.domain;
import java.io.Serializable;
public class Page implements Serializable{
private Long pid;
private String pname;
private String pageurl;
//set和get方法略去
}
映射文件Page.hbm.xml配置如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--
用来描述一个持久化类
name 类的全名
table 可以不写 默认值和类名一样
catalog 数据库的名称 一般不写
-->
<class name="com.tt.domain.Page" table="page" >
<!--
标示属性 和数据库中的主键对应
name 属性的名称
column 列的名称
-->
<id name="pid" column="pid" length="200" type="java.lang.Long">
<!--
主键的产生器
就该告诉hibernate容器用什么样的方式产生主键
-->
<generator class="increment"></generator>
</id>
<!--
描述一般属性
-->
<property name="pname" column="pname" length="20" type="string">
</property>
<property name="pageurl" column="pageurl" length="200" type="java.lang.String"></property>
</class>
</hibernate-mapping>
当然,不要忘了在hibernate.cfg.xml中映射这个映射文件,语句如下:
<mapping resource="com/tt/domain/Page.hbm.xml" />
6、编写dao层和service层,代码如下:
//PageDao接口
package com.tt.dao;
import com.tt.domain.Page;
public interface PageDao {
public void savePage(Page page);
}
//PageDaoImpl类
package com.tt.dao.impl;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.tt.dao.PageDao;
import com.tt.domain.Page;
public class PageDaoImpl extends HibernateDaoSupport implements PageDao{
public void savePage(Page page) {
// TODO Auto-generated method stub
this.getHibernateTemplate().save(page);
}
}
//PageService接口
package com.tt.service;
import com.tt.domain.Page;
public interface PageService {
public void savePage(Page page);
}
//PageServiceImpl类
package com.tt.service.impl;
import com.tt.dao.PageDao;
import com.tt.domain.Page;
import com.tt.service.PageService;
public class PageServiceImpl implements PageService{
private PageDao pageDao;
public PageDao getPageDao() {
return pageDao;
}
public void setPageDao(PageDao pageDao) {
this.pageDao = pageDao;
}
public void savePage(Page page) {
// TODO Auto-generated method stub
this.pageDao.savePage(page);
}
}
从代码中我们可以看到,PageServiceImpl中保存的是PageDao接口,这就是spring最大的特点:完全的面向接口编程,这也是它实现解耦的其中一种方式
7、写spring的配置文件
配置如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingResources">
<list>
<value>com/tt/domain/Page.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<tx:advice id="tx" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" read-only="false"/>
<tx:method name="update*" read-only="false"/>
<tx:method name="delete*" read-only="false"/>
<!--
* 代表了除了上述的三种情况的以外的情况
-->
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.tt.service.impl.*.*(..))" id="perform"/>
<aop:advisor advice-ref="tx" pointcut-ref="perform"/>
</aop:config>
</beans>
紧跟着要测试一下,确保每一步都是正确的,这样配置下来心里才踏实,出错率也低,即使出错也好排查,好处这么多…………那就来测试一下吧,测试代码如下:
//测试类
package com.tt.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tt.domain.Page;
import com.tt.service.PageService;
public class TestSpring {
@Test
public void testsessionfactory(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
System.out.println(context.getBean("sessionFactory"));
}
}
测试没问题之后进行下一步:在spring配置文件中配置dao和service并且测试
配置内容如下:
<bean id="pageDao" class="com.tt.dao.impl.PageDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="pageService" class="com.tt.service.impl.PageServiceImpl">
<property name="pageDao">
<ref bean="pageDao"/>
</property>
</bean>
<bean id="page" class="com.tt.domain.Page"></bean>
测试代码如下:
//这个方法添加在上面那个测试类TestSpring中
@Test
public void TestService(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
PageService pageService = (PageService)context.getBean("pageService");
Page page = (Page)context.getBean("page");
page.setPname("tuniu");
page.setPageurl("http://www.tuniu.com");
pageService.savePage(page);
}
8、前面的测试没有问题之后证明spring和hibernate的整合成功,接下来就要将Struts2也整合进去,首先要写一个action类,代码如下:
package com.tt.action;
import com.opensymphony.xwork2.ActionSupport;
import com.tt.domain.Page;
import com.tt.service.PageService;
public class PageAction extends ActionSupport{
private PageService pageService;
public PageService getPageService() {
return pageService;
}
public void setPageService(PageService pageService) {
this.pageService = pageService;
}
public String savePage(){
Page page = new Page();
page.setPname("tuniu");
page.setPageurl("http://www.tuniu.com");
this.pageService.savePage(page);
return null;
}
}
9、写spring配置文件,把action注入到spring容器中,配置信息如下:
<bean id="pageAction" class="com.tt.action.PageAction" scope="prototype">
<property name="pageService">
<ref bean="pageService"/>
</property>
</bean>
注意:在spring中bean默认为单例,但是按照Struts2的要求,action应该为多例,因此在这里配置时使scope=”prototype”
然后写Struts.xml,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<!----> <package name="page" namespace="/" extends="struts-default">
<action name="pageAction_*" method="{1}" class="pageAction">
<result ></result>
</action>
</package>
</struts>
注意:
1、由于在这个例子中不打算写前端表单,因此会直接在浏览器上访问action,访问之后可以实现在数据库中插入一条数据,则证明三大框架已经打通,因此在action的配置中result为空,不进行页面跳转,与之对应的是action类中return的是null
2、由于action的创建已经交给spring来做,因此action配置中的class应该是spring配置文件中配置的相应action类的id
10、在web.xml中加入spring的监听器和Struts2的过滤器,代码如下:
<?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">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<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>