Maven高级
学习目标
- 了解搭建私服的使用
- 理解传递依赖
- 掌握如何解决依赖版本冲突问题
- 能够使用maven构建SSM工程
- 学习使用maven分模块方式构建工程
1. 私服:私服的介绍
目标
理解私服的作用
仓库的介绍
仓库的概念
中央仓库
目前来说: https://repo1.maven.org/maven2/是真正的Maven中央仓库的地址,该地址内置在Maven的源码中其他的都是镜像。
什么是仓库镜像
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像,使用镜像可以提高项目构建效率。
仓库的索引
中央仓库带有索引文件以方便用户对其进行搜索,索引每周更新一次,中央仓库的索引有几十M。
黑名单
如果某个IP地址恶意的下载中央仓库内容,例如全公司100台机器使用同一个IP反复下载,这个IP(甚至是IP段)会进入黑名单,因此稍有规模的使用Maven时,应该用Nexus架设私服。
私服
有些公司不提供外网给项目组人员,因此就不能使用maven访问远程的仓库地址,所以很有必要在局域网里找一台有外网权限的机器,搭建nexus私服,然后开发人员连到这台私服上,这样的话就可以通过这台搭建了nexus私服的电脑访问maven的远程仓库。
2. 私服:私服的安装和启动
下载
Nexus的官网 https://www.sonatype.com/
- 选择导航菜单Products
- 选择OSS Edition
注:资料中已经下载latest-win64直接使用即可。
默认是使用jetty做为web容器
安装
- 在任意位置创建目录:nexus
- 解压到nexus目录下会出现两个目录,两个目录都有用
- 安装路径下etc目录中nexus-default.properties文件保存有nexus基础配置信息,例如默认访问端口,nexus默认的端口号是8081
- 安装路径下bin目录中nexus.vmoptions文件保存有nexus服务器启动对应的配置信息,例如默认占用内存空间
启动
注:要保证JDK环境配置正确
- 进入以下目录
- 输入cmd进入命令行
- 可以输入nexus /?查看所有的参数,输入 /run在窗口下运行服务器
- 如果弹出以下窗口,点允许访问
- 启动成功,默认是8081,不要关闭这个窗口,不然服务器就退出了
访问
- 当Nexus启动后,可以在浏览器中输入:http://localhost:8081/可以看到以下页面
- 点击右上角登录
- 弹出以下对话框
- 输入默认的帐号:admin,密码:在admin.password文件中找
- 登录成功以后出现配置向导,直接点next
- 修改密码,输入两次,建议都使用admin,不要忘记了
- 允许匿名的账户登录
- 配置完成
3. 私服:仓库类别和配置
类别介绍

proxy:是远程仓库的代理。比如说在nexus中配置了一个central仓库的proxy,当用户向这个proxy请求一个组件,这个proxy就会先在本地查找,如果找不到的话,就会从远程仓库下载,然后返回给用户,相当于起到一个中转的作用。
Hosted:是宿主仓库,用户可以把自己的一些构件,deploy到hosted中,也可以手工上传构件到hosted里。比如说oracle的驱动程序,在central repository是获取不到的,就需要手动上传到hosted里。
Group:是仓库组,在maven里没有这个概念,是nexus特有的。目的是将上述多个仓库聚合,对用户暴露统一的地址,这样用户就不需要在pom中配置多个地址,只要统一配置group的地址就可以了。
注:公司内部通常只需关注hosted宿主仓库就可以了
修改配置
中央仓库的地址
Nexus的中央仓库,默认配置的是maven的中央仓库:https://repo1.maven.org/maven2/,为了提高速度可以配置成阿里云的中央仓库https://maven.aliyun.com/repository/central
- 选择中央仓库

- 修改地址:Remote storage的位置
- 记得点最下面的保存按钮
修改RELEASES为可以重复部署
因为下面要上传jar包到这个仓库RELEASES下
- 仓库选择Releases
- 在Access Settings中选择Allow Redeploy,设置为可以重复部署
- 点保存按钮
4. 私服:上传项目到私服
- 配置本地仓库访问私服的权限,修改maven的conf/settings.xml配置文件,用户名和密码,复制如下片段到相应的位置,大约在111行。注意:密码要与你设置的密码相同
<server><id>releases</id><username>admin</username><password>admin</password></server><server><id>snapshots</id><username>admin</username><password>admin</password></server>
- 重新创建一个新的模块,配置要上传项目中的发布管理,添加如下代码段:

