阅读提示:读者在阅读3中内容时,可以结合4中的原理介绍和5中的SSH三大框架整体工作流程理解。
若对文中提到的IOC、AOP概念模糊,可先移步到:Spring基础、IOC(控制反转)、AOP(面向切面编程)、Log4j、注解配置
2)Spring整合JDBC的步骤(示例见SpringTest02)

引入JDBC开发包
--根据COST表编写实体类--定义CostDao接口,编写实现类并继承JdbcDaoSupport,在实现类的增删改查方法中,利用super.getJdbcTemplate()工具完成相应操作
@Repository("jdbcCostDAO")
// @Scope("singleton")// 默认情况是单例
public class JdbcCostDAO extends JdbcDaoSupport implements ICostDao {
@Resource
// 将容器中的dataSource给DAOSupport注入
public void setMyDataSource(DataSource ds) {
super.setDataSource(ds);// DaoSupport利用ds实例化template对象,使得getJdbcTemplate()可以获取连接
}
@Override
public List<Cost> findAll() throws DataAccessException {
String sql = "select * from COST";
CostMapper mapper = new CostMapper();
List<Cost> list = super.getJdbcTemplate().query(sql, mapper);
return list;
}
@Override
public List<Cost> findByPage(int page, int pageSize)
throws DataAccessException {
String sql = "select ID,NAME,BASE_DURATION,BASE_COST,UNIT_COST,STATUS,DESCR,CREATIME,STARTIME,COST_TYPE from(select ID,NAME,BASE_DURATION,BASE_COST,UNIT_COST,STATUS,DESCR,CREATIME,STARTIME,COST_TYPE,rownum n from COST where rownum < order by ID)where n>";// 分页
// 算当前页最大行:当前页数2*每页显示5=当前最大行10
// 小于下一页的最小行
int nextMin = page * pageSize + 1;
// 大于上一页的最大行
int lastMax = (page - 1) * pageSize;
Object[] params = { nextMin, lastMax };
CostMapper mapper = new CostMapper();
List<Cost> list = super.getJdbcTemplate().query(sql, params, mapper);
return list;
}
@Override
public int findTotalPage(int pageSize) throws DataAccessException {
String sql = "select count(*) from COST";
int size = super.getJdbcTemplate().queryForInt(sql);
if (size % pageSize == 0) {
return size / pageSize;
} else {
return size / pageSize + 1;
}
}
@Override
public void deleteById(Integer id) throws DataAccessException {
String sql = "delete from COST where ID=";
Object[] params = { id };
super.getJdbcTemplate().update(sql, params);
}
@Override
public Cost findByName(String feeName) throws DataAccessException {
String sql = "select * from COST where NAME=";
Object[] params = { feeName };
CostMapper mapper = new CostMapper();
Cost cost = (Cost) super.getJdbcTemplate().queryForObject(sql, params,
mapper);
return cost;
}
@Override
public Cost findById(Integer id) throws DataAccessException {
String sql = "select * from COST where ID=";
Object[] params = { id };
CostMapper mapper = new CostMapper();
Cost cost = (Cost) super.getJdbcTemplate().queryForObject(sql, params,
mapper);
return cost;
}
@Override
public void updateCost(Cost cost) throws DataAccessException {
String sql = "update cost set name=,base_duration=,"
+ "base_cost=,unit_cost=,cost_type=,descr= " + "where id=";
Object[] params = { cost.getName(), cost.getBaseDuration(),
cost.getBaseCost(), cost.getUnitCost(), cost.getCostType(),
cost.getDescr(), cost.getId() };
super.getJdbcTemplate().update(sql, params);
}
}
CostMapper.java:
public class CostMapper implements RowMapper{
//将rs中当前游标指定的记录转换成实体对象
public Object mapRow(ResultSet rs, int index) throws SQLException {
Cost c = new Cost();
c.setId(rs.getInt("id"));
c.setName(rs.getString("name"));
c.setBaseDuration(rs.getInt("base_duration"));
c.setBaseCost(rs.getDouble("base_cost"));
c.setUnitCost(rs.getDouble("unit_cost"));
c.setStatus(rs.getString("status"));
c.setDescr(rs.getString("descr"));
c.setCreateTime(rs.getDate("creatime"));
c.setStartTime(rs.getDate("startime"));
c.setCostType(rs.getString("cost_type"));
return c;
}
}
--将CostDao实现组件扫描到Spring容器
--在Spring容器定义一个连接池对象(需引入连接池开发包[dbcp+数据库驱动],在Spring配置中添加dataSource组件定义),然后将连接池对象给CostDao注入,目是为JdbcTemplate设置Connection连接资源.(方法:在Dao中定义一个setXXX方法,接收注入的DataSource对象,然后给DaoSupport传入)
applicationContext.xml:
<span style="font-size:14px;"><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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" 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/aop http://www.springframework.org/schema/aop/spring-aop-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 "> <!-- 开启组件扫描 --> <context:component-scan base-package="com.test"></context:component-scan> <!-- 定义一个连接池对象dataSource --> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="username" value="system"></property> <property name="password" value="123456"></property> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property> <property name="url" value="jdbc:oracle:thin:@localhost:1521:test"></property> <property name="maxActive" value="20"></property><!-- 最大连接数 --> <property name="initialSize" value="1"></property><!-- 初始连接数 --> </bean> </beans></span>
--测试Dao方法
@Test
public void test1() {
String conf = "/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(conf);
ICostDao costDao = (ICostDao) ac.getBean("jdbcCostDAO");
//costDao.deleteById(122);
List<Cost> list = costDao.findAll();
for (Cost c : list) {
System.out.println(c.getId() + " " + c.getName());
}
}
3)JdbcTemplate API的使用(示例见SpringTest03)

