在框架的整合中,SSM已经介绍过了,即springMVC+spring+mybatis。那如何将spring和struts2结合起来呢,SSH则做了这件事情,将struts中的action对象交给spring来创建,这样最大的好处就是,我们在struts跳转时,通过spring就已经将action对象中的方法注入了属性值。struts的action交由spring创建经常使用的场景就是:在spring中创建dao实现类的bean,创建service实现类的bean,并注入dao的实现类bean,创建Action层的bean,在该bean中注入service的实现类bean。层层注入,最终struts跳转时创建的对象中的service中的方法即可直接使用。值得注意的是,此时struts的action为单实例。还有一点则为hibernate和spring的整合,通过dao的实现层继承了hibernateTemplate类,在spring中将dao的实现类(实则是给它的父类注入属性值)注入sessionFactory值。该值中包含数据库连接信息、实体与数据库映射文件、hibernate方言等配置。
接下来我们从零开始,搭建SSH开发环境。
一:环境搭建
1. 导入jar包;
2.创建项目,编写web.xml;
3. 创建实体类,dao层,action层等项目层级;
4. 配置spring,完成hibernate和struts中action的注册装配工作;
5. 配置struts,完成跳转和返回页面设置;
6. 配置hibernate的映射文件。
二:增删改查
三:流程分析
四:搭建技巧和注意事项
一:环境搭建
SSH的搭建可以理解为spring和struts的整合,然后将hibernate的配置信息装配至spring中。
1. 导入相关的jar包。截图如下:
2. eclipse中创建动态web项目,并生成web.xml文件。之前已经了解过spring和struts的整合过程了,即在web.xml中设置filter过滤器配置struts拦截,设置一个listener监听器,随着tomcat的启动扫描spring的配置文件。struts的配置文件读取默认是src下的struts.xml,spring的配置文件默认读取是在WEB-INF下的applicationContext.xml文件,可以在web.xml中设置读取spring配置文件的路径,添加以下代码即可。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
web.xml的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>ssh</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<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>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>
3. 创建实体类,action类,和dao层,这里创建过程不再贴代码出来了。其中dao层的实现类,因为需要使用hibernate进行JDBC交互。所以采用继承hibernateTemplate的方式进行数据库查询。要完成hibernate数据库查询,最重要的一步就是给sessionFactory注入配置信息。这一步时spring完成的。dao层的实现了如下:添加了增删查的方法。
public class HeroDaoImpl extends HibernateTemplate implements HeroDao {
public List<Hero> getHeroList() {
return find("from Hero");
}
public void add(Hero hero) {
save(hero);
}
public void del(int id) {
List<Hero> lh = find("from Hero where id="+id);
Hero h = new Hero();
for (Hero hero : lh) {
h = hero;
}
delete(h);
}
}
4. 配置spring文件:主要是配置hibernate的sessionFactory的注入和struts的action的注入。
applicationContext.xml配置文件代码如下:主配置文件完成主要bean的注册,然后通过import标签读取各分支配置文件。增加了代码的可读性。
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="sessionFctory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="data"/>
<property name="mappingResources"> 此处为配置hibernate的映射文件路径
<list>
<value>hbm/Hero.hbm.xml</value>
</list>
</property>
<property name="schemaUpdate">
<value>true</value>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hbm2ddl.auto=update
</value>
</property>
</bean>
<bean id="data" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<import resource="spring/spring-*.xml"/> 通过import标签读取其他字配置文件路径
</beans>
spring-hero.xml中:主要完成了dao实现层的装配,把dao装配至service中,再把service装配到action中,struts跳转时,即可直接使用了。
我们已经了解了,struts在跳转时,是多实例的,即每一次action请求都会创建一个实例对象,而由spring创建的action则是单实例的,我们只需在action的bean中添加scope="prototype",告诉spring,我要多实例即可。
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="heroAction" class="com.action.HeroAction" scope="prototype">
<property name="heroService" ref="heroService"/>
</bean>
<bean id="heroService" class="com.service.impl.HeroServiceImpl">
<property name="heroDao" ref="heroDao"/>
</bean>
<bean id="heroDao" class="com.dao.impl.HeroDaoImpl">
<property name="sessionFactory" ref="sessionFctory"/>
</bean>
</beans>
5. 配置struts文件,struts的配置主要就是完成页面的跳转。唯一不同的就是action中指向的不再是具体的类路径,而是bean的id。
可通过配置主文件struts.xml,通过include读取子配置文件。
struts.xml文件如下:
<?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.i18n.encoding" value="UTF-8"/> 设置编码方式
<constant name="struts.objectFactory" value="spring"/>
声明struts的action由spring创建(不声明时,struts也会自动去
寻找spring中的bean进行匹配的)
<include file="struts/struts-hero.xml"/> 读取子配置文件
</struts>
struts-hero.xml文件如下:完成了对action的跳转和返回页面的配置。其中action的class指向的是spring中的bean。
<?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>
<package name="hero" extends="struts-default">
<action name="heroList" class="heroAction" method="list">
<result name="OK">jsp/hero/heroList.jsp</result>
</action>
<action name="addHero" class="heroAction" method="add">
<result name="OK" type="redirect">/heroList</result>
</action>
<action name="deleteHero" class="heroAction" method="del">
</action>
</package>
</struts>
6. hibernate的实体映射文件,在配置sessionFactory时,需要通过mappingResources属性完成读取映射文件。映射文件如下:
hbm/Hero.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.pojo">
<class name="Hero" table="hero_1">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
</class>
</hibernate-mapping>
至此,已经完成了SSH环境的整体搭建,此时只需要编写请求页面和响应页面,完成需要进行的业务逻辑即可,
二:增删改查
1. 查询所有数据库列表,实现思路是:前台页面发起action请求-->tomcat启动时,读取spring配置文件,完成了所有bean的注册和装配-->struts完成拦截并读取到处理该请求的action-->该action指向了spring中已经注册好的bean对象,并跳转值该对象的指定方法中-->在该对象中完成数据库查询,return result-->struts根据return完成页面跳转-->s标签循环显示数组数据-->OVER
发起的请求为heroList,action与显示JSP的代码如下:
public class HeroAction {
private HeroService heroService;
private List<Hero> heroList;
private Hero hero;
private int id;
public String list() {
heroList = heroService.getHeroList();
System.out.println(this);
return "OK";
}
public void del() {
HttpServletResponse res = ServletActionContext.getResponse();
try {
heroService.del(id);
res.getWriter().write("OK");
} catch (IOException e) {
e.printStackTrace();
}
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
</head>
<body>
<table align="center" border="1">
<tr>
<td>id</td>
<td>name</td>
<td>操作</td>
</tr>
<s:iterator value="heroList" var="h" status="st">
<tr>
<td>${h.id}</td>
<td>${h.name}</td>
<td><button id="${h.id}" class="c">删除</button></td>
</tr>
</s:iterator>
</table>
<font id="test"/>
<script type="text/javascript" src="js/heroJs.js"></script>
</body>
</html>
2. 删除时,前台传入需要删除数据的id值,后台根据该ID值删除该记录,本例使用jquery的ajax完成动态删除。后台和jsp代码上图中均有,js代码如下:
var del = "";
$(function () {
$("button.c").click(function() {
var id = $(this).attr("id");
var page = "deleteHero";
if(confirm("确认删除?")) {
$.ajax({
url:page,
type:"post",
data:{
id:id
},
dataType:"text",
success:function(result) {
if(result == "OK") {
window.location.reload();
del = "yes";
}else {
del = "no";
}
},
error:function() {
del = "no";
}
});
}
});
});
3. 增加时,只需jsp中提交form表单,跳转至struts的action,跳转至方法中,通过dao实现类中方法完成数据库插入操作。
4. SSH的事务管理。
三:流程分析
SSH配置顺序理解:
首先可以先认为是struts和spring的整合,然后再把hibernate的配置装配在spring中。
1. 访问路径/heroList
2. web.xml中的过滤器会将请求交由struts进行处理
3. struts根据heroList创建对应的heroActionBean
此时heroActionBean不再由Struts自己创建,而是由Spring创建
4. spring根据applicationContext.xml创建heroActionBean对应的对象HeroAction
5. Spring 创建HeroAction的时候 注入Service
6. 创建Service的时候注入DAO
7. Struts 调用HeroAction的list方法
8. 在list方法中调用注入好的dao,访问数据库,查询结果
9. 跳转到list.jsp显示数据
四:搭建技巧和注意事项
1. hibernate的自动生成表结构:
hbm2ddl.auto=update
但是有时候,会失效,不能自动生成表结构,需要在sessionfactory中加一个属性即可:
<property name="schemaUpdate">
<value>true</value>
</property>
2. spring+struts创建action时,action对象由struts创建时,他是多例的,交给spring创建后,他的实例就变成了单例了。可以通过scope="prototype",告诉spring,这个实例创建时,他要是多例的。单实例会带来很多严重的后果,因为所有请求的action都会同时使用同一个对象,当多用户访问发起多请求高并发情况时,就极有可能出现不同用户之间注入的数据混淆。则基本不会允许struts跳转action为时单实例对象。
3. 给spring配置事务管理,保证了数据的原子性,就是要么都成功,要么都失败。
如果执行十条数据,执行到第六条时抛出了异常,则这个事务就回回滚,前面插入的五条数据也会回滚,从而达到了都失败的效果,保证了事务的原子性。
4. 使用ajax和responseBody完成删除操作。
注意:使用responseBody注解时,是在springMVC跳转时采用的注解,直接return "",可以在ajax的返回结果中使用。
在struts框架中,如果return"" 了,则会去action中寻找result标签去匹配。就会报错,应该使用response.write方法完成返回结果的写入。
5. <constant name="struts.objectFactory" value="spring"/>
action的创建交给spring,此时struts中action的class实例化时,就直接引用spring已经实例化好了的bean即可。