SSH整合之路
前言
对于Java Web开发的初学者来说,搭建一个SSH框架的项目一直是入门的拦路虎。主要原因:
1、struts2、spring和hibernate各自的版本众多。它们之间的兼容性问题增加了整合的难度。
2、对于较新版本之间的整合资料太少。老版本之间的整合方法不一定适用。
3、官方的参考文档自身存在的问题,经常让人摸不着头脑。
经过三天苦逼的生活
,终于整合成功。就想着立马写下来,与大家一起分享。不过仍存在一些小问题和不明白的地方,还希望大家帮忙指正。
环境说明
系统:win7 32位
版本选择:
struts-2.3.16.1
spring-framework-4.0.4.RELEASE-dist
hibernate-release-4.3.5.Final
Mysql 5.6
jdk 1.7
apache-tomcat-7.0.52-windows-x86
整合过程
1、建库创表
create database project;
create table user(
userId int auto_increment,
userName varchar(16) not null,
password varchar(16) not null,
gender int not null,
primary key(userId)
);
2、创建Struts项目
2.1 创建项目
2.1.1 在Eclipse中创建一个Dynamic Web Project,本文项目名称为SSH3。
注:事先得安装好Tomcat服务器,并在Target runtime配置项选中它。其他配置如上图所示。
注:选中生成web.xml,这样可生成其模版。
2.2 导入struts2的相关jar包
把Struts内apps文件夹下的struts2-blank war包用压缩工具解压,然后把WEB-INF/lib内的jar包复制到SSH项目下的WEB-INF/lib下。
2.3 在src目录下创建相应package,结构如下图所示。
RegisterAction.java
package com.ssh.action;
import com.opensymphony.xwork2.ActionSupport;
import com.ssh.forms.UserForm;
import com.ssh.service.UserManager;
public class RegisterAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private UserForm user;
private String tip;
private UserManager userManager;
public UserForm getUser() {
return user;
}
public void setUser(UserForm user) {
this.user = user;
}
public String getTip() {
return tip;
}
public void setTip(String tip) {
this.tip = tip;
}
public UserManager getUserManager() {
return userManager;
}
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
public String execute() {
try {
userManager.regUser(user);
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
return ERROR;
}
}
}
相应的RegisterAction-validation.xml
这部分可以参考Struts 2的官方文档
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<!-- Action中user的username属性 -->
<field name="user.username">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>用户名不能为空</message>
</field-validator>
<!-- 指定username属性必须匹配的正则表达式 -->
<field-validator type="regex">
<param name="regex"><![CDATA[(\w{6,16})]]></param>
<message>用户名输入不合法,必须为长度在6-16中间数字或字母</message>
</field-validator>
</field>
<!-- user.password属性 -->
<field name="user.password">
<field-validator type="regex">
<param name="regex"><![CDATA[(\w{6,16})]]></param>
<message>密码输入不合法,必须长度在6-16之间的数字或字母</message>
</field-validator>
</field>
</validators>
UserForm.java、UserManager.java和UserManagerImpl.java
package com.ssh.forms;
public class UserForm {
private String username;
private String password;
private int gender;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
}
</pre><pre name="code" class="html">
</pre><pre name="code" class="html">package com.ssh.service;
import com.ssh.forms.UserForm;
public interface UserManager {
public void regUser(UserForm user);
}
package com.ssh.serviceImpl;
import com.ssh.forms.UserForm;
import com.ssh.service.UserManager;
public class UserManagerImpl implements UserManager {
public void regUser(UserForm userForm){
}
}
struts.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<span style="background-color: rgb(255, 204, 102);"><constant name="struts.devMode" value="true"/></span>
<package name="lee" extends="struts-default">
<action name="registerAction" class="com.ssh.action.RegisterAction">
<result name="input">/register.jsp</result>
<result name="success">/success.jsp</result>
<result name="error">/fail.jsp</result>
</action>
<action name="">
<result>.</result>
</action>
</package>
</struts>
注:<constant name="struts.devMode" value="true"/> 设置为开放模式,否则输入不合法的提示信息可能看不到。
register.jsp
<%@ 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=UTF-8">
<title>User Register Page</title>
</head>
<body>
<s:fielderror></s:fielderror>
<s:form action="registerAction">
<s:textfield name="user.username" label="用户名"></s:textfield>
<s:password name="user.password" label="密码"></s:password>
<s:select list="#{'1':'男','0':'女'}" listKey="key" listValue="value"
name="user.gender" label="性别" value="1"></s:select>
<s:submit value="注册"></s:submit>
</s:form>
</html>
success.jsp和fail.jsp仅仅只是一句提示注册成功和失败的话,在此不再列出。
2.4 将项目部署到Tomcat服务器
2.5 测试结果
3、整合Hibernate和spring
3.1 导入相关jar包
1、将Hibernate内的lib/required下的jar包复制到SSH3项目的lib目录下;复制lib\optional\c3p0下的c3p0-0.9.2.1.jar、mchange-commons-java-0.2.3.4.jar;
2、导入Mysql数据库的jar包;mysql-connector-java-5.1.7-bin.jar
3、将Spring内libs目录下包含所有的jar包(不需要复制结尾为sources和javadoc的jar包)到SSH3项目的lib目录下。
3.2 添加并修改相应类
User.java和User.hbm.xml,配置可以参考Hibernate的官方文档
package com.ssh.beans;
public class User {
private int userId;
private String username;
private String password;
private int gender;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
}
<?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 package="com.ssh.beans">
<class name="User" table="user">
<id name="userId" column="userId">
<generator class="native"></generator>
</id>
<property name="username" column="userName" type="java.lang.String"
not-null="true" length="16"></property>
<property name="password" column="password" type="java.lang.String"
not-null="true" length="16" />
<property name="gender" column="gender" type="java.lang.Integer" length="1" />
</class>
</hibernate-mapping>
BaseDao和UserDao
package com.ssh.dao;
import org.hibernate.HibernateException;
public interface BaseDao {
public void saveObject(Object obj) throws HibernateException;
}
package com.ssh.daoImpl;
import org.hibernate.HibernateException;
import <span style="color:#ff0000;">org.springframework.orm.hibernate4.support.HibernateDaoSupport;</span>
import com.ssh.dao.BaseDao;
public class UserDao extends HibernateDaoSupport implements BaseDao {
@Override
public void saveObject(Object obj) throws HibernateException {
getHibernateTemplate().save(obj);
}
}
修改UserManagerImpl
package com.ssh.serviceImpl;
import org.hibernate.HibernateException;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ssh.beans.User;
import com.ssh.dao.BaseDao;
import com.ssh.forms.UserForm;
import com.ssh.service.UserManager;
public class UserManagerImpl implements UserManager {
private BaseDao dao;
public void setDao(BaseDao dao) {
this.dao = dao;
}
<span style="color: rgb(255, 0, 0);">@Transactional(readOnly = false)</span>
public void regUser(UserForm userForm) throws HibernateException {
// 构造User对象
User user = new User();
BeanUtils.copyProperties(userForm, user);
dao.saveObject(user);
}
}
修改struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.devMode" value="true"/>
<package name="lee" extends="struts-default">
<action name="registerAction" <span style="color:#ff0000;">class="regAction"></span>
<result name="input">/register.jsp</result>
<result name="success">/success.jsp</result>
<result name="error">/fail.jsp</result>
</action>
<action name="">
<result>.</result>
</action>
</package>
</struts>
applicationContext.xml配置
参考:spring官方文档spring-framework-reference的14.3 Hibernate
<?xml version="1.0" encoding="UTF-8"?>
<span style="color:#ff0000;"><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-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/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"></span>
<!-- 定义数据源的信息 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 指定连接数据库的驱动 -->
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<!-- 指定连接数据库的URL -->
<property name="jdbcUrl" value="jdbc:mysql://localhost/project" />
<!-- 指定连接数据库的用户名 -->
<property name="user" value="root" />
<property name="password" value="123456" />
<!-- 指定连接数据库连接池的最大连接数 -->
<property name="maxPoolSize" value="40" />
<!-- 指定连接数据库连接池的最小连接数 -->
<property name="minPoolSize" value="1" />
<!-- 指定连接数据库连接池的初始化连接数 -->
<property name="initialPoolSize" value="1" />
<!-- 指定连接数据库连接池的连接的最大空闲时间 -->
<property name="maxIdleTime" value="20" />
</bean>
<!--定义Hibernate的SessionFactory -->
<!-- SessionFactory使用的数据源为上面的数据源 -->
<!-- 指定了Hibernate的映射文件和配置信息 -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource">
</property>
<property name="mappingResources">
<list>
<span style="color:#ff0000;"><value>com/ssh/beans/User.hbm.xml</value></span>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">20</prop>
</props>
</property>
</bean>
<bean id="baseDao" class="com.ssh.daoImpl.UserDao">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<span style="color:#3333ff;"> <!--
<aop:config>
<aop:pointcut id="productServiceMethods"
expression="execution(com.ynwi.ssh.service.UserManager.(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" read-only="false" />
</tx:attributes>
</tx:advice>
-->
</span>
<!-- 配置事务的传播特性 -->
<span style="color:#ff0000;"><tx:annotation-driven /></span>
<!--用户注册业务逻辑类 -->
<bean id="userManager" class="com.ssh.serviceImpl.UserManagerImpl">
<property name="dao">
<ref bean="baseDao" />
</property>
</bean>
<!-- 用户注册的Action -->
<bean id="regAction" class="com.ssh.action.RegisterAction">
<property name="userManager">
<ref bean="userManager" />
</property>
</bean>
<!-- more bean definitions go here -->
</beans>
修改web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>SSH3</display-name>
<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>
<span style="color:#ff0000;"> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener></span>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
4、部分异常
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
配置事务的传播特性,并设置为可写。有两种方法
1、在applicationContext中配置;
2、采用annotation方式
本文采用的是第二种。因为参考官方文档提供的示例,第一种配置总是不能生效,原因还没找到,希望大家给与指正。
下面这两个异常为缺少相应的jar包,其特点已标注出来。可以通过在包含struts、hibernate和spring解压文件的目录下,通过搜索蓝色的jar包名快速得到。
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception isjava.lang.NoClassDefFoundError: org/
aopalliance
/intercept/MethodInterceptor
aopalliance-1.0.jar
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: com/
mchange
/v2/ser/Indirector
mchange-commons-java-0.2.3.4.jar
5、测试结果
参考:
[1]
http://blog.csdn.net/yeohcooller/article/details/9316923
[2] struts 2、hibernate和spring相关官方文档