b.根据COST表编写实体类和hbm.xml
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> <!-- 通过class指定实体类和表的关系 --> <class name="com.test.pojo.Cost" table="cost" dynamic-update="true"> <!-- 通过id元素指定主键属性和字段的关系: name:指定主键属性 column:指定主键字段 --> <id name="id" type="integer" column="id"> <!-- 用来指明主键的生成方式 --> <generator class="sequence"> <param name="sequence">cost_seq</param> </generator> </id> <!-- 通过property元素指定属性和字段的关系: name:指定的是实体类中的属性 column:指定都是表中的字段 type:指定的是属性与字段转换时的类型 --> <property name="name" type="string" column="name" /> <property name="baseDuration" type="integer" column="base_duration" /> <property name="baseCost" type="double" column="base_cost" /> <property name="unitCost" type="double" column="unit_cost" /> <property name="status" type="string" column="status" /> <property name="descr" type="string" column="descr" /> <property name="createTime" type="date" column="creatime" /> <property name="startTime" type="date" column="startime" /> <property name="costType" type="string" column="cost_type" /> </class> </hibernate-mapping>c.定义DAO接口,根据接口编写实现类(继承HibernateDaoSupport,使用HibernateTemplate)
--HibernateTemplate提供了增删改查处理方法。save()、delete()、updata()、load()、get()、find()
@Repository("hibernateCostDAO")
// @Scope("singleton")// 默认情况是单例
public class HibernateCostDAO extends HibernateDaoSupport implements ICostDao {
@Resource
public void setMySessionFactory(SessionFactory sf) {
// 将注入的sessionFactory,用于实例化template
super.setSessionFactory(sf);
}
@Override
public List<Cost> findAll() throws DataAccessException {
String sql = " from Cost";
List<Cost> list = super.getHibernateTemplate().find(sql);
return list;
}
@Override
public List<Cost> findByPage(int page, int pageSize) {
List list = (List) super.getHibernateTemplate().execute(
new HibernateCallback() {
@Override
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
String hql = "from Cost";
Query query = session.createQuery(hql);
int begin = (page - 1) * pageSize;
query.setFirstResult(begin);
query.setMaxResults(pageSize);
return query.list();
}
});
return list;
}
@Override
public int findTotalPage(int pageSize) throws DataAccessException {
String hql = "select count(*) from Cost";
Session session = super.getSession();
long size = (Long) session.createQuery(hql).uniqueResult();
session.close();// 一定记得关闭session,使用getHibernateTemplate()会在调用结束后自动关闭session
if (size % pageSize == 0) {
return (int) (size / pageSize);
} else {
return (int) (size / pageSize + 1);
}
}
@Override
public void deleteById(Integer id) throws DataAccessException {
Cost cost = findById(id);
super.getHibernateTemplate().delete(cost);
}
@Override
public Cost findByName(String feeName) throws DataAccessException {
String sql = "from Cost where NAME=";
Object[] params = { feeName };
List<Cost> cost = super.getHibernateTemplate().find(sql, params);
if (cost.isEmpty()) {
return null;
}
return cost.get(0);
}
@Override
public Cost findById(Integer id) throws DataAccessException {
Cost cost = (Cost) super.getHibernateTemplate().load(Cost.class, id);
return cost;
}
@Override
public void updateCost(Cost cost) throws DataAccessException {
super.getHibernateTemplate().update(cost);
}
}
d.将DAO实现类扫描到Spring容器
e.在Spring配置中,定义SessionFactory对象,给DAO注入。
<!-- 开启组件扫描 --> <context:component-scan base-package="com.test"></context:component-scan> <!-- 定义一个连接池对象dataSource --> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="username" value="system"></property> <property name="password" value="123456"></property> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property> <property name="url" value="jdbc:oracle:thin:@localhost:1521:test"></property> <property name="maxActive" value="20"></property><!-- 最大连接数 --> <property name="initialSize" value="1"></property><!-- 初始连接数 --> </bean> <!-- 定义SessionFactory组件,给DAO注入 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!--注入连接池对象 --> <property name="dataSource" ref="myDataSource"></property> <!-- 注入Hibernate 框架参数 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> <!-- 注入映射描述文件 --> <property name="mappingResources"> <list> <value>com/test/pojo/Cost.hbm.xml</value> </list> </property> </bean>
@Test
public void test1() {
String conf = "/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(conf);
ICostDao costDao = (ICostDao) ac.getBean("hibernateCostDAO");
// costDao.deleteById(122);
List<Cost> list = costDao.findAll();
for (Cost c : list) {
System.out.println(c.getId() + " " + c.getName());
}
}(示例见SpringTest04)

