SSH整合
搞清楚SSH整合中,Struts2、Spring、Hibernate三个框架的分工。
Struts2负责表现层(Web层)。
Spring负责业务逻辑层(Service层)。
Hibernate负责数据访问层(Dao层)。
Hibernate + Spring + Struts 2
数据库依赖,数据库连接池依赖
日志依赖
Jackson等依赖
- 整合Hibernate
- 使用Maven搭建一个Web项目
- 在pom.xml中引入Hibernate和数据库依赖
<!-- 配置hibernate依赖包 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.10.Final</version> </dependency>
<!-- 配置mysql驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.43</version> </dependency> |
- 创建所需要的包
com.zking.pojo com.zking.action com.zking.dao com.zking.service |
- 创建数据库表
在MySQL中创建数据库表:
Create table t_user( user_id int primary key auto_increment, user_name varchar(50), pass_word varchar(50) ); |
- 创建实体类及映射文件
根据数据库表的字段在com.zking.pojo中创建实体类(User.java)和 映射文件(User.hbm.xml)。
User.java代码:
/** * 用户实体类 * * @author DML * @date 2018年8月18日 * */ public class User implements Serializable {
private static final long serialVersionUID = 7206188332382708460L;
private Integer userId; private String userName; private String password;
public User() { super(); } public User(String userName, String password) { super(); this.userName = userName; this.password = password; } public User(Integer userId, String userName, String password) { super(); this.userId = userId; this.userName = userName; this.password = password; } public Integer getUserId() { return userId; } public void setUserId(Integer 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; } @Override public String toString() { return "User [userId=" + userId + ", userName=" + userName + ", password=" + password + "]"; }
} |
User.hbm.xml代码:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2018-8-18 12:59:17 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping package="com.zking.ssh.pojo"> <class name="User" table="T_USER"> <id name="userId" column="USER_ID"> <generator class="native" /> </id> <property name="userName" column="USER_NAME" /> <property name="password" column="PASS_WORD" /> </class> </hibernate-mapping> |
- 配置hibernate.cfg.xml核心配置文件
在src或resources下创建核心配置文件hibernate.cfg.xml,主要配置:数据源、hibernate配置、映射文件加载。(使用hibernate工具创建cfg.xml文件)
<hibernate-configuration> <!-- 如果这里出现name="sessionFactory"则会报JNDI错 --> <session-factory>
<!-- 第一:设置数据库配置(数据源),必须配置项 --> <property name = "connection.driver_class">com.mysql.jdbc.Driver</property> <property name = "connection.url">jdbc:mysql://localhost:3306/db_abc</property> <property name = "connection.username">root</property> <property name = "connection.password">root</property>
<!-- 第二:设置hibernate配置,可选配置项 --> <property name = "dialect">org.hibernate.dialect.MySQLDialect</property> <property name = "show_sql">true</property> <property name = "format_sql">true</property>
<!-- 第三:设置加载映射文件,必须配置项 --> <mapping resource="com/zking/pojo/User.hbm.xml" />
</hibernate-configuration> |
- 测试hibernate框架
创建测试类,对hibernate框架的配置进行测试。
@Test public void testHibernate(){ Configuration cfg = new Configuration().configure(); SessionFactory sessionFactory = cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); // 测试添加一条记录 session.save(new User("admins","123")); tx.commit(); }catch(Exception e){ tx.rollback(); }finally{ session.close(); sessionFactory.close(); } } |
查看结果是否完成了添加功能。
如果出现了报错先解决报错,再走Spring的整合。
- 整合Spring
思想:将Hibernate交由Spring(大管家)管理。
- 在pom.xml中引入Spring的依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.10.RELEASE</version> </dependency> |
- 配置Spring核心配置文件:applicationContext.xml
2.1 在src下创建Spring核心配置文件:applicatoinContext.xml
也可以配置多个applicationContext-***.xml,用于实例化各包中的类对象。如:
applicationContext-action.xml
applicationContext-entity.xml
applicationContext-biz.xml
applicationContext-dao.xml
……
为每个包配置一个applicationContext.xml文件,好处:分包实例化对象。也可以写在一个applicationContext.xml中,在web.xml中加载一次即可。
2.2 在rescources中创建数据库连接池配置文件:db.properties
//配置数据源参数(需引入C3P0依赖) driver_Class=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8 uname=root upass=root //注意不要写password,否则与数据源配置name有冲突
//配置连接池参数 initPoolSize=3 //最小连接数 maxPoolSize=20 //最大连接数 |
注意:整合时使用数据库连接池技术,hibernate.cfg.xml中的设置数据库配置代码可以删除。
在pom.xml中引入数据库连接池技术C3PO依赖:
<!-- 引入C3P0数据库连接池 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> |
2.3 配置applicationContext.xml(Spring整合重点)
<!-- 1. 载入db.properties --> <context:property-placeholder location="classpath:db.properties" /> <!-- 注意:如果敲不出<context>说明该xml的<beans>中没有引入xmlns:context -->
<!-- 2. 配置数据源(需引入C3P0,同时删除hibernate.hbm.xml中的数据源配置) --> <!-- 要引用C3PO中的ComboPooledDataSource类 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 读取db.properties中参数值 --> <property name="user" value="${uname}"></property> <property name="password" value="${upass}"></property> <property name="jdbcUrl" value="${url}"></property> <property name="driverClass" value="${driver_Class}"></property> <property name="initialPoolSize" value="${initPoolSize}"></property> <property name="maxPoolSize" value="${maxPoolSize}"></property> <!-- 注意:db.properties中的key尽量不要与这里name的值一致,会引起冲突 --> </bean>
<!-- 3. 配置SessionFactory --> <!-- 实例化LocalSessionFactoryBean类,需要在pom.xml中引入spring-orm支持依赖 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <!-- 3.1 引入数据源 --> <property name="dataSource" ref="dataSource"></property> <!-- 3.2 加载hibernate核心配置文件 (hibernate核心文件交给spring来加载)--> <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> <!-- 3.3 加载hibernate映射文件 --> <property name="mappingLocations" value="classpath:com/zking/pojo/*.hbm.xml"></property> <!-- *.hbm.xml代表加载pojo下面所有的.hbm.xml文件 删除掉hibernate.cfg.xml中<mapping>对应的映射文件 提示:hibernate.cfg.xml中的show_sql和format_sql其实也可以写到db.properties中,那么hibernate.cfg.xml文件就可以删除掉了。 --> </bean>
<!-- 4. 配置事务 --> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean>
<!-- 5. 配置事务的属性 --> <!-- 在<beans>标签中复制xmlns:aop="http://www.springframework.org/schema/aop" 修改成:xmlns:tx="http://www.springframework.org/schema/tx" 复制最后一行:http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd 改成:http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd 这样<tx:>就可以使用。 <tx:advice>表示通知/增强,AOP在项目中是通过事务来体现,而事务的底层是通知。 --> <tx:advice id="myAdvice" transaction-manager="transactionManager"> <!-- 事务的属性 --> <tx:attributes> <!--当方法以add开头,REQUIRED表示如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中 1、PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启。 --> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="*"/> </tx:attributes> </tx:advice>
<!-- 6. 配置事务的切点 --> <!-- 指明哪些包里的哪些类,哪些类中的哪些方法要事务 --> <aop:config> <!-- * com.zking.dao.*.*(..)表示com.zking.dao包下所有的类中的所有方法,这是一种固定写法 --> <aop:pointcut id="myCut" expression="execution(* com.zking.dao.*.*(..))"/> <!--注意:需要再次引入一个依赖:spring-aspects,用于解析上面这个表达式--> <!-- 通知关联,事务的属性 --> <aop:advisor advice-ref="myAdvice" pointcut-ref="myCut"/> </aop:config> |
问题:将dao包下所有的dao方法做为通知切入到事务中。
在pom.xml中引入依赖:
<!-- 引入spring-orm依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>4.3.10.RELEASE</version> </dependency>
<!-- 引入Spring 的AspectJ依赖,解析事务切点 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.10.RELEASE</version> </dependency> |
- 配置Dao
3.1 编写接口:IUserDao
public interface IUserDao{ // 添加对象 public void addUser(User user); } |
3.2 编写实现类:UserDaoImpl,实现接口IUserDao
该实现类中有CRUD操作,hibernate中做CRUD操作是通过session对象,而session对象是通过sessionFactory获得,因此主要是如何获得sessionFactory。另注意,不要想着new对象,所以对象实例化交由xml中配置。
public class UserDaoImpl implements IUserDao{ // 声明sessionFactory,已在applicationContext.xml中实例化 private SessionFactory sessionFactory; // 省略sessionFactory的set和get方法
// 获得session的方法 public Session getSession(){ return sesionFactory.getCurrentSession(); }
@override public void addUser(User user){ // 添加方法 getSession().save(stu); } } |
- 在applicationContext-dao.xml中配置对象
<!--配置UserDaoImpl--> <bean id="UserDaoImpl" class="com.zking.dao.UserDaoImpl"> <!--注入:ref="sessionFactory"引用的是跨文件的id,引用applicationContext-public.xml中id="sessionFactory"对象 --> <property name="sessionFactory" ref="sessionFactory"></property> </bean> |
- 测试Spring框架
@Test public void test(){ // 加载spring配置文件 ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml", "applicationContext-dao.xml"}); // 测试能否得到sessionFactory对象 // Object obj = ac.getBean("sessionFactory"); // System.out.println(obj);
// 里氏替换 IUserDao iUserDao = (IUserDao)ac.getBean("UserDaoImpl"); iUserDao.addUser(new User("小红", "女", 20)); } |
注意:如果运行报错sessionFactory错误,那么有可能是数据源、hibernate核心配置文件、映射文件出了问题。因为这三者出问题,都会报sessionFactory错误,applicationContext.xml配置文件中已表现出。
- 整合Struts2
- 在pom.xml中导入struts依赖
<!-- 引入struts2框架依赖 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.33</version> </dependency>
<!-- 引入struts2对Spring的支持插件 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>2.3.33</version> </dependency>
|
- 配置web.xml文件
<!-- 启动服务器,加载Struts2核心过滤器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> |
- Web层页面
<form action="UserActionadd.action" method="post"> <!-- 注意:这里的stu.sname中stu一定要与action中实体类名相同,stu表示action中的对象 --> <input type="text" name="stu.sname" /><br/> <input type="text" name="stu.ssex" /><br/> <input type="text" name="stu.sage" /><br/> <input type="submit" value="保存" /> </form> |
- 配置biz包
4.1 配置IUserBiz(UserDao的biz接口),里面的方法与IUserDao一致
public interface IUserBiz{ public void addUser(User stu); } |
4.2 创建biz实现类:UserBizImpl,实现IUserBiz接口,重写addUser()方法
public class UserBizImpl implements IUserBiz{ // dao包中UserDaoImpl的父接口 private IUserDao iUserDao; public void setIUserDao(IUserDao iUserDao){ this.iUserDao = iUserDao; } public IUserDao getIUserDao(){ return iUserDao; }
@override public void addUser(User stu){ iUserDao.addUser(stu); } } |
同时需要在applicationContext-biz.xml中配置UserBizImpl,为iUserDao注入一个对象。
<bean id="UserBizImpl" class="com.zking.biz.UserBizImpl"> <!-- ref="UserDaoImpl"为applicationContext-dao.xml中的对象--> <property name="iUserDao" ref="UserDaoImpl"> </bean> |
- 编写Action
在com.zking.action包中创建表单对应的Action对象。
Public class UserAction{ private User stu; // 注意这里的stu与form表单中的stu一致 public User getStu() { return stu; } public void setStu(User stu) { this.stu = stu; }
private IUserBiz iUserBiz; // 用来调用addUser() public IUserBiz getIUserBiz() { return iUserBiz; } public void setIUserBiz(IUserBiz iUserBiz) { this.iUserBiz = iUserBiz; }
public String add() throws Exception { iUserBiz.addUser(stu); return "success"; } } |
- 配置applictaionContext-action.xml
<!-- 配置UserAction --> <bean id="UserAction" class="com.zking.action.UserAction" scope="prototype"> <property name="iUserBiz" ref="UserBizImpl"></property> </bean> |
- 配置struts.xml
在resources中创建struts.xml配置文件,配置文件的跳转。并准备一个success.jsp,先确保流程跳转无误。
<struts> <package name="myPackage" extends="struts-default"> <!-- 注意:class的值不再是一个类的全栈名,而是<bean>中的id --> <action name="UserAction*" class="UserAction" method="{1}"> <result name="success">/success.jsp</result> </action> </package> </struts> |
- 在web.xml中加载Spring
<!--加载Spring--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-*.xml</param-value> </context-param>
<!--添加监听--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> <!--注意:需要导入spring-web依赖--> </listener> |
注意:<context-param>在web.xml中的dtd约束中有要求:放在过滤器的上面。
引入spring-web依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.8.RELEASE</version> </dependency> |
总结:SSH框架最主要的本质是:“高内聚、低耦合”。在ssh中使用Struts是作为系统的整体基础架构,主要负责MVC的分离,在Struts框架的模型部分,控制业务跳转,利用Hibernate框架对持久层提供支持,Spring做管理层,管理struts和hibernate。具体做法是:用面向对象的分析方法根据需求提出一些模型,将这些模型实现为基本的Java对象,然后编写基本的DAO(Data Access Objects)接口,并给出Hibernate的DAO实现,采用Hibernate架构实现的DAO类来实现Java类与数据库之间的转换和访问,最后由Spring做管理,管理struts和hibernate。
Web.xml
<!-- 配置字符集拦截器,由spring提供 --> <filter> <filter-name>encodingFilter</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>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
Struts.xml
<struts> <!-- 包含struts-default.xml文件 --> <include file="struts-default.xml"></include> <!-- 设置字符集为UTF-8 --> <constant name="struts.i18n.encoding" value="UTF-8"></constant> <!-- 设置struts2允许的后缀名 --> <constant name="struts.action.extension" value="do,action"></constant> <!-- 是否允许浏览器缓存静态内容 --> <constant name="struts.serve.static.browserCache" value="false"></constant> <!-- 配置文件变化时是否重新加载 --> <constant name="struts.configuration.xml.reload" value="true"></constant> <!-- 是否开启开发者模式 --> <constant name="struts.devMode" value="true"></constant> <!-- 是否允许动态方法调用 --> <constant name="struts.enable.DynamicMethodInvocation" value="false"></constant> <!-- 由spring担任工程bean --> <constant name="struts.ObjectFactory" value="spring"></constant>
<!--使用动态方法配置:value="true”表示使用动态方法调用。--> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <package name=”my” extends=”struts-default” namespace=”/”> <action name="user" class="userAction"> <result name="success">login.jsp</result> <allowed-methods>login</allowed-methods> </action> </package>
<!--使用通配符--> <package name="pack1" extends="struts-default" namespace="/"> <global-allowed-methods>regex:.*</global-allowed-methods> <action name="action_*" class="com.zking.action.Login4Action" method="{1}"> …… </action> </package>
<!-- 映射action --> <package name="user" namespace="/" extends="struts-default"> <action name="hello" class="com.xxx.controller.UserAction" method="test"> <result name="index">index.jsp</result> </action> </package> </struts> |
ApplicationContext.xml
<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:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 开启注解编程 --> <!-- <mvc:annotation-driven></mvc:annotation-driven> --> <context:annotation-config></context:annotation-config>
<!-- 指定需要开启(扫描)注解编程的包 --> <context:component-scan base-package="com.zking"> </context:component-scan> </beans> |
log4j2-test.properties文件
log4j.rootLogger=ERROR,Console,OneFile,HtmlFile log4j.logger.org.apache.cxf=DEBUG log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=TRACE log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG #log4j.logger.org.hibernate.SQL=DEBUG #log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=TRACE
log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.Target=System.out log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.Threshold=ALL log4j.appender.Console.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c]%m%n
log4j.appender.OneFile=org.apache.log4j.RollingFileAppender log4j.appender.OneFile.File=d:/OASystem/oasys.txt log4j.appender.OneFile.MaxFileSize=10MB log4j.appender.OneFile.Threshold=ERROR log4j.appender.OneFile.layout=org.apache.log4j.PatternLayout log4j.appender.OneFile.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c]%m%n
log4j.appender.HtmlFile=org.apache.log4j.DailyRollingFileAppender log4j.appender.HtmlFile.file=../logs/oasys/oasys log4j.appender.HtmlFile.DatePattern='_'yyyy-MM-dd'.html' log4j.appender.HtmlFile.layout=org.apache.log4j.HTMLLayout log4j.appender.HtmlFile.Threshold=ERROR |