Maven 整合 SSH 框架

     前面的一系列文章中,我们总结了三大框架:Struts2,Hibernate,Spring 的基本知识。本篇就姑且尝试着使用 Maven 这个项目构建工具来将这三个框架整合一起。说到这里,如果有对 Maven 还不熟悉的同学,此处推荐下面两个链接快速了解下,记得回来!

Maven 是什么?
如何给小白说明 Maven 是什么?

我对 Maven 的理解就是,它是一个工具能提供两大主要功能,其一是依赖管理,其二是项目构建。

所谓的依赖管理就是指,我们对于框架中的 jar 包从此不需要手动的添加到项目中来,而是使用 Maven 的语法进行引用,当然在打包发布的时候,这些包还是会被加入进来,但是在我们的源代码中就不存在任何的 jar 包,整个项目轻量可移植性强。

而所谓的项目构建指的是,对项目进行编译,测试,打包,发布等。原先我们是通过 IDE 来完成这样的工作,但是不同的 IDE 有不同的使用操作,但是如果你是 Maven 项目的话,无论你在哪种 IDE 中编码,都可以使用相同的 Maven 命令进行上述的几种操作,这其实在一定程度上减少了我们对 IDE 的依赖。

上述我们简单介绍了 Maven 这个项目管理工具,具体深入的学习不是本篇的重点,本篇着重完成对 SSH 框架整合的一个操作,主要涉及以下内容:

  • 分别配置各个框架的运行环境
  • 了解整个 Web 项目配置文件的加载顺序
  • Spring 整合 Struts2
  • Spring 整合 Hibernate
  • 创建Action,Service,Dao 模拟登录过程
  • 项目的模块分离与再聚合

一、分别配置各个框架的运行环境

首先,我们先将三个框架各自的运行环境都配置到我们的 web 项目中。

创建一个 Maven 的 web 工程,基本的目录结构大致是这样的:

web 项目的基本目录结构

然后我们先来配置 struts2 的运行环境。
第一步,pom.xml 中依赖 struts2 的核心包:

<dependency>
   <groupId>org.apache.struts</groupId>
   <artifactId>struts2-core</artifactId>
   <version>2.3.32</version>
</dependency>

由于 Maven 会自动引入该核心包所依赖的其他 jar 包,所以我们无需在手动依赖其他任何 jar 包。

第二步,web.xml 中配置核心过滤器:

<!--配置Struts的核心过滤器-->
<filter>
  <filter-name>struts</filter-name>
  <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class></filter>

<filter-mapping>
  <filter-name>struts</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

第三步,创建 struts.xml 用于配置控制器 Action。

至此,struts2 的运行环境已经配置完成,下面我们看 Hibernate 运行环境的配置。
第一步,依赖相关的 jar 包,我们看看 Hibernate 需要依赖哪些 jar 包?

//mysql 驱动的依赖
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>6.0.6</version>
</dependency>
//Hibernate 核心包依赖
<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>4.3.11.Final</version>
</dependency>

同样,hibernate 核心包需要依赖的其他 jar 包,Maven 会为我们自动查询并引入。

第二步,创建 Hibernate 核心配置文件 hibernate.cfg.xml 并完成基本信息的配置。

这里写图片描述

需要说明一点的是,为了简单起见,这里我们并没有使用数据源进行数据库的连接,等到与 Spring 整合的时候会使用数据源配置数据库连接。

至此,Hibernate 的基本环境也已经配置完成,下面我们看 Spring 的环境配置。

第一步,引入 Spring 相关依赖:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-expression</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>
    
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

第二步,创建 Spring 核心配置文件 applicationContext.xml 。

第三步,web.xml 中创建 Spring 的配置文件加载 Listener,它的具体作用我们下一小节进行介绍。

<!--配置Spring监听器-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListene</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

这样,三个框架各自的运行环境就已经创建完成了,但是显然它们现在是不能整合共同工作的。整个项目的目录结构如下:

这里写图片描述

二、了解整个 Web 项目配置文件的加载顺序

如果上述操作无误的话,现在我们的 web.xml 配置文件中起码应该是这样的:

这里写图片描述

当整个 web 应用启动时,首先会去加载 web.xml ,其中会启动 struts 的核心过滤器,然后我们的 Spring 监听器监听到 web 容器启动后,会根据 ServletContext 中保存的我们的配置参数信息去加载 Spring 的配置文件。而一般来说,Spring 整合 Hibernate 之后,Spring 的配置文件中会指明去加载 Hibernate 的配置文件,更具体的我们下文会详细介绍,此处只需要了解 Spring 配置文件中会去加载 Hibernate 的核心配置文件。

那么,这样的话,我们三个框架的核心配置文件已经能够按顺序加载了。下面我们两两整合框架,先进行 Spring 与 Struts2 的整合。

三、Spring 整合 Struts2