*3)采用组件扫描,将Action交给Spring管理
applicationContext.xml:
<!-- 开启组件扫描 --> <context:component-scan base-package="com.test"></context:component-scan>*4)引入struts2-spring-plugin.jar开发包【原理见下文4】
*5)修改原有<action>配置,将class属性指定成Spring中Action对象的id值
@Service
@Scope("prototype")
public class HelloAction {
private String msg;
@Resource
private MessageDao dao;
public String execute() {
msg = dao.getMessage();
System.out.println("执行Action...");
return "success";
}
//省略get/setMsg();
}//交由StrutsSpringObjectFactory创建
//将Spring容器中id名与setxxx一致的Bean对象注入
public class HelloAction1 {
private String msg;
private MessageDao dao;
// StrutsSpringObject将Spring容器中id名与setxxx一致的Bean对象注入
public void setJdbcMessageDao(MessageDao dao) {
this.dao = dao;
}
public String execute() {
msg = dao.getMessage();
return "success";
}
//省略get/setMsg();
}public interface MessageDao {
public String getMessage();
}@Repository//配置注解后默认id=jdbcMessageDao
public class JdbcMessageDao implements MessageDao {
public String getMessage() {
// 访问数据库,获取出信息
System.out.println("访问数据库,获取出信息");
return "新年快乐";
}
}struts.xml:<struts> <!-- http://localshost:8080/struts01a/NAMESPACE/ACTIONNAME.action --> <!-- 记忆口诀: URL虽然长,namespace站中央; action name排队尾,action后缀不要忘; extends包继承,action class做封装; action method找方法,返回值让result忙 --> <package name="demo1" namespace="/day01" extends="struts-default"> <!-- struts2-spring-plugin.jar利用helloAction 当做id去Spring容器寻找Bean对象 --> <!-- 走StrutsSpringObjectFactory的try流程,整合方法一(参考4中原理分析图ssh-1.jpg) --> <action name="hello" class="helloAction" method="execute"> <result>/hello.jsp</result> </action> <!-- 走StrutsSpringObjectFactory的catch流程,整合方法二(参考4中原理分析图ssh-2.jpg),此时生成的Action在容器外 --> <action name="hello1" class="com.test.action.HelloAction1" method="execute"> <result>/hello.jsp</result> </action> </package> </struts>hello.jsp:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
信息:
<br />${msg }
</body>
</html>index.jsp:
<html> <head> </head> <body> <a href="day01/hello.action">Struts+Spring整合案例1</a><!--走try逻辑,见下文4原理分析 --> <a href="day01/hello1.action">Struts+Spring整合案例2</a><!-- 走catch逻辑,见下文4原理分析 --> <br> </body> </html>
*6)在web.xml中定义ContextLoaderListener,用于在服务器启动时,实例化Spring容器,在web.xml中采用<content-param>指定Spring。
web.xml:
<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> <!-- 指定Spring配置位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 封装了实例化Spring容器功能 --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></span>
7)测试

点击任何链接都可看到相同效果:

在Struts2底层有一个StrutsObjectFactory组件,用于实例化Struts2中的Action等组件对象。当引入了struts2-spring-plugin之后,该插件提供了一个StrutsSpringObjectFactory组件,它也属于ObjectFactory组件。在struts2-spring-plugin配置(struts-plugin.xml)中将原来Struts2的ObjectFactory指定成了StrutsSpringObjectFactory。因此Struts再接收请求后,会利用StrutsSpringObjectFactory获取Action对象。
struts-plugin.xml核心代码:
<struts>
<bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory"/>
<!-- Make the Spring object factory the automatic default -->
<constant name="struts.objectFactory" value="spring" />
...
</struts>而在StrutsSpringObjectFactory中提供一个获取Action对象的方法,该方法主要逻辑如下:public class StrutsSpringObjectFactory{
//用于获取Action对象
public Object buildAction(){
try{
//ssh-1.jpg整合流程1
//获取web.xml中listener创建的Spring容器对象
ApplicationContext ac = ...;
//调用ac.getBean()获取Spring容器的Bean对象。用<action>配置中的class属性值去寻找
Object action = ac.getBean(class属性值)
//将返回的action对象交给Struts框架处理请求
return obj;
}catch(Exception ex){
//ssh-2.jpg整合流程2
//如果找不到class名字的Bean对象,会首先利用反射技术创建一个Action对象(在Spring容器外)
Class c = Class.forName(class属性值);
Object obj = c.newInstance();
//访问Spring容器,将Spring容器中id名和Action对象属性名一致的Bean对象,给Action对象注入
//返回Action对象给Struts框架处理请求
}
}
}综上,由于struts2-spring-plugin插件中StrutsSpringObjectFactory的buildAction的try...catch...流程,导致Struts和Spring有两种整合方ssh1.jpg:

ssh2.jpg:

转载请注明出处:
http://blog.csdn.net/daijin888888/article/details/51777488
热门源码