坐标如下:

- 在pom.xml文件中添加以下代码段
<distributionManagement><repository><id>releases</id><url>http://localhost:8081/repository/maven-releases/</url></repository><snapshotRepository><id>snapshots</id><url>http://localhost:8081/repository/maven-snapshots/</url></snapshotRepository></distributionManagement>
上面的url即仓库地址
- 执行deploy命令,上传项目到私服。

- 上传日志结果

- 去私服查看snapshots上传的结果

- 修改当前模块的坐标为RELEASE
- 再次上传到私服
- 查看上传的日志
- 查看RELEASE仓库上传的结果
5. 私服:从私服下载项目
目标
从私服下载资源
私服下载的配置
注:项目A必须是RELEASE版本才可以使用
- 假设上面的模块是A,创建另一个模块B
<groupId>com.itheima</groupId><artifactId>heima-deploy-b</artifactId><version>1.0-RELEASE</version>
- 依赖于上面的模块A
<dependencies><dependency><groupId>com.itheima</groupId><artifactId>heima-deploy</artifactId><version>1.0-RELEASE</version></dependency></dependencies>
- 删除本地仓库中A模块的jar包
- 修改%MAVEN_HOME%\conf\setttings.xml文件,项目B是依赖于私服仓库中模块A
注:后面还要再改回来,以后还是使用阿里云的镜像<mirror><id>nexus</id><mirrorOf>*</mirrorOf><url>http://localhost:8081/repository/maven-public/</url></mirror>
- clean清除项目B,再complie编译一次
- 可以看到日志信息是从本地仓库中下载
改回阿里云远程仓库
注:接下来的学习还是要使用原来的配置,上面只是临时配置一下。
<mirror><id>nexus</id><mirrorOf>*</mirrorOf><url>http://maven.aliyun.com/nexus/content/groups/public/</url></mirror>
6. 回顾:依赖范围
目标
- 依赖的作用
- 依赖范围
依赖范围
在maven中三种类路径