Spring 与 Struts2 整合的核心点在于,将 Struts2 的 Action 交由 Spring 的 IOC 容器来创建。我们先创建一个 Action,

//index.jsp
<body>
    <form action="login" method="post">
        姓名:<input type="text" name="name" /><br/>
        <input type="submit" value="提交" />
    </form>
</body>
public class LoginAction extends ActionSupport {

    private String name;
    //省略getter,setter方法
    public String execute(){
        if("single".equals(this.name)){
            return SUCCESS;
        }else{
            return ERROR;
        }
    }
}

Spring 中配置该 Action 的实例信息:

<bean id="login_action" class="Actions.LoginAction" scope="prototype">
        
</bean>

接下来在 struts.xml 中引用该 bean 即可。

<package name="myPackage" extends="struts-default">
    <action name="login" class="login_action">
        <result name="success">/welcom.jsp</result>
        <result name="error">/error.jsp</result>
    </action>
</package>

注意我们这里 action 标签中的 class 属性已经不再指向具体的 Action 类了,它指向的是 Spring 中的实例 bean。

至此,对于 Struts2 和 Spring 的整合大致上结束了,为什么说大致呢?当你启动 web 容器运行上述程序时,会报错:

Unable to load configuration. - action .....

告诉你无法加载 struts.xml 配置文件,其实就是 action 的 class 属性对应的类找不到的意思。解决办法是,添加一个 Spring 插件依赖,该插件会让容器在找不到对应的实体类的时候,去 Spring IOC 容器中找。具体依赖是:

<dependency>
  <groupId>org.apache.struts</groupId>
  <artifactId>struts2-spring-plugin</artifactId>
  <version>2.3.15.1</version>
</dependency>

然后我们启动 web 容器测试我们的整合效果。

这里写图片描述

这里写图片描述

整合成功! Struts2 与 Spring 的整合还算简单,Spring 整合 Hibernate 则相对复杂一些。

四、Spring 整合 Hibernate

整合 Hibernate 的第一步依然是依赖相关 jar 包。

//MySQL 驱动包
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>6.0.6</version>
</dependency>
//c3p0 
<dependency>
  <groupId>com.mchange</groupId>
  <artifactId>c3p0</artifactId>
  <version>0.9.5</version>
</dependency>

第二步是配置数据源和 session 工厂。

<!--读取属性配置文件内容-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置c3p0数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${diverClass}"/>
    <property name="jdbcUrl" value="${jdbcUrl}"/>
    <property name="user" value="${user}"/>
    <property name="password" value="${password}"/>
</bean>

创建一个属性文件保存 jdbc 连接的基本信息,连接驱动,连接 url,用户名,密码等。然后我们在 Spring 配置文件中配置了一个单例的数据源,它负责创建于数据库的连接。

接着配置一个 SessionFactory 实例:

<!--配置session工厂-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocations" value="classpath:hibernate.cfg.xml"/>
</bean>

创建 session 工厂的时候会去加载 Hibernate 的核心配置文件,这里我们通过注入 configLocations 属性的值告诉 Spring 该文件的位置。这里还需要引入一个在 Spring 配置文件中支持 Hibernate 相关操作的一个插件:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>4.0.0.RELEASE</version>
</dependency>

Spring 对 Hibernate 的整合也基本结束,下面我们通过模拟一个登陆操作来初步体验下整合后框架的整体运行过程。

五、模拟登录过程

为了项目之间各个模块的耦合性低,我们通常会选择将整个项目分分层,Action 控制器拦截请求,Service 处理业务,Dao 完成对数据的存取。

这里写图片描述

MyDao 中封装着我们对于数据库的所有操作,MyService 中封装着我们所有的业务逻辑。我们先在 Dao 层中添加一个方法用于根据用户名返回给用于所有信息,也就是返回该用户名所匹配的那条记录。

public class MyDao {

    private SessionFactory sessionFactory;
    //省略getter,setter方法
    public UserInfo getByName(String name){
        Session session = this.sessionFactory.openSession();
        List list = session.createSQLQuery("SELECT * FROM logins WHERE NAME ='"+name+"'")
                .addEntity(UserInfo.class)
                .list();
        session.close();
        if(list != null && list.size() != 0){
            return (UserInfo) list.get(0);
        }else {
            return null;
        }
    }
}
//Spring IOC 容器中配置一个 MyDao 实例
<bean id="myDao" class="Dao.MyDao">
   <property name="sessionFactory" ref="sessionFactory"/>
</bean>

接着我们写 Service 层:

public class MyService {

    private MyDao dao;
    //省略getter,setter方法
    public boolean sure(String name,String pwd){
        UserInfo userInfo = this.dao.getByName(name);
        if(userInfo == null){
            return false;
        }else {
            if(userInfo.getPwd().equals(pwd)) return true;
            else return false;
        }
    }
}
//Spring IOC 容器中配置一个 Service 实例
<bean id="myService" class="Service.MyService">
    <property name="dao" ref="myDao"/>
