1.初识Maven
1.1介绍
Maven是一款用于管理和构建Java项目的工具,是Apache旗下的一个开源项目。
1.2Maven的作用
1.2.1依赖管理
方便快捷地管理项目依赖的资源(jar包),避免版本冲突的问题。
1.2.2项目构建
提供了标准化的跨平台的自动化构建方式。
方便地完成项目的编译(compile)、测试(test)、打包(package)、发布(deploy)等操作。
1.2.3统一项目结构
提供了标准的、统一的项目结构。
2.Maven概述
2.1Maven介绍
2.2Maven模型
- 项目对象模型
- 依赖管理模型
- 构建生命周期/阶段
2.3Maven仓库
- 本地仓库
- 中央仓库 https://repo1.maven.org/maven2/
- 远程仓库(私服)
2.4Maven安装
2.4.1下载
2.4.2安装
1.解压安装
解压到没有中文、特殊字符的路径下
E:\ServerEnvironment
bin:存放的是可执行命令。(mvn命令重点关注)
conf:存放Maven的配置文件。(settings.xml配置文件后期需要修改)
lib:存放Maven依赖的jar包。(Maven也是使用java开发的,所以它也依赖其他的jar包)
2.配置本地仓库
在Maven安装目录中新建一个文件夹mvn_repo,当作本地仓库,用来存储jar包
进入conf目录下修改settings.xml
配置文件
a、打开settings.xml文件,定位到53行
b、复制<localRepository>
粘贴到注释的外面(55行)
c、复制之前新建的用来存储jar包的路径,替换掉<localRepository>
标签中的内容
3.配置阿里云私服
进入conf目录下修改settings.xml
配置文件
定位到160行左右
将<mirrors>
子标签<mirror>
中的内容替换成
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
4.配置Maven环境变量
1.系统变量新建MAVEN_HOME。变量值为maven的解压安装目录
2.在path中进行配置。%MAVEN_HOME%\bin
3。cmd中输入mvn -v
进行验证,如图所示则表示安装成功
5.配置关联的JDK版本(可选)
进入conf目录下修改settings.xml
配置文件
在 <profiles> </profiles>
中增加如下配置:
<profile>
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>17</jdk>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
</properties>
</profile>
3.IDEA集成Maven
3.1创建Maven项目
3.1.1全局设置
关闭当前项目
进入全局设置
Build,Execution,Deployment
=> Build Tools
=> Maven
三行分别为:Maven安装目录;安装目录下的settings.xml文件夹;Maven的仓库路径(选完settings.xml会自己设置)
配置工程的编译版本为17。
这里是全局配置信息,以后再创建project默认就是我们全局配置的信息。
3.1.2创建项目
创建一个空项目,命名为 web-project01
点击齿轮,选择 Project Structure,设置JDK的版本号
创建模块
选择Maven,填写基本信息
创建HelloWorld类并运行
目录结构
src
main
源代码java文件目录
源代码配置文件目录
test
测试代码java文件目录
测试代码配置文件目录
target 编译、打包生成文件存放目录
3.1.3pom文件详解
POM(Project Object Model):指的是项目对象模型,用来描述当前的maven项目。
当前文件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">
<!-- POM模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 当前项目坐标 -->
<groupId>com.itheima</groupId>
<artifactId>maven-project01</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 项目的JDK版本及编码 -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
<project>
:pom文件的根标签,表示当前的maven项目
<modelVersion>
:声明项目描述遵循哪一个POM模型版本
<groupId>``<artifactId>``<version>
:坐标,定位项目在本地仓库中的位置,由以上三个标签组成一个坐标
<maven.compiler.source>
:编译JDK的版本
<maven.compiler.target>
:运行JDK的版本
<project.build.sourceEncoding>
:设置项目的字符集
3.2Maven坐标
Maven中的坐标是资源的唯一标识,通过该坐标可以唯一定位资源位置,使用坐标来定义项目或引入项目中需要的依赖。
(资源可以是插件、依赖、当前项目)
(这个项目被其他项目依赖时,也是需要坐标来引入的)
groupId:定义当前Maven项目隶属组织名称(通常是域名反写)
artifactId:定义当前Maven项目名称(通常是模块名称,例如 order-service、goods-service)
version:定义当前项目版本号
SNAPSHOT:功能不稳定、尚处于开发中的版本、即快照版本
RELEASE:功能趋于稳定、当前更新停止,可用于发行的版本
3.3导入Maven项目
- 方式一:
File
->Project Structure
->Modules
->Import Module
->选择maven项目的pom.xml
。
- 方式二:
Maven面板
->+(Add Maven Projects)
->选择maven项目的pom.xml
。
4.依赖管理
4.1依赖配置
4.1.1基本配置
依赖:指当前项目运行需要的jar包,一个项目可以引入多个依赖
在当前工程中,我们需要用到logback来记录日志
1.在pom.xml中编写<dependencies>
标签
2.在<dependencies>
标签中使用<dependency>
引入坐标
<dependencies>
<!-- 依赖 : spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.4</version>
</dependency>
</dependencies>
点击刷新按钮,引入最新的坐标
:::info
1.如果引入的依赖在本地仓库中不存在,将会连接远程仓库/中央仓库,然后下载依赖
2.如果不知道依赖的坐标信息,可以到mvn的中央仓库(https://mvnrepository.com/)中搜索
:::
4.1.2查找依赖
以常见的logback-classic为例,版本1.2.11
- 利用中央仓库搜索依赖的坐标
找到对应版本
复制到xml文件中
- 利用IDEA工具搜索依赖
xml文件标签下 Alt + Insert快捷键弹出搜索窗口
找到对应版本
创建成功,刷新即可
- 熟练后快速导入依赖
直接键入 + 自动联想
4.1.3依赖传递
查看之前配置过的spring-context依赖,可以看到引入的依赖并不只是这一项,而是有非常多的依赖,这就涉及到Maven中非常重要的特性 依赖传递。
如果传递下来的依赖,在项目开发中我们确实不需要,那么就可以通过依赖中的排除依赖功能将其排除。
4.1.4排除依赖
传递下来的micrometer-observation的依赖
加入依赖排除的配置后,该依赖就被排除掉了
4.2生命周期
4.2.1介绍
Maven的生命周期就是为了对所有的构建过程进行抽象和统一,描述了一次项目构建应该经历哪些阶段。这个生命周期包含了项目的清理, 初始化,编译,测试,打包,集成测试,验证,部署和站点生成等几乎所有步骤。
Maven对项目构建的生命周期划分为3套(相互独立):
- clean:清理工作。
- default:核心工作。如:编译、测试、打包、安装、部署等。
- site:生成报告、发布站点等。
每套生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。
我们主要关注以下阶段就可:
- clean:移除上一次构建生成的文件
- compile:编译项目源代码
- test:使用合适的单元测试框架运行测试(junit)
- package:将编译后的文件打包,如:jar、war等
- install:安装项目到本地仓库
Maven的生命周期是抽象的,这意味着生命周期本身不做任何实际工作。在Maven的设计中,实际任务(如源代码编译)都交由插件来完成。
IDEA中在右侧Maven工具栏中已经给出了快速访问通道
- 生命周期的顺序是:clean --> validate --> compile --> test --> package --> verify --> install --> site --> deploy
- 我们需要关注的就是:clean --> compile --> test --> package --> install
:::info
在同一套生命周期中,当执行后面的生命周期时,前面的生命周期都会执行。
例:当运行package时,clean不会运行,compile会运行。因为compile与package属于同一套生命周期,而clean与package不属于同一套生命周期。
:::
4.2.2执行
一、在IDEA中执行
双击compile,由插件执行,对源代码进行编译
编译后生成target目录及字节码文件
二、命令行执行
打开Maven项目对应的磁盘目录,进入cmd,输入mvn clean
同理
mvn compile
mvn test
mvn package
mvn install
5.单元测试
5.1介绍
阶段划分:单元测试 --> 集成测试 --> 系统测试 --> 验收测试
测试方法:黑盒、白盒、灰盒
5.2Junit入门
5.2.1单元测试
针对最小的功能单元(方法),编写测试代码对其正确性进行测试
JUnit:最流行的Java测试框架之一
通过main方法进行测试有如下问题:
- 测试代码与源代码未分开,难维护。
- 一个方法测试失败,影响后面的方法。
- 无法自动化测试,得到测试报告。
JUnit单元测试的优势:
- 测试代码与源代码分开,便于维护。
- 可以根据需要进行自动化测试。
- 可自动分析测试结果,产出测试报告。
5.2.2入门程序
需求:使用JUnit,对UserService中的业务方法进行单元测试。
package com.itheima;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
public class UserService {
//给定一个身份证号,计算出该用户的年龄
public Integer getAge(String idCard){
if(idCard == null || idCard.length() != 18){
throw new IllegalArgumentException("无效的身份证号码");
}
String birthday = idCard.substring(6,14);
LocalDate parse = LocalDate.parse(birthday, DateTimeFormatter.ofPattern("yyyyMMdd"));
return Period.between(parse,LocalDate.now()).getYears();
}
public String getGender(String idCard){
if(idCard == null || idCard.length() != 18){
throw new IllegalArgumentException("无效的身份证号码");
}
return Integer.parseInt(idCard.substring(16,17)) % 2 == 1 ? "男" : "女";
}
}
- 在
pom.xml
中引入JUnit的依赖。
- 在test/java目录下,创建相同的包,创建测试类,并编写对应的测试方法,并在方法上声明@Test注解。
@Test
public void testGetAge(){
Integer age = new UserService().getAge("110002200505091218");
System.out.println(age);
}
- 运行单元测试(通过:绿色;失败:红色)。
:::info
测试类的命名规范为:XxxxTest
测试方法的命名规定为:public void xxx(){}
:::
5.3断言
JUnit提供了一些辅助方法,用来帮我们确定被测试的方法是否按照预期的效果正常工作,这种方式称为断言。
断言方法 | 描述 |
---|---|
assertEquals(Object exp, Object act, String msg) | 检查两个值是否相等,不相等就报错。 |
assertNotEquals(Object unexp, Object act, String msg) | 检查两个值是否不相等,相等就报错。 |
assertNull(Object act, String msg) | 检查对象是否为null,不为null,就报错。 |
assertNotNull(Object act, String msg) | 检查对象是否不为null,为null,就报错。 |
assertTrue(boolean condition, String msg) | 检查条件是否为true,不为true,就报错。 |
assertFalse(boolean condition, String msg) | 检查条件是否为false,不为false,就报错。 |
assertSame(Object exp, Object act, String msg) | 检查两个对象引用是否相等,不相等,就报错。 |
@Test
public void testGetAge2(){
Integer age = new UserService().getAge("110002200505091218");
Assertions.assertNotEquals(18, age, "两个值相等");
// String s1 = new String("Hello");
// String s2 = "Hello";
// Assertions.assertSame(s1, s2, "不是同一个对象引用");
}
@Test
public void testGetGender2(){
String gender = new UserService().getGender("612429198904201611");
Assertions.assertEquals("男", gender);
}
测试结果
5.4常见注解
注解 | 说明 | 备注 |
---|---|---|
@Test | 测试类中的方法用它修饰才能成为测试方法,才能启动执行 | 单元测试 |
@BeforeEach | 用来修饰一个实例方法,该方法会在每一个测试方法执行之前执行一次。 | 初始化资源(准备工作) |
@AfterEach | 用来修饰一个实例方法,该方法会在每一个测试方法执行之后执行一次。 | 释放资源(清理工作) |
@BeforeAll | 用来修饰一个静态方法,该方法会在所有测试方法之前只执行一次。 | 初始化资源(准备工作) |
@AfterAll | 用来修饰一个静态方法,该方法会在所有测试方法之后只执行一次。 | 释放资源(清理工作) |
@ParameterizedTest | 参数化测试的注解 (可以让单个测试运行多次,每次运行时仅参数不同) | 用了该注解,就不需要@Test注解了 |
@ValueSource | 参数化测试的参数来源,赋予测试方法参数 | 与参数化测试注解配合使用 |
@DisplayName | 指定测试类、测试方法显示的名称 (默认为类名、方法名) |
演示 @BeforeEach
,@AfterEach
,@BeforeAll
,@AfterAll
注解:
@BeforeEach
public void testBefore(){
System.out.println("before...");
}
@AfterEach
public void testAfter(){
System.out.println("after...");
}
@BeforeAll //该方法必须被static修饰
public static void testBeforeAll(){
System.out.println("before all ...");
}
@AfterAll //该方法必须被static修饰
public static void testAfterAll(){
System.out.println("after all...");
}
@Test
public void testGetAge(){
Integer age = new UserService().getAge("110002200505091218");
System.out.println(age);
}
@Test
public void testGetGender(){
String gender = new UserService().getGender("612429198904201611");
System.out.println(gender);
}
测试结果
演示 @ParameterizedTest
,@ValueSource
,@DisplayName
注解:
package com.itheima;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@DisplayName("测试-学生业务操作")
public class UserServiceTest {
@DisplayName("测试-获取年龄")
@Test
public void testGetAge(){
Integer age = new UserService().getAge("110002200505091218");
System.out.println(age);
}
@DisplayName("测试-获取性别")
@Test
public void testGetGender(){
String gender = new UserService().getGender("612429198904201611");
System.out.println(gender);
}
@DisplayName("测试-获取性别3")
@ParameterizedTest
@ValueSource(strings = {"612429198904201611","612429198904201631","612429198904201626"})
public void testGetGender3(String idcard){
String gender = new UserService().getGender(idcard);
System.out.println(gender);
}
}
测试结果
:::info
规范的单元测试必须要在test目录中编写
:::
5.5依赖范围
依赖的jar包通常可以在任何地方使用。如果希望限制依赖的使用范围,可以通过<scope>...</scope>
设置其作用范围。
Junit的依赖自动配置了范围,为test
在主程序中午饭使用Junit的依赖
scope常见取值如下
scope值 | 主程序 | 测试程序 | 打包(运行) | 范例 |
---|---|---|---|---|
compile(默认) | Y | Y | Y | log4j |
test | - | Y | - | junit |
provided | Y | Y | - | servlet-api |
runtime | - | Y | Y | jdbc驱动 |