| classpath范围 | 理解为 |
|---|---|
| 编译类路径 | 在main目录下起作用 |
| 测试类路径 | 在test目录下起作用 |
| 运行时类路径 | 在运行的过程中起作用,在target目录下 |
依赖范围
| 依赖范围 | 编译类路径 | 测试类路径 | 运行时类路径 |
|---|---|---|---|
| compile (默认) | Y | Y | Y |
| provided | Y | Y | (不会打包到项目中) |
| runtime | Y | Y | |
| test | Y |
7. 依赖:依赖传递
什么是依赖传递
概念:某个项目依赖了另一个项目,另一个项目中jar包会不会传递到这个项目中来
面试题
- 项目A依赖junit,依赖范围是test,项目B依赖项目A,问: 项目B对junit是否有依赖?
- 项目A依赖junit,依赖范围是compile,项目B依赖项目A,问: 项目B对junit是否有依赖?
- 项目A依赖junit,依赖范围是provided,项目B依赖项目A,问: 项目B对junit是否有依赖?
- 项目A依赖junit,依赖范围是runtime,项目B依赖项目A,问: 项目B对junit是否有依赖?
依赖传递
实验设计:两个项目
创建项目:maven_a
创建项目:maven_b
演示
- 项目A依赖junit,依赖范围是test,项目B依赖项目A,问: 项目B对junit是否有依赖?
没有
- 项目A依赖junit,依赖范围是compile,项目B依赖项目A,问: 项目B对junit是否有依赖?
有,产生依赖传递
- 项目A依赖junit,依赖范围是provided,项目B依赖项目A,问: 项目B对junit是否有依赖?
没有
- 项目A依赖junit,依赖范围是runtime,项目B依赖项目A,问: 项目B对junit是否有依赖?
有,产生依赖传递
小结
哪两种依赖范围会产生传递依赖?
compile, runtime 在运行时中起作用中范围会产生依赖传递
8. 依赖:依赖可选和依赖排除【重点】
目标
- 什么是可选依赖和依赖排除
- 分别如何配置
依赖可选
前提是会产生依赖传递的两种情况
什么是可选依赖
- A项目依赖了junit
- B项目依赖了A项目
- 根据依赖传递特性,默认情况下B项目会依赖junit
- 我们可以在A项目通过可选依赖,让B项目不能依赖junit
配置方式
在A项目的依赖配置中,通过optional子标签进行配置。它有两个取值:
- true:是可选依赖,不进行依赖传递
- false:默认值,进行依赖传递。
我是A项目,由我决定要不要给你,我的地盘我做主
步骤
- 创建A项目,依赖于junit
- 创建B项目,依赖于项目A
- 在项目A中指定optional为true
- 查看项目B的依赖情况
依赖排除
什么是依赖排除
- A项目依赖了junit
- B项目依赖了A项目
- 根据依赖传递特性,默认情况下B项目会依赖junit
- 我们可以在B项目通过排除依赖,配置B项目不依赖junit
配置步骤
通过在B项目中配置 exclusions标签进行配置
- 在依赖A项目下的version标签下编写exclusions
- exclusions中每个exclusion是一个要排除的jar包
- 只需指定groupId和artifactId就可以了,不用指定version版本
你给我就要,我不是很没面子?我来决定要不要
代码
项目A的pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>day51_02_A</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope><!-- 依赖可选,取值是true或false,这个包不会传递下去,我要决定给不给 --><!--<optional>true</optional>--></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency></dependencies></project>
项目B的pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>day51_03_B</artifactId><version>1.0-SNAPSHOT</version><dependencies><!--依赖于项目A--><dependency><groupId>com.itheima</groupId><artifactId>day51_02_A</artifactId><version>1.0-SNAPSHOT</version><!-- 依赖排除,我来决定要不要 --><exclusions><!-- 可以设置多个 --><exclusion><!-- 要写排除的坐标,不用写version --><groupId>junit</groupId><artifactId>junit</artifactId></exclusion></exclusions></dependency></dependencies></project>
小结
| 依赖配置 | 配置元素 |
|---|---|
| 可选 | <optional>true</optional> |
| 排除 | <exclusions><exclusion>坐标没有version</exclusion></exclusions> |
9. 依赖:依赖冲突【重点】
目标
- 依赖冲突的三种情况
- 如何解决依赖冲突
情况1:两个直接依赖
问题
一个项目中同时配置了2份junit4.12和junit4.11不同的版本,项目最终会使用哪个junit的版本?
配置文件pom.xml
<dependencies><!--默认是compile,会产生依赖传递--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version></dependency></dependencies>
效果

结论
如果两个直接依赖:以下面配置的为准
情况2:一个直接依赖一个间接依赖
问题
A项目依赖junit4.12,B项目依赖junit4.11,B项目依赖于A项目,B项目使用哪个版本的junit?
配置文件
项目A的pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>day51_02_A</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>compile</scope></dependency></dependencies></project>
项目B的pom.xml (junit4.12是间隔依赖,junit4.11是直接依赖)
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.itheima</groupId><artifactId>day51_03_B</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- 直接依赖 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version></dependency><!--依赖于项目A--><dependency><groupId>com.itheima</groupId><artifactId>day51_02_A</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
效果
点这个按钮可看包的依赖情况

结论
如果一个间接依赖,一个直接依赖:以直接依赖为准
情况3:两个间接依赖
问题
spring-core包到底使用哪个?
- spring-aop 5.2.0间接依赖了spring-core和spring-beans
- spring-tx 4.2.8间接依赖了spring-core和spring-beans
如果版本不同使用哪个jar包
场景
在project_a 中,同时配置spring-aop 5.2.0和spring-tx 4.2.8
配置文件
spring-aop 5.2.0在上面效果

spring-tx 4.2.8在上面的效果

