※ssh整合
ssh指struts+spring+hibernate三大框架,通过ssh三大框架间的配合使用来开发项目是jee中较流行的一种方式,下边通过一个案例来说明ssh的整合,案例使用一个雇员管理系统
具体步骤:
创建web项目
(1)先整合spring
①引入spring开发包
②编写applicationContext.xml文件(或者beans.xml),将该文件放在src目录下(也可以根据情况建立另外的包并放在包下),下边是该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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
</beans>
③测试spring是否ok
建一个test包,写一个简单的TestService类并在applicationContext.xml里装配bean,再写一个Test类进行测试,测试ok表明目前spring可以工作
④在web.xml中初始化我们的spring容器,这样在启动Tomcat的时候,就会实例化spring容器
<!-- 指定spring的配置文件,默认从web根目录寻找配置文件,可以通过spring提供的classpath:前缀指定从类路径下寻找 -->
<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>
⑤配置后,spring容器由web容器接管
// 通过下面语句可以直接获取到spring容器实例,即ApplicationContext
WebApplicationContext ctx = WebApplicationContextUtils
.getWebApplicationContext(this.getServlet().getServletContext());
(2)整合hibernate
①加入hibernate开发包
②因为使用的是ssh,所以hibernate的核心就被spring接管了。hibernate.cfg.xml文件对象映射文件,SessionFactory在spring的文件中配置即可
③在applicationContext.xml中配置数据源
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://localhost:3306/graduation_project"></property>
<property name="username" value="root"></property>
<property name="password" value="123"></property>
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="30"></property>
<!-- 连接池的最大值 -->
<property name="maxActive" value="500"></property>
<!-- 最大空闲值,当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接释放一部分,一直减少到maxIdle为止 -->
<property name="maxIdle" value="2"></property>
<!-- 最小空闲值,当空闲的连接数少于阀值时,连接池就会预申请一些连接,以免洪峰来时来不及申请 -->
<property name="minIdle" value="1"></property>
</bean>
④在applicationContext.xml中配置SessionFactory对象
<!-- 配置会话工厂 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 接管了hibernate对象映射文件 -->
<property name="mappingResources">
<list>
<value>com/lewis/domain/Employee.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=false
</value>
</property>
</bean>
⑤编写domain对象和映射文件Employee.hbm.xml,测试spring和hibernate是否可以结合使用
⑥考虑分层
⑦使用事务管理器来统一管理事务,在applicationContext.xml中配置事务管理器
<!-- 配置事务管理器,统一管理SessionFactory的事务 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 启用事务注解 -->
<tx:annotation-driven transaction-manager="txManager"/>
接下来添加事务注解
//这里配置@Transactional用处是让spring的事务管理器接管该Service的事务,也可以只将注解添加在某个方法前
@Transactional
public class EmployeeServiceImpl implements EmployeeServiceIntfc {
此时事务管理器、SessionFactory、数据源之间的关系图如下
⑧在applicationContext.xml中配置hibernate的二级缓存
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=false
<!-- 启用二级缓存 -->
hibernate.cache.use_second_level_cache=true
<!-- 指定使用哪种二级缓存 -->
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
<!-- 启用对二级缓存的统计策略 -->
hibernate.generate_statistics=true
</value>
</property>
添加二级开发包,将ehcache的配置文件放到src目录
(3)整合struts
① 引入struts开发包
② 创建struts-config.xml,放到/WEB-INF目录下
<struts-config>
<form-beans>
<!-- type表示表单类的全路径 -->
<form-bean name="employeeForm" type="com.lewis.web.form.EmployeeForm" />
</form-beans>
<action-mappings>
<!-- name表示表单给哪个action用 -->
<action path="/login" parameter="flag" name="employeeForm"
type="com.lewis.web.action.LoginAction">
<forward name="ok" path="/WEB-INF/main.jsp"></forward>
<forward name="err" path="/WEB-INF/login.jsp"></forward>
</action>
</action-mappings>
</struts-config>
③ 在web.xml中配置struts
<!-- 配置struts -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
④由spring接管struts(action控件)
⑤在struts-config.xml作如下配置:
<!-- 配置代理请求处理 DelegatingRequestProcessor ,作用是让ActionServlet到spring容器文件中去找action的配置 -->
<controller>
<set-property property="processorClass"
value="org.springframework.web.struts.DelegatingRequestProcessor" />
</controller>
⑥在applicationContext.xml中配置action的路径
<!-- 配置action路径 -->
<bean name="/login" class="com.lewis.web.action.LoginAction"/>
此时struts-config.xml中对应的action的type就可以不要了
⑦这样就可以通过spring容器来获取action和配置action的一些属性,可以在action里添加一个属性:
<property name="employeeServiceIntfc" ref="employeeService"></property>
在相对应的action里添加一个employeeServiceIntfc属性和setter方法,就可以无需通过(1)⑤的语句来获取spring容器对象,直接可以通过employeeServiceIntfc.XX()来调用业务逻辑里的方法。
※注意在配置spring容器里的bean时name不要写错,一旦写错就会出错导致实例化失败,出现404等错误。
⑧struts的action是单例,对于并发的处理并不好,因为不管有多少请求,总是由一个action去处理。而降action交由spring管理之后,可以通过修改该action的scope属性为prototype来解决这个问题。
<bean scope="singleton/prototype/request/session/global session"></bean>
⑨struts有中文乱码的毛病,要解决这个问题,有两种方式
方法一:自己配置过滤器
9.1.1建一个com.xxx.web.filter包,建一个实现javax.servlet.Filter的Servlet,重写doFilter和init方法:
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException{
arg0.setCharacterEncoding("utf-8");
arg2.doFilter(arg0, arg1);
}
9.1.2在web.xml中配置过滤器
<!-- 配置自己写的过滤器 -->
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.lewis.web.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
方法二:使用spring框架提供的处理中文乱码的过滤器
直接在web.xml里进行配置就行
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
※对ssh整合的特别说明
①spring可以通过注解的方式来配置属性
1.1重新这样配置bean
<bean id="employeeService" class="com.lewis.service.impl.EmployeeServiceImpl"/>
1.2在EmployeeService的属性sessionFactory中添加一个注解@Resource
@Resource
private SessionFactory sessionFactory;
1.3在applicationContext.xml中启用注解
<!-- 启用注解扫描 -->
<context:annotation-config />
②ssh整合时,如何解决懒加载问题
2.1方法一:显示初始化懒加载,明确初始化
Hibernate.initialize(Department.class);//select预先查询
或者在Session还没关闭时,访问一次xxx.getXxx(),强制访问数据库
2.2方法二:在对象映射文件配置lazy=false,取消懒加载
但是以上两个方法都不好,因为无论你用不用该关联对象,hibernate都会发出sql语句去查询
2.3方法三:延长session的生命周期(推荐该方法)
spring专门提供了opensessioninview的方法来解决懒加载,需要在web.xml文件中添加如下配置:
<!-- 配置opensessioninview解决懒加载,本质是一个过滤器 -->
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
该方法可以有效的减少对数据库的查询,但缺点是和数据保持的session时间延长了