</bean>

创建 Service 实例的同时并将 MyDao 实例注入到其中,逻辑上实现了 Service 调 Dao,组件调用。下面写控制器:

public class LoginAction extends ActionSupport {

    private String name;
    private String pwd;
    private MyService service;
    //省略getter,setter方法
    public void setName(String name) {
        this.name = name;
    }

    public String execute(){
       boolean flag = this.service.sure(name,pwd);
       if(flag) return SUCCESS;
       else return ERROR;
    }
}
//Spring IOC 容器中配置 Action 实例
<bean id="login_Action" class="Actions.LoginAction" scope="prototype">
    <property name="service" ref="myService"/>
</bean>
//struts.xml 中使 Action 生效
<package name="myPackage" extends="struts-default">
    <action name="login" class="login_Action">
        <result name="success">/welcom.jsp</result>
        <result name="error">/error.jsp</result>
    </action>
</package>

好了,我们来测试一下!

这里写图片描述

这里写图片描述
这里写图片描述

这里写图片描述

上述我们使用整合后的框架做了一个小案例,由于代码量较小还不能体现框架分层处理的优势,但是我们还要对其进行更深层次的解耦。

六、项目的模块分离与再聚合

上述的项目中,我们的 Dao,Service,Action 等层次的代码都处于同一个项目中,项目的模块化就是将这些层分离出去,然后再以热插拔的形式聚合回原项目,这样的话,项目中的各个组件都是一个一个的子模块,那么任意一个模块出现问题后,可以立即用一个新模块接上。这种模块化的思想已经越来越成为一种主流的思想。

下面我们来介绍下,如何拆分出这些模块。

首先我们要新建一个工程作为父工程,这些 Dao,Service,Action 都是它下面的子模块。打个比方来说,父工程就相当于电脑主板,Dao,Service,Action 都是热插拔在上面的内存条、硬盘等部件,主板上的资源在各个部件上都是可见的。所以我们的父工程只需要做一件事,依赖子模块所需要的所有的 jar 包。

这里写图片描述

这个父工程什么都不要有,只需要有一个 pom.xml 文件用于依赖所有需要的 jar 包即可。然后我们将上一个项目中所有需要依赖的 jar 包都添加到父工程的 pom.xml 中进行引用。

然后我们选中项目创建第一个子模块 Dao,

这里写图片描述

将属于 Dao 的所有相关文件全部移植到 Dao 模块中来。

这里写图片描述

除了这些,还有一些配置在 Spring 中的代码,我们也要拷贝过来。

这里写图片描述

拷贝原先的 Spring 的配置文件并删除和我们 Dao 层无关的所有配置代码。这就完成了对 Dao 模块的分离,下面我们分离 Service 模块。

第一步是一样的,先创建一个子模块然后移植过来原先项目中和 Service 相关的所有代码文件。

这里写图片描述

相关的文件拷贝后的 Service 目录结构如上图所示,但是整个 Service 模块是报错的,原因很简单,Service 现在是独立于 Dao 的,但是它又是依赖 Dao 的,所以我们只需要将 Dao 模块打包发布到本地仓库,然后 Service 通过 Maven 依赖即可。

<dependency>
    <groupId>top.walkeryam</groupId>
    <artifactId>Dao</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

依赖 Dao 包之后就会发现项目不再报错了,最后我们分离 Action。

第一步依然是创建子模块并移植过来相关的所有代码,

这里写图片描述

这里的报错和上述的原因是一样的,Action 要依赖 Service ,所以我们只要为其添加 Service 的引用即可。

<dependency>
   <groupId>top.walkeryam</groupId>
   <artifactId>Service</artifactId>
   <version>1.0-SNAPSHOT</version>
</dependency>

但是还没完,这么多 Spring 配置文件,web 容器怎么知道加载哪个?
修改 web.xml 中有关 Spring 配置文件位置的代码:

这里写图片描述

使用通配符告诉容器加载所有类路径下符合指定规则的配置文件,这样我们各个模块中的 Spring 的配置都可以被加载了。

下面我们将 Action 打成 war 包,并存放到 web 容器的项目目录下,单独运行 Action,由于 Dao 和 Service 都已经以热插拔的形式接入到 Action 中了,所以直接运行 Action 是没有问题的。

这里写图片描述

启动本地 Tomcat ,浏览器中进行测试。

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

测试成功!那至此我们也完成了 Maven 项目的模块化拆分与聚合的操作,项目之间的各个组件耦合度降低,每个组件又都是可热插拔的,一旦哪天项目中的某个组件崩溃导致整个项目挂了,可随机替换出错的组件。

模块化的思想已经越来越成熟了,不知道本篇上述的所有内容阐述的是否到位,但依然建议你深入理解整个解耦模块化的思想。总结不到之处,望指出!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容