代码
<!-- 两个间接依赖spring-core包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>4.2.8.RELEASE</version></dependency>
结论
如果2个间接依赖:以上面配置为准
小结
| 依赖冲突的三种情况 | 依赖如何处理的 | |
|---|---|---|
| 1 | 两个直接依赖 | 以下面配置的为准 |
| 2 | 一个直接依赖一个间接依赖 | 以直接为准 |
| 3 | 两个间接依赖 | 以上面配置的为准 |
10. 多环境配置
多环境介绍
maven提供配置多种环境的设定,帮助开发者使用过程中快速切换环境
步骤
- 创建的maven工程,复制jdbc.properties到resources目录下
- 修改jdbc.properties中的jdbc.url=${jdbc.url}
jdbc.driverClassName=com.mysql.jdbc.Driverjdbc.url=${jdbc.url}jdbc.username=rootjdbc.password=root
- 在pom.xml中profiles下配置三个不同的环境:开发,生产,测试
- 在profile的properties中分别指定不同的jdbc.url属性值
- 分别选择不同的profile
指定resource的目录地址和开启替换的参数 ```xml <?xml version=”1.0” encoding=”UTF-8”?> <project xmlns=”http://maven.apache.org/POM/4.0.0“
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0 com.itheima multi-env 1.0-SNAPSHOT env_dev jdbc:mysql://127.0.0.1:3306/ssm true env_pro jdbc:mysql://127.2.2.2:3306/ssm env_test jdbc:mysql://127.3.3.3:3306/ssm ${basedir}/src/main/resources true
7. 运行package命令,查看target中的jar包中jdbc.properties中的url是否不同 8. 也可以使用命令行方式执行
mvn 指令 –P 环境定义id
<br /><a name="3acccac8"></a># 11. 继承与聚合:介绍<a name="73e82552-5"></a>## 目标1. 分模块创建项目的好处2. 理解继承与聚合的概念<a name="ef636c63"></a>## 三种不同的实现方式<a name="bc32a18c"></a>### 方式一:传统开发项目中包含企业所有业务的统一系统, 如下:<br />特点:传统开发方式是将这些业务集中在1个web项目中, 缺点是代码量大, 业务插拔不方便 。<a name="fdb67ce7"></a>### 方式二:模块开发特点: 模块化开发业务清晰, 维护方便, 业务插拔较简单, 缺点是各模块间 仍然存在依赖 。<a name="667285e3"></a>### 方式三:微服务特点:将各个业务拆分成多个独立的系统,如下:注:今天使用第二种方式<a name="7ef1bb26"></a>## 传统项目与分模块构件项目区别<a name="3cdd7893"></a>## 分模块创建项目好处1. 项目架构一目了然,更清晰2. 有利于团队合作开发,不同的成员开发一个模块3. 代码的可维护性更强4. 更方便重用,例如:所有的工具类都写到一个utils工程中,不仅当前项目可以用,其他项目也可以用。<a name="4df71bef"></a>## 继承的作用1. 父项目:1. 抽取所有项目公用的配置和插件1. 锁定当前项目中各个子项目依赖的版本2. 子项目:<br />继承父项目,父项目的公用的配置就可以直接使用了<a name="e00e4808"></a>## 聚合的作用主要是为了聚合各个子模块,作为一个整体运行,这样就实现了分模块构建项目而运行的时候是一个整体项目。**聚合与继承通常是一起使用的**<a name="d7df58c7"></a>## 小结:聚合与继承的作用<a name="675500c5"></a># 12. 继承与聚合:案例演示【重点】<a name="73e82552-6"></a>## 目标演示项目的继承与聚合1. 创建父项目project_parent2. 创建子项目project_entity<a name="f610ae8c"></a>## 实现步骤<a name="0879c556"></a>### 第1步:创建父项目project_parent1. 创建父模块,指定父模块的坐标 2. 指定模块的名字,模块根目录,模块文件所在位置 3. 因为父项目中不需要编写Java代码,所以src目录可以删除,只保留pom.xml配置文件。<br />4. 在父项目的pom.xml中添加junit的依赖包```xml<!--添加junit的依赖包--><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency></dependencies>
第2步:创建子项目project_child
- 在project_parent模块下点右键,创建子模块
- 指定子模块的名字,注:模块根目录和位置都在父模块的下一级目录
父项目的pom.xml文件变化:可以看到子模块的聚合信息
- 父模块或聚合模块的打包类型是pom
- 可以通过modules看出当前是一个聚合项目,它聚合了哪些模块
```xml
<?xml version=”1.0” encoding=”UTF-8”?>
4.0.0
com.itheima day51_04_parent 1.0-SNAPSHOT pom day51_05_child <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>
```
子项目的pom.xml文件:可以看到继承于父模块的信息
- 包含parent标签:指定父模块的坐标
- 包含当前模块的坐标信息
```xml
<?xml version=”1.0” encoding=”UTF-8”?>
com.itheima day51_04_parent 1.0-SNAPSHOT
4.0.0 day51_05_child
5. 子模块中继承了父模块中的依赖包 <a name="76711877"></a># 13. 继承与聚合:父模块版本锁定【重点】<a name="69fa3701"></a>## 作用版本锁定,统一维护组件的版本<a name="1bc21f7e"></a>## dependencyManagement元素> 作用:一旦在父项目中使用了版本锁定,就是统一控制各个组件的版本。>> 如果子项目继承父项目,父项目中版本锁定的包子项目是**不能**直接使用的。>> 如果要使用,需要在子项目添加依赖,但不需要指定版本号。>> 注:父项目中版本锁定的jar包,子项目中可以使用,也可以不使用<a name="52b36576-2"></a>## 步骤1. 在父项目中pom.xml1. 在dependencies的上一级配置dependencyManagement1. 配置依赖于junit1. 配置依赖spring-context2. 此时在子项目pom.xml中并没有依赖任何包1. 在子项目需要再配置一次依赖spring-context,子项目中不需要指定版本version,这时子项目中就有了依赖包了1. 因为没有配置junit,所以junit的包并没有继承下来<a name="06e004ef-2"></a>## 代码父项目的pom.xml```xml<!--使用版本锁定--><dependencyManagement><!--添加junit的依赖包--><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!-- 依赖spring的包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.0.RELEASE</version></dependency></dependencies></dependencyManagement>
子项目的pom.xml
<dependencies><!-- 不需要指定版本,因为版本已经锁定 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency></dependencies>
效果

小结
- 父项目如果进行了版本锁定,子项目可以有选择的使用哪些包,可以使用父项目中的包,也可以不使用
- 统一整个项目的版本
14. 分模块构建项目1:父项目和聚合项目【重点】
目标
使用分模块方式构建SSM项目
分析

需求
实现查询所有的用户和他的订单信息
无条件查询

条件查询

准备数据库环境
代码
CREATE DATABASE maven_adv IF NOT EXISTS;USE maven_adv;-- 用户名CREATE TABLE `user` (uid INT PRIMARY KEY AUTO_INCREMENT,`name` VARCHAR(20) NOT NULL,sex CHAR(1) DEFAULT '男',phone VARCHAR(20));INSERT INTO `user` (`name`,sex,phone) VALUES ('张小敏','女','13923454567'), ('李强','男','18712321234'),('邹家俊','男','16233425678');SELECT * FROM `user`;-- 订单表CREATE TABLE `order` (oid INT PRIMARY KEY AUTO_INCREMENT,address VARCHAR(100) COMMENT '订单地址',total DOUBLE COMMENT '金额',uid INT,FOREIGN KEY(uid) REFERENCES `user`(uid));-- 一个用户下多个订单INSERT INTO `order` (address,total,uid) VALUES ('广东省汕头市', 3200,1),('湖南省株洲市', 250,1),('广西省柳州市', 1200,2),('广州市海珠区', 78,2),('海南省海口市', 605,3);-- 查询所有订单SELECT * FROM `order`;-- 查询用户和订单SELECT * FROM `user` u INNER JOIN `order` o ON u.uid = o.uid;
查询结果
表关系如下
创建父项目
- 创建项目ssm_parent
- 删除src目录
- pom.xml文件如下
<!--统一管理依赖包版本--><properties><!-- 指定编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.encoding>UTF-8</maven.compiler.encoding><!--spring 版本--><spring.version>5.2.10.RELEASE</spring.version><!-- log4j日志包版本 --><slf4j.version>1.7.7</slf4j.version><!-- jstl标签版本 --><jstl.version>1.2</jstl.version><!--servlet版本--><servlet.version>3.1.0</servlet.version><!--jsp版本--><jsp.version>2.0</jsp.version><!-- mybatis版本号 --><mybatis.version>3.5.0</mybatis.version><!--mysql驱动版本--><mysql.version>5.1.30</mysql.version><!-- mybatis-spring整合包版本 --><mybatis.spring.version>1.3.1</mybatis.spring.version><!--druid版本--><druid.version>1.0.29</druid.version><!-- aspectj版本号 --><aspectj.version>1.6.12</aspectj.version><!--json--><jackson.version>2.9.8</jackson.version><!--lombok--><lombok.version>1.18.6</lombok.version><!-- junit --><junit.version>4.12</junit.version></properties><dependencies><!--spring依赖包--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><!-- spring mvc包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><!--spring jdbc包--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><!--aspectj包--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>${aspectj.version}</version></dependency><!--servlet依赖--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>${servlet.version}</version></dependency><!-- mybatis核心包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>${mybatis.version}</version></dependency><!-- mybatis-spring整合包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>${mybatis.spring.version}</version></dependency><!-- mysql数据库依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!--数据库连接池druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><!-- log4j包 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version></dependency><!--json包--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${jackson.version}</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><!--spring-test测试包--><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency></dependencies>
15. 分模块构建项目2:实体类,持久层【重点】
目标
- 创建实体类子模块
- 持久层子模块
- 业务层子模块
创建父工程
- 创建实体类ssm_entity工程
- 结构如下
- 创建用户实体类
package com.itheima.entity;import lombok.Data;@Datapublic class User {private Integer uid;private String name;private char sex;private String phone;}
- 创建订单实体类,订单类中包含了用户类
package com.itheima.entity;import lombok.Data;/*** 一个订单对应一个用户*/@Datapublic class Order {private Integer oid;private String address;private Double total;private User user; //包含了用户对象,查询订单对象,可以获取到用户对象的属性}
持久层步骤
- 创建ssm_dao项目
- 添加依赖: ssm_entity项目
- 编写dao接口
- 编写查询用户和订单的方法
- 方法提供address地址做为参数
- 使用XML的配置方式
- 创建实体类映射配置文件
注:在resources下创建目录名要使用/,而不是点号
- 使用表连接查询用户表和订单表的信息
- 创建resultMap,指定id和type属性。
注:需要在applicationContext.xml中SqlSessionFactoryBean配置别名typeAliasesPackage - 创建子元素result,指定属性:user.uid,映射的列是uid
- 创建子元素result,指定属性:user.name,映射的列是name
- 创建子元素result,指定属性:user.sex,映射的列是sex
- 创建子元素result,指定属性:user.phone,映射的列是phone
- 查询的结果指定为上面的resultMap
实现
- 创建ssm_dao项目
添加依赖: ssm_entity
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>ssm_parent</artifactId><groupId>com.itheima</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ssm_dao</artifactId><!-- 依赖于entity --><dependencies><dependency><groupId>com.itheima</groupId><artifactId>ssm_entity</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
- 编写dao接口,查询所有的用户和订单信息。注:Order不要导错了 ```java package com.itheima.dao;
import com.itheima.entity.Order; import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface OrderDao { /**
* 查询所有的订单和用户*/List<Order> findUserAndOrder(@Param("address") String address);
}
4. 编写XML配置文件,查询所有的用户和订单1. 配置映射对象1. 将order对象中user属性创建映射关系1. 查询订单所有的用户和订单```xml<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.itheima.dao.OrderDao"><!-- 创建一个实体映射关系 --><resultMap id="orderMap" type="com.itheima.entity.Order"><result property="user.uid" column="uid"/><result property="user.name" column="name"/><result property="user.sex" column="sex"/><result property="user.phone" column="phone"/></resultMap><!-- 查询用户和订单 --><select id="findUserAndOrder" resultMap="orderMap">SELECT * FROM `user` u INNER JOIN `order` o ON u.uid = o.uid</select></mapper>
16. 分模块构建项目2:业务层
步骤
- 创建项目:ssm_service
- 添加dao层的依赖:ssm_dao
- 编写service接口:查询所有用户和订单
- 编写service实现类:调用DAO查询
实现
- 创建项目:ssm_service

结构
添加dao层的依赖:ssm_dao ```xml <?xml version=”1.0” encoding=”UTF-8”?> <project xmlns=”http://maven.apache.org/POM/4.0.0“
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<artifactId>ssm_parent</artifactId><groupId>com.itheima</groupId><version>1.0-SNAPSHOT</version>
4.0.0 ssm_service com.itheima ssm_dao 1.0-SNAPSHOT
3. 编写配置类<br />JdbcConfig```javapackage com.itheima.config;@PropertySource("classpath:jdbc.properties") //加载属性文件public class JdbcConfig {@Value("${jdbc.username}")private String username;@Value("${jdbc.password}")private String password;@Value("${jdbc.url}")private String url;@Value("${jdbc.driverClassName}")private String driverClassName;/*** 创建数据源,放到容器中*/@Beanpublic DataSource dataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);dataSource.setDriverClassName(driverClassName);return dataSource;}/*** 创建事务管理器*/@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}}
MybatisConfig
jdbc.properties
log4j.properties
SpringConfig
- 编写service接口:查询所有用户和订单
方法的查询参数是字符串的地址 ```java package com.itheima.service;
import com.itheima.entity.Order;
import java.util.List;
public interface OrderService { /**
* 查询所有用户的订单*/List<Order> findUserAndOrder(String address);
}
5. 编写service接口实现:调用DAO查询1. 添加@Service注解,添加到Spring容器1. 使用@Autowared注解,从容器中注入Dao的实现类1. 在方法中调用DAO对象查询记录1. 使用注解式事务```javapackage com.itheima.service.impl;import com.itheima.dao.OrderDao;import com.itheima.entity.Order;import com.itheima.service.OrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;@Servicepublic class OrderServiceImpl implements OrderService {@Autowiredprivate OrderDao orderDao;/*** 查询所有用户的订单* @param address*/@Overridepublic List<Order> findUserAndOrder(String address) {return orderDao.findUserAndOrder(address);}}
- 测试类 ```java package com.itheima.test;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class OrderTest {
@Autowiredprivate OrderService orderService;@Testpublic void testFindOrder() {List<Order> orders = orderService.findUserAndOrder("");orders.forEach(System.out::println);}
}
<a name="844393f7-1"></a>## 查询结果<a name="e3f5fa89"></a># 17. 分模块构建项目3:表现层子模块【重点】<a name="73e82552-9"></a>## 目标创建web层子模块<a name="52b36576-4"></a>## 步骤1. 创建maven模块:ssm_web<br />2. 修改pom.xml中包的类型为war,并且刷新```xml<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>ssm-parent</artifactId><groupId>com.itheima</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ssm-web</artifactId><packaging>war</packaging><dependencies><dependency><groupId>com.itheima</groupId><artifactId>ssm-service</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
- 将java工程转成web工程

为OK以后
点Yes
- 选择上面的添加web.xml
- 选择正确的目录结构:
scr\main\webapp\WEB-INF\web.xml
- 结构如下,完成
实现
- SpringMvcConfig ```java package com.itheima.config;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration @ComponentScan({“com.itheima.controller”, “com.itheima.config”}) //扫描控制器 @EnableWebMvc //开启json转换 public class SpringMvcConfig { }
5. 启动时加载的配置类```javapackage com.itheima.config;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;/*** tomcat启动的时候自动加载的配置类*/public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {/*** 加载Spring的配置类,父容器* @return*/@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{SpringConfig.class};}/*** 加载SpringMVC的配置类,子容器* @return*/@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}}
18. SSM案例:显示所有订单
目标

静态资源
- 复制静态资源
- 静态资源放行
package com.itheima.config;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configurationpublic class SpringMvcSupport extends WebMvcConfigurationSupport {/*** 把静态资源放行*/@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {System.out.println("静态资源放行");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/**").addResourceLocations("/");}}
- 建议部署到tomcat中运行,注:是部署ssm_web项目到tomcat中,而不是部署ssm_parent项目
注:分模块构建中使用tomcat插件运行有时会出现找不到jar包的情况


代码
如果部署运行出现找不到类,则在父工程上打包一次

控制器代码
package com.itheima.controller;import com.itheima.entity.Order;import com.itheima.service.OrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController@RequestMapping("/order")public class OrderController {@Autowiredprivate OrderService orderService;/*** 查询用户和订单*/@RequestMapping("/find")public List<Order> find(String address) {return orderService.findUserAndOrder(address);}}
页面测试

页面代码
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>查询所有联系人</title><!-- 1. 导入CSS的全局样式 --><link href="css/bootstrap.min.css" rel="stylesheet"><!-- 2. jQuery导入,建议使用1.9以上的版本 --><script src="js/jquery-3.3.1.js"></script><!-- 3. 导入bootstrap的js文件 --><script src="js/bootstrap.min.js"></script><script src="js/vue.js"></script><script src="js/axios.js"></script><style type="text/css">tr, th {text-align: center;}</style></head><body><div class="container"><div class="row"><div class="col-md-4"><h3>用户和订单列表</h3></div><div class="col-md-8"><div class="input-group" style="padding-top: 15px"><div class="input-group"><input type="text" id="address" name="address" class="form-control" placeholder="输入查询的地址"><span class="input-group-btn"><button class="btn btn-primary" type="button" onclick="findAll()">查询订单</button></span></div></div></div></div><div class="row"><div class="col-md-12"><table border="1" class="table table-striped table-bordered table-hover table-condensed"><tr class="info"><th>编号</th><th>姓名</th><th>性别</th><th>电话</th><th>地址</th><th>金额</th></tr><tbody id="orderBody"><tr v-for="(order,index) in orderData"><td>{{index+1}}</td><td>{{order.user.name}}</td><td>{{order.user.sex}}</td><td>{{order.user.phone}}</td><td>{{order.address}}</td><td>{{order.total}}</td></tr></tbody></table></div></div></div></div></body><script type="text/javascript">new Vue({el: ".container",data: {orderData: []},methods: {//查询所有订单findAll() {axios.get("/order/find").then(resp => {this.orderData = resp.data;});}},created() {this.findAll();}});</script></html>
19. SSM案例:完成订单的模糊查询
目标


步骤
修改OrderDao.xml中的配置
- 判断address如果不为空,而且也不为空串,则做为where条件拼接在查询语句的后面
- 模糊查询使用
"%"#{address}"%"
注:mybatis中如果使用if等表达式时,方法上的参数要使用@Param(“address”)注解,否则会出现异常。
代码
OrderDao.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.itheima.dao.OrderDao"><!-- 创建一个实体映射关系 --><resultMap id="orderMap" type="com.itheima.entity.Order"><result property="user.uid" column="uid"/><result property="user.name" column="name"/><result property="user.sex" column="sex"/><result property="user.phone" column="phone"/></resultMap><!-- 查询用户和订单 --><select id="findUserAndOrder" resultMap="orderMap">SELECT * FROM `user` u INNER JOIN `order` o ON u.uid = o.uid<if test="address!=null and address!=''">where address like "%"#{address}"%"</if></select></mapper>
页面代码
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>查询所有联系人</title><!-- 1. 导入CSS的全局样式 --><link href="css/bootstrap.min.css" rel="stylesheet"><!-- 2. jQuery导入,建议使用1.9以上的版本 --><script src="js/jquery-3.3.1.js"></script><!-- 3. 导入bootstrap的js文件 --><script src="js/bootstrap.min.js"></script><script src="js/vue.js"></script><script src="js/axios.js"></script><style type="text/css">tr, th {text-align: center;}</style></head><body><div class="container"><div class="row"><div class="col-md-4"><h3>用户和订单列表</h3></div><div class="col-md-8"><div class="input-group" style="padding-top: 15px"><div class="input-group"><input type="text" v-model="address" class="form-control" placeholder="输入查询的地址"><span class="input-group-btn"><button class="btn btn-primary" type="button" @click="findAll()">查询订单</button></span></div></div></div></div><div class="row"><div class="col-md-12"><table border="1" class="table table-striped table-bordered table-hover table-condensed"><tr class="info"><th>编号</th><th>姓名</th><th>性别</th><th>电话</th><th>地址</th><th>金额</th></tr><tbody id="orderBody"><tr v-for="(order,index) in orderData"><td>{{index+1}}</td><td>{{order.user.name}}</td><td>{{order.user.sex}}</td><td>{{order.user.phone}}</td><td>{{order.address}}</td><td>{{order.total}}</td></tr></tbody></table></div></div></div></div></body><script type="text/javascript">new Vue({el: ".container",data: {orderData: [],address: ''},methods: {//查询所有订单findAll() {axios.get("/order/find?address=" + this.address).then(resp => {this.orderData = resp.data;});}},created() {this.findAll();}});</script></html>
