Maven 階段 一 :第三章 使用Maven - 命令環(huán)境

第一節(jié) 實(shí)驗(yàn)一:根據(jù)坐標(biāo)創(chuàng)建 Maven 工程

  • 1、Maven 核心概念:坐標(biāo)
    • ①數(shù)學(xué)中的坐標(biāo)
    • ②Maven中的坐標(biāo)
    • ③坐標(biāo)和倉庫中 jar 包的存儲路徑之間的對應(yīng)關(guān)系
  • 2、實(shí)驗(yàn)操作
    • ①創(chuàng)建目錄作為后面操作的工作空間
    • ②在工作空間目錄下打開命令行窗口
    • ③使用命令生成Maven工程
    • ④調(diào)整
    • ⑤自動(dòng)生成的 pom.xml 解讀
  • 3、Maven核心概念:POM
    • ①含義
    • ②模型化思想
    • ③對應(yīng)的配置文件
  • 4、Maven核心概念:約定的目錄結(jié)構(gòu)
    • ①各個(gè)目錄的作用
    • ②約定目錄結(jié)構(gòu)的意義
    • ③約定大于配置

1、Maven 核心概念:坐標(biāo)

1. ① 數(shù)學(xué)中的坐標(biāo)

image.png

使用 x、y、z 三個(gè)『向量』作為空間的坐標(biāo)系,可以在『空間』中唯一的定位到一個(gè)『點(diǎn)』。

2. ② Maven中的坐標(biāo)

  ### 1. \[1\]向量說明
     1. 使用三個(gè)『向量』在『Maven的倉庫』中唯一的定位到一個(gè)『jar』包。
        1. groupId:公司或組織的 id
        2. artifactId:一個(gè)項(xiàng)目或者是項(xiàng)目中的一個(gè)模塊的 id
        3. version:版本號
  ### 2. \[2\]三個(gè)向量的取值方式
     1. groupId:**公司或組織域名的倒序,通常也會(huì)加上項(xiàng)目名稱**
        1. 例如:com.www.maven
     2. artifactId:**模塊的名稱,將來作為 Maven 工程的工程名**
     3. version:**模塊的版本號,根據(jù)自己的需要設(shè)定**
        1. 例如:SNAPSHOT 表示快照版本,正在迭代過程中,不穩(wěn)定的版本
        2. 例如:RELEASE 表示正式版本【快照】

舉例:

     * groupId:com.www.maven
     * artifactId:pro01-www-maven
     * version:1.0-SNAPSHOT

3. ③ 坐標(biāo)和倉庫中 jar 包的存儲路徑之間的對應(yīng)關(guān)系

  ### 1. 坐標(biāo):
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>

上面坐標(biāo)對應(yīng)的 jar 包在 Maven 本地倉庫中的位置:

Maven本地倉庫根目錄\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
一定要學(xué)會(huì)根據(jù)坐標(biāo)到本地倉庫中找到對應(yīng)的 jar 包。

2、實(shí)驗(yàn)操作

①創(chuàng)建目錄作為后面操作的工作空間

例如:D:\Soft\JetBrains\DevInstall\apache-maven-3.8.6\maven-workspace\spaceVideo

WARNING
此時(shí)我們已經(jīng)有了三個(gè)目錄,分別是:

Maven 核心程序:中軍大帳
Maven 本地倉庫:兵營
本地工作空間:戰(zhàn)場

②在工作空間目錄下打開命令行窗口

image.png

③使用命令生成Maven工程

image.png

運(yùn)行** mvn archetype:generate** 命令

TIP

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 7:【直接回車,使用默認(rèn)值】

Define value for property 'groupId': com.www.maven
Define value for property 'artifactId': pro01-maven-java
Define value for property 'version' 1.0-SNAPSHOT: :【直接回車,使用默認(rèn)值】

Define value for property 'package' com.www.maven: :【直接回車,使用默認(rèn)值】

Confirm properties configuration: groupId: com.atguigu.maven artifactId: pro01-maven-java version: 1.0-SNAPSHOT package: com.www.maven Y: :【直接回車,表示確認(rèn)。如果前面有輸入錯(cuò)誤,想要重新輸入,則輸入 N 再回車?!?/p>

④調(diào)整

Maven 默認(rèn)生成的工程,對 junit 依賴的是較低的 3.8.1 版本,我們可以改成較適合的 4.12 版本。

自動(dòng)生成的 App.java 和 AppTest.java 可以刪除

<!-- 依賴信息配置 -->
<!-- dependencies復(fù)數(shù)標(biāo)簽:里面包含dependency單數(shù)標(biāo)簽 -->
<dependencies>
    <!-- dependency單數(shù)標(biāo)簽:配置一個(gè)具體的依賴 -->
    <dependency>
        <!-- 通過坐標(biāo)來依賴其他jar包 -->
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        
        <!-- 依賴的范圍 -->
        <scope>test</scope>
    </dependency>
</dependencies>

⑤自動(dòng)生成的 pom.xml 解讀

<!-- project 標(biāo)簽  :根標(biāo)簽 ,表示對當(dāng)前工程進(jìn)行配置、管理-->
<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 標(biāo)簽 : 從 Maven 2 開始 就固定是 4.0.0-->
    <!--    代表當(dāng)前 pom.xml  所采用的標(biāo)簽結(jié)構(gòu)-->
    <modelVersion>4.0.0</modelVersion>
    <!-- 坐標(biāo)信息 -->
    <!--    groupId 標(biāo)簽 : 坐標(biāo)向量之一 : 代表公司或組織 開發(fā)的某一個(gè)項(xiàng)目 -->
    <groupId>com.www.maven</groupId>
    <!--    artifactId 標(biāo)簽: 坐標(biāo)向量之一 : 代表項(xiàng)目下的某一個(gè) 模塊 -->
    <artifactId>pro01-maven-java</artifactId>
    <!--  version 標(biāo)簽 : 坐標(biāo)向量之一 : 代表當(dāng)前模塊的版本  -->
    <version>1.0-SNAPSHOT</version>
    <!--  package 標(biāo)簽 : 打包方式    -->
    <!--    取值 jar :生成 jar 包,說明是一個(gè)普通的 Java 工程   -->
    <!--    取值 war : 生成 war 包 ,說明這是一個(gè) Web 工程    -->
    <!--    取值 pom :說明這個(gè)工程是用來管理其他工程的工程  -->
    <packaging>jar</packaging>

    <!--    工程名     -->
    <name>pro01-maven-java</name>
    <!--    Maven  官網(wǎng)地址     -->
    <url>http://maven.apache.org</url>

    <!--    在Maven 中定義屬性值       -->
    <properties>
        <!--        在構(gòu)建過程中讀取 源碼時(shí)使用的字符集      -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <!--    dependence 標(biāo)簽: 配置具體依賴信息, 可以包含多個(gè) dependency 子標(biāo)簽 -->
    <dependencies>
        <!--        dependency 標(biāo)簽 :配置一個(gè)具體的依賴信息   -->
        <dependency>
            <!--            坐標(biāo)信息 : 需要導(dǎo)入哪個(gè) jar 包 ,就配置他的坐標(biāo)信息即可        -->
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <!--             scope 標(biāo)簽 : 配置當(dāng)前依賴的范圍       -->
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

3、Maven核心概念:POM

①含義

POM:Project Object Model,項(xiàng)目對象模型。和 POM 類似的是:DOM(Document Object Model),文檔對象模型。它們都是模型化思想的具體體現(xiàn)。

②模型化思想

POM 表示將工程抽象為一個(gè)模型,再用程序中的對象來描述這個(gè)模型。這樣我們就可以用程序來管理項(xiàng)目了。我們在開發(fā)過程中,最基本的做法就是將現(xiàn)實(shí)生活中的事物抽象為模型,然后封裝模型相關(guān)的數(shù)據(jù)作為一個(gè)對象,這樣就可以在程序中計(jì)算與現(xiàn)實(shí)事物相關(guān)的數(shù)據(jù)。

③對應(yīng)的配置文件

POM 理念集中體現(xiàn)在 Maven 工程根目錄下 pom.xml 這個(gè)配置文件中。所以這個(gè) pom.xml 配置文件就是 Maven 工程的核心配置文件。其實(shí)學(xué)習(xí) Maven 就是學(xué)這個(gè)文件怎么配置,各個(gè)配置有什么用。

4、Maven核心概念:約定的目錄結(jié)構(gòu)

①各個(gè)目錄的作用

image.png

另外還有一個(gè) target 目錄專門存放構(gòu)建操作輸出的結(jié)果。

②約定目錄結(jié)構(gòu)的意義

Maven 為了讓構(gòu)建過程能夠盡可能自動(dòng)化完成,所以必須約定目錄結(jié)構(gòu)的作用。

例如:Maven 執(zhí)行編譯操作,必須先去 Java 源程序目錄讀取 Java 源代碼,然后執(zhí)行編譯,最后把編譯結(jié)果存放在 target 目錄。

③約定大于配置

Maven 對于目錄結(jié)構(gòu)這個(gè)問題,沒有采用配置的方式,而是基于約定。這樣會(huì)讓我們在開發(fā)過程中非常方便。如果每次創(chuàng)建 Maven 工程后,還需要針對各個(gè)目錄的位置進(jìn)行詳細(xì)的配置,那肯定非常麻煩。

目前開發(fā)領(lǐng)域的技術(shù)發(fā)展趨勢就是:約定大于配置,配置大于編碼。

第二節(jié) 實(shí)驗(yàn)二:在 Maven 工程中編寫代碼

1、主體程序

image.png

主體程序指的是被測試的程序,同時(shí)也是將來在項(xiàng)目中真正要使用的程序。

package com.www.maven;

/**
 * <p>
 *
 *
 * @author Www
 * <p>
 * 郵箱: 483223455@qq.com
 * <p>
 * 創(chuàng)建時(shí)間: 2022/8/17  15:38  星期三
 * <p>
 */
public class Calculator {
    public int sum(int i, int j){
        return i + j;
    }
}

2、測試程序

image.png
package com.www.maven;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
    
public class CalculatorTest{
    
    @Test
    public void testSum(){
        
        // 1.創(chuàng)建Calculator對象
        Calculator calculator = new Calculator();
        
        // 2.調(diào)用Calculator對象的方法,獲取到程序運(yùn)行實(shí)際的結(jié)果
        int actualResult = calculator.sum(5, 3);
        
        // 3.聲明一個(gè)變量,表示程序運(yùn)行期待的結(jié)果
        int expectedResult = 8;
        
        // 4.使用斷言來判斷實(shí)際結(jié)果和期待結(jié)果是否一致
        // 如果一致:測試通過,不會(huì)拋出異常
        // 如果不一致:拋出異常,測試失敗
        assertEquals(expectedResult, actualResult);
        
    }
    
}

第三節(jié) 實(shí)驗(yàn)三:執(zhí)行 Maven 的構(gòu)建命令

  • 1、要求
  • 2、清理操作
  • 3、編譯操作
  • 4、測試操作
  • 5、打包操作
  • 6、安裝操作

實(shí)驗(yàn)三:執(zhí)行 Maven 的構(gòu)建命令

1、要求

運(yùn)行 Maven 中和構(gòu)建操作相關(guān)的命令時(shí),必須進(jìn)入到 pom.xml 所在的目錄。如果沒有在 pom.xml 所在的目錄運(yùn)行 Maven 的構(gòu)建命令,那么會(huì)看到下面的錯(cuò)誤信息:

The goal you specified requires a project to execute but there is no POM in this directory

TIP

mvn -v 命令和構(gòu)建操作無關(guān),只要正確配置了 PATH,在任何目錄下執(zhí)行都可以。而構(gòu)建相關(guān)的命令要在 pom.xml 所在目錄下運(yùn)行——操作哪個(gè)工程,就進(jìn)入這個(gè)工程的 pom.xml 目錄。

2、清理操作

mvn clean

效果:刪除 target 目錄

3、編譯操作

  • 主程序編譯:mvn compile
  • 測試程序編譯:mvn test-compile
  • 主體程序編譯結(jié)果存放的目錄:target/classes
  • 測試程序編譯結(jié)果存放的目錄:target/test-classes

4、測試操作

mvn test

測試的報(bào)告存放的目錄:target/surefire-reports

5、打包操作

mvn package

打包的結(jié)果——jar 包,存放的目錄:target

6、安裝操作

mvn install

[INFO] Installing D:\maven-workspace\space201026\pro01-maven-java\target\pro01-maven-java-1.0-SNAPSHOT.jar to D:\maven-rep1026\com\atguigu\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.jar
[INFO] Installing D:\maven-workspace\space201026\pro01-maven-java\pom.xml to D:\maven-rep1026\com\atguigu\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.pom

安裝的效果是將本地構(gòu)建過程中生成的 jar 包存入 Maven 本地倉庫。這個(gè) jar 包在 Maven 倉庫中的路徑是根據(jù)它的坐標(biāo)生成的。

坐標(biāo)信息如下:
<!-- 坐標(biāo)信息 -->
    <!--    在本地倉庫中安裝后對應(yīng)的路徑 :com\www\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.jar-->
    <!--    groupId 標(biāo)簽 : 坐標(biāo)向量之一 : 代表公司或組織 開發(fā)的某一個(gè)項(xiàng)目 -->
    <groupId>com.www.maven</groupId>
    <!--    artifactId 標(biāo)簽: 坐標(biāo)向量之一 : 代表項(xiàng)目下的某一個(gè) 模塊 -->
    <artifactId>pro01-maven-java</artifactId>
    <!--  version 標(biāo)簽 : 坐標(biāo)向量之一 : 代表當(dāng)前模塊的版本  -->
    <version>1.0-SNAPSHOT</version>
在 Maven 倉庫中生成的路徑如下:
D:\Soft\JetBrains\DevInstall\apache-maven-3.8.6\repository\com\www\maven\pro01-maven-java\1.0-SNAPSHOT\pro01-maven-java-1.0-SNAPSHOT.jar

另外,安裝操作還會(huì)將 pom.xml 文件轉(zhuǎn)換為 XXX.pom 文件一起存入本地倉庫。所以我們在 Maven 的本地倉庫中想看一個(gè) jar 包原始的 pom.xml 文件時(shí),查看對應(yīng) XXX.pom 文件即可,它們是名字發(fā)生了改變,本質(zhì)上是同一個(gè)文件。

第四節(jié) 實(shí)驗(yàn)四:創(chuàng)建 Maven 版的 Web 工程

  • 1、說明
  • 2、操作
  • 3、生成的pom.xml
  • 4、生成的Web工程的目錄結(jié)構(gòu)
  • 5、創(chuàng)建 Servlet
    • ①在 main 目錄下創(chuàng)建 java 目錄
    • ②在 java 目錄下創(chuàng)建 Servlet 類所在的包的目錄
    • ③在包下創(chuàng)建 Servlet 類
    • ④在 web.xml 中注冊 Servlet
  • 6、在 index.jsp 頁面編寫超鏈接
  • 7、編譯
  • 8、配置對 servlet-api.jar 包的依賴
  • 9、將 Web 工程打包為 war 包
  • 10、將 war 包部署到 Tomcat 上運(yùn)行

實(shí)驗(yàn)四:創(chuàng)建 Maven 版的 Web 工程

1、說明

使用 **mvn archetype:generate **命令生成 Web 工程時(shí),需要使用一個(gè)專門的 archetype。這個(gè)專門生成 Web 工程骨架的 archetype 可以參照官網(wǎng)看到它的用法:

image.png

參數(shù) archetypeGroupId、archetypeArtifactId、archetypeVersion 用來指定現(xiàn)在使用的 maven-archetype-webapp 的坐標(biāo)

2、操作

注意:如果在上一個(gè)工程的目錄下執(zhí)行 mvn archetype:generate 命令,那么 Maven 會(huì)報(bào)錯(cuò):不能在一個(gè)非 pom 的工程下再創(chuàng)建其他工程。所以不要再剛才創(chuàng)建的工程里再創(chuàng)建新的工程,請回到工作空間根目錄來操作。

然后運(yùn)行生成工程的命令:

mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4

下面的操作按照提示執(zhí)行:

TIP

Define value for property 'groupId': com.www.maven Define value for property 'artifactId': pro02-maven-web Define value for property 'version' 1.0-SNAPSHOT: :【直接回車,使用默認(rèn)值】

Define value for property 'package' com.www.maven: :【直接回車,使用默認(rèn)值】

Confirm properties configuration: groupId: com.www.maven artifactId: pro02-maven-web version: 1.0-SNAPSHOT package: com.www.maven Y: :【直接回車,表示確認(rèn)】

3、生成的pom.xml

確認(rèn)打包的方式是war包形式

<packaging>war</packaging>

4、生成的Web工程的目錄結(jié)構(gòu)

image.png

webapp 目錄下有 index.jsp

WEB-INF 目錄下有 web.xml

5、創(chuàng)建 Servlet

①在 main 目錄下創(chuàng)建 java 目錄

image.png

②在 java 目錄下創(chuàng)建 Servlet 類所在的包的目錄

image.png

③在包下創(chuàng)建 Servlet 類

package com.www.maven;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;

/**
 * @author Www
 */
public class HelloServlet extends HttpServlet{
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        response.getWriter().write("hello maven web");
        
    }
    
}

④在 web.xml 中注冊 Servlet

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>helloServlet</servlet-name>
    <servlet-class>com.www.maven.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/helloServlet</url-pattern>
  </servlet-mapping>
</web-app>

6、在 index.jsp 頁面編寫超鏈接

<html>
<body>
<h2>Hello World!</h2>
<a href="helloServlet">Access Servlet</a>
</body>
</html>

TIP

JSP全稱是 Java Server Page,和 Thymeleaf 一樣,是服務(wù)器端頁面渲染技術(shù)。這里我們不必關(guān)心 JSP 語法細(xì)節(jié),編寫一個(gè)超鏈接標(biāo)簽即可。

7、編譯

此時(shí)直接執(zhí)行 mvn compile 命令出錯(cuò):

DANGER
程序包 javax.servlet.http 不存在
程序包 javax.servlet 不存在
找不到符號
符號: 類 HttpServlet ....

上面的錯(cuò)誤信息說明:我們的 Web 工程用到了 HttpServlet 這個(gè)類,而 HttpServlet 這個(gè)類屬于 servlet-api.jar 這個(gè) jar 包。此時(shí)我們說,Web 工程需要依賴 servlet-api.jar 包。

image.png

8、配置對 servlet-api.jar 包的依賴

對于不知道詳細(xì)信息的依賴可以到 https://mvnrepository.com/ 網(wǎng)站查詢。使用關(guān)鍵詞搜索,然后在搜索結(jié)果列表中選擇適合的使用。

image.png

比如,我們找到的 servlet-api 的依賴信息:

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

這樣就可以把上面的信息加入 pom.xml。重新執(zhí)行 mvn compile 命令。

9、將 Web 工程打包為 war 包

運(yùn)行 mvn package 命令,生成 war 包的位置如下圖所示:

image.png

10、將 war 包部署到 Tomcat 上運(yùn)行

將 war 包復(fù)制到 Tomcat/webapps 目錄下
image.png
啟動(dòng) Tomcat:
image.png
image.png

通過瀏覽器嘗試訪問:http://localhost:8080/pro02-maven-web/index.jsp

第五節(jié) 實(shí)驗(yàn)五:讓 Web 工程依賴 Java 工程

  • 1、觀念
  • 2、操作
  • 3、在 Web 工程中,編寫測試代碼
    • ①補(bǔ)充創(chuàng)建目錄
    • ②確認(rèn) Web 工程依賴了 junit
    • ③創(chuàng)建測試類
  • 4、執(zhí)行Maven命令
    • ①測試命令
    • ②打包命令
    • ③查看當(dāng)前 Web 工程所依賴的 jar 包的列表
    • ④以樹形結(jié)構(gòu)查看當(dāng)前 Web 工程的依賴信息

1、觀念

明確一個(gè)意識:從來只有 Web 工程依賴 Java 工程,沒有反過來 Java 工程依賴 Web 工程。本質(zhì)上來說,Web 工程依賴的 Java 工程其實(shí)就是 Web 工程里導(dǎo)入的 jar 包。最終 Java 工程會(huì)變成 jar 包,放在 Web 工程的 ****WEB-INF/lib ****目錄下。

2、操作

在 pro02-maven-web 工程的 pom.xml 中,找到 dependencies 標(biāo)簽,在 dependencies 標(biāo)簽中做如下配置:

<dependency>
    <!-- 配置對Java工程pro01-maven-java的依賴 -->
    <!-- 具體的配置方式:在dependency標(biāo)簽內(nèi)使用坐標(biāo)實(shí)現(xiàn)依賴 -->
     <groupId>com.www.maven</groupId>
     <artifactId>pro01-maven-java</artifactId>
     <version>1.0-SNAPSHOT</version>
     <scope>compile</scope>
</dependency>

3、在 Web 工程中,編寫測試代碼

①補(bǔ)充創(chuàng)建目錄

pro02-maven-web\src\test\java\com\www\maven

②確認(rèn) Web 工程依賴了 junit

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

③創(chuàng)建測試類

把 Java 工程的 CalculatorTest.java 類復(fù)制到 pro02-maven-wb\src\test\java\com\www\maven 目錄下

4、執(zhí)行Maven命令

①測試命令

mvn test

說明:測試操作中會(huì)提前自動(dòng)執(zhí)行編譯操作,測試成功就說明編譯也是成功的。

②打包命令

mvn package

image.png

通過查看 war 包內(nèi)的結(jié)構(gòu),我們看到被 Web 工程依賴的 Java 工程確實(shí)是會(huì)變成 Web 工程的 WEB-INF/lib 目錄下的 jar 包。

image.png

③查看當(dāng)前 Web 工程所依賴的 jar 包的列表

mvn dependency:list

TIP
[INFO] The following files have been resolved:
[INFO] org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] com.www.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile
[INFO] junit:junit:jar:4.12:test

說明:javax.servlet:javax.servlet-api:jar:3.1.0:provided 格式顯示的是一個(gè) jar 包的坐標(biāo)信息。

格式是:
TIP
** groupId:artifactId:打包方式:version:依賴的范圍**

這樣的格式雖然和我們 XML 配置文件中坐標(biāo)的格式不同,但是本質(zhì)上還是坐標(biāo)信息,大家需要能夠認(rèn)識這樣的格式,將來從 Maven 命令的日志或錯(cuò)誤信息中看到這樣格式的信息,就能夠識別出來這是坐標(biāo)。進(jìn)而根據(jù)坐標(biāo)到Maven 倉庫找到對應(yīng)的jar包,用這樣的方式解決我們遇到的報(bào)錯(cuò)的情況。

④以樹形結(jié)構(gòu)查看當(dāng)前 Web 工程的依賴信息

mvn dependency:tree

TIP
[INFO] com.www.maven:pro02-maven-web:war:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.12:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] \- com.www.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile

我們在 pom.xml 中并沒有依賴 hamcrest-core,但是它卻被加入了我們依賴的列表。原因是:junit 依賴了hamcrest-core,然后基于依賴的傳遞性,hamcrest-core 被傳遞到我們的工程了

第六節(jié) 實(shí)驗(yàn)六:測試依賴范圍

  • 1、依賴范圍
    • ①compile 和 test 對比
    • ②compile 和 provided 對比
    • ③結(jié)論
  • 2、測試
    • ①驗(yàn)證 compile 范圍對 main 目錄有效
    • ②驗(yàn)證test范圍對main目錄無效
    • ③驗(yàn)證test和provided范圍不參與服務(wù)器部署
    • ④驗(yàn)證provided范圍對測試程序有效

1、依賴范圍

標(biāo)簽的位置:dependencies/dependency/scope
標(biāo)簽的可選值:compile/test/provided/system/runtime/import

①compile 和 test 對比

main目錄(空間) test目錄(空間) 開發(fā)過程(時(shí)間) 部署到服務(wù)器(時(shí)間)
compile 有效 有效 有效 有效
test 無效 有效 有效 無效

②compile 和 provided 對比

main目錄(空間) test目錄(空間) 開發(fā)過程(時(shí)間) 部署到服務(wù)器(時(shí)間)
compile 有效 有效 有效 有效
provided 有效 有效 有效 無效

③結(jié)論

compile:通常使用的第三方框架的 jar 包這樣在項(xiàng)目實(shí)際運(yùn)行時(shí)真正要用到的 jar 包都是以 compile 范圍進(jìn)行依賴的。比如 SSM 框架所需jar包。

test:測試過程中使用的 jar 包,以 test 范圍依賴進(jìn)來。比如 junit。

provided:在開發(fā)過程中需要用到的“服務(wù)器上的 jar 包”通常以 provided 范圍依賴進(jìn)來。比如 servlet-api、jsp-api。而這個(gè)范圍的 jar 包之所以不參與部署、不放進(jìn) war 包,就是避免和服務(wù)器上已有的同類 jar 包產(chǎn)生沖突,同時(shí)減輕服務(wù)器的負(fù)擔(dān)。說白了就是:“服務(wù)器上已經(jīng)有了,你就別帶啦!”

2、測試

①驗(yàn)證 compile 范圍對 main 目錄有效

TIP

main目錄下的類:HelloServlet 使用compile范圍導(dǎo)入的依賴:pro01-www-maven

驗(yàn)證:使用compile范圍導(dǎo)入的依賴對main目錄下的類來說是有效的

有效:HelloServlet 能夠使用 pro01-www-maven 工程中的 Calculator 類

驗(yàn)證方式:在 HelloServlet 類中導(dǎo)入 Calculator 類,然后編譯就說明有效。

②驗(yàn)證test范圍對main目錄無效

測試方式:在主體程序中導(dǎo)入org.junit.Test這個(gè)注解,然后執(zhí)行編譯。

具體操作:在pro01-maven-java\src\main\java\com\www\maven目錄下修改Calculator.java

package com.atguigu.maven;

import org.junit.Test;

public class Calculator {
    
    public int sum(int i, int j){
        return i + j;
    }
    
}

執(zhí)行Maven編譯命令:

[ERROR] /D:/maven-workspace/space201026/pro01-maven-java/src/main/java/com/www/maven/Calculator.java:[3,17] 程序包org.junit不存在

③驗(yàn)證test和provided范圍不參與服務(wù)器部署

其實(shí)就是驗(yàn)證:通過compile范圍依賴的jar包會(huì)放入war包,通過test范圍依賴的jar包不會(huì)放入war包。


image.png

④驗(yàn)證provided范圍對測試程序有效

測試方式是在pro02-maven-web的測試程序中加入servlet-api.jar包中的類。

修改:pro02-maven-web\src\test\java\com\www\maven\CalculatorTest.java

package com.www.maven;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;

import org.junit.Test;
import com.www.maven.Calculator;

// 靜態(tài)導(dǎo)入的效果是將Assert類中的靜態(tài)資源導(dǎo)入當(dāng)前類
// 這樣一來,在當(dāng)前類中就可以直接使用Assert類中的靜態(tài)資源,不需要寫類名
import static org.junit.Assert.*;

public class CalculatorTest{
    
    @Test
    public void testSum(){
        
        // 1.創(chuàng)建Calculator對象
        Calculator calculator = new Calculator();
        
        // 2.調(diào)用Calculator對象的方法,獲取到程序運(yùn)行實(shí)際的結(jié)果
        int actualResult = calculator.sum(5, 3);
        
        // 3.聲明一個(gè)變量,表示程序運(yùn)行期待的結(jié)果
        int expectedResult = 8;
        
        // 4.使用斷言來判斷實(shí)際結(jié)果和期待結(jié)果是否一致
        // 如果一致:測試通過,不會(huì)拋出異常
        // 如果不一致:拋出異常,測試失敗
        assertEquals(expectedResult, actualResult);
        
    }
    
}

然后運(yùn)行Maven的編譯命令:mvn compile

然后看到編譯成功。

第七節(jié) 實(shí)驗(yàn)七:測試依賴的傳遞性

  • 1、依賴的傳遞性
    • ①概念
    • ②傳遞的原則
  • 2、使用 compile 范圍依賴 spring-core
  • 3、驗(yàn)證 test 和 provided 范圍不能傳遞

1、依賴的傳遞性

①概念

A 依賴 B,B 依賴 C,那么在 A 沒有配置對 C 的依賴的情況下,A 里面能不能直接使用 C?

②傳遞的原則

在 A 依賴 B,B 依賴 C 的前提下,C 是否能夠傳遞到 A,取決于 B 依賴 C 時(shí)使用的依賴范圍。

  * **B 依賴 C 時(shí)使用 compile 范圍:可以傳遞**
  * **B 依賴 C 時(shí)使用 test 或 provided 范圍:不能傳遞,**所以需要這樣的 jar 包時(shí),就必須在需要的地方明確配置依賴才可以

2、使用 compile 范圍依賴 spring-core

測試方式:讓 pro01-maven-java 工程依賴 spring-core

具體操作:編輯 pro01-maven-java 工程根目錄下 pom.xml

<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>

使用 mvn dependency:tree 命令查看效果:

TIP

[INFO] com.www.maven:pro01-maven-java:jar:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.12:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] \- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] \- commons-logging:commons-logging:jar:1.1.1:compile

還可以在 Web 工程中,使用 mvn dependency:tree 命令查看效果(需要重新將 pro01-maven-java 安裝到倉庫):

TIP
[INFO] com.www.maven:pro02-maven-web:war:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.12:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] \- com.www.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile
[INFO] \- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] \- commons-logging:commons-logging:jar:1.1.1:compile

3、驗(yàn)證 test 和 provided 范圍不能傳遞

從上面的例子已經(jīng)能夠看到,pro01-maven-java 依賴了 junit,但是在 pro02-maven-web 工程中查看依賴樹的時(shí)候并沒有看到 junit。

要驗(yàn)證 provided 范圍不能傳遞,可以在 pro01-maven-java 工程中加入 servlet-api 的依賴。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

效果還是和之前一樣:

TIP
[INFO] com.www.maven:pro02-maven-web:war:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.12:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] \- com.www.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile

[INFO] \- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] \- commons-logging:commons-logging:jar:1.1.1:compile

第八節(jié) 實(shí)驗(yàn)八:測試依賴的排除

  • 1、概念
  • 2、配置方式
  • 3、測試

1、概念

當(dāng) A 依賴 B,B 依賴 C 而且 C 可以傳遞到 A 的時(shí)候,A 不想要 C,需要在 A 里面把 C 排除掉。而往往這種情況都是為了避免 jar 包之間的沖突。

image.png

所以配置依賴的排除其實(shí)就是阻止某些 jar 包的傳遞。因?yàn)檫@樣的 jar 包傳遞過來會(huì)和其他 jar 包沖突。

2、配置方式

<dependency>
            <!--             配置對 java 工程的依賴-->
            <groupId>com.www.maven</groupId>
            <artifactId>pro01-maven-java</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
            <!--            配置 依賴的排除  -->
            <exclusions>
                <!--       配置具體排除信息 ,讓 commons-logging 不要傳遞到當(dāng)前項(xiàng)目  -->
                <exclusion>
                    <!--  這里指定坐標(biāo)是不需要指定 version    -->
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

3、測試

測試的方式:在 pro02-maven-web 工程中配置對 commons-logging 的排除

<dependency>
            <!--             配置對 java 工程的依賴-->
            <groupId>com.www.maven</groupId>
            <artifactId>pro01-maven-java</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
            <!--            配置 依賴的排除  -->
            <exclusions>
                <!--       配置具體排除信息 ,讓 commons-logging 不要傳遞到當(dāng)前項(xiàng)目  -->
                <exclusion>
                    <!--  這里指定坐標(biāo)是不需要指定 version    -->
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

運(yùn)行 mvn dependency:tree 命令查看效果:

TIP

[INFO] com.www.maven:pro02-maven-web:war:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.12:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- javax.servlet:javax.servlet-api:jar:3.1.0:provided
[INFO] \- com.www.maven:pro01-maven-java:jar:1.0-SNAPSHOT:compile
[INFO] \- org.springframework:spring-core:jar:4.0.0.RELEASE:compile

發(fā)現(xiàn)在 spring-core 下面就沒有 commons-logging 了。

第九節(jié) 實(shí)驗(yàn)九:繼承

  • 1、概念
  • 2、作用
  • 3、舉例
  • 4、操作
    • ①創(chuàng)建父工程
    • ②創(chuàng)建模塊工程
    • ③查看被添加新內(nèi)容的父工程 pom.xml
    • ④解讀子工程的pom.xml
    • ⑤在父工程中配置依賴的統(tǒng)一管理
    • ⑥子工程中引用那些被父工程管理的依賴
    • ⑦在父工程中升級依賴信息的版本
    • ⑧在父工程中聲明自定義屬性
  • 5、實(shí)際意義

1、概念

Maven工程之間,A 工程繼承 B 工程

  • B 工程:父工程
  • A 工程:子工程

本質(zhì)上是 A 工程的 pom.xml 中的配置繼承了 B 工程中 pom.xml 的配置。

2、作用

父工程中統(tǒng)一管理項(xiàng)目中的依賴信息,具體來說是管理依賴信息的版本。

它的背景是:

  • 對一個(gè)比較大型的項(xiàng)目進(jìn)行了模塊拆分。
  • 一個(gè) project 下面,創(chuàng)建了很多個(gè) module。
  • 每一個(gè) module 都需要配置自己的依賴信息。

它背后的需求是:

  • 在每一個(gè) module 中各自維護(hù)各自的依賴信息很容易發(fā)生出入不易統(tǒng)一管理。
  • 使用同一個(gè)框架內(nèi)的不同 jar 包,它們應(yīng)該是同一個(gè)版本,所以整個(gè)項(xiàng)目中使用的框架版本需要統(tǒng)一。
  • 使用框架時(shí)所需要的 jar 包組合(或者說依賴信息組合)需要經(jīng)過長期摸索和反復(fù)調(diào)試,最終確定一個(gè)可用組合。這個(gè)耗費(fèi)很大精力總結(jié)出來的方案不應(yīng)該在新的項(xiàng)目中重新摸索。

通過在父工程中為整個(gè)項(xiàng)目維護(hù)依賴信息的組合既保證了整個(gè)項(xiàng)目使用規(guī)范、準(zhǔn)確的 jar 包;又能夠?qū)⒁酝慕?jīng)驗(yàn)沉淀下來,節(jié)約時(shí)間和精力。

3、舉例

在一個(gè)工程中依賴多個(gè) Spring 的 jar 包

TIP

[INFO] +- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- org.springframework:spring-beans:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-expression:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.0.0.RELEASE:compile
[INFO] | \- aopalliance:aopalliance:jar:1.0:compile

使用 Spring 時(shí)要求所有 Spring 自己的 jar 包版本必須一致。為了能夠?qū)@些 jar 包的版本進(jìn)行統(tǒng)一管理,我們使用繼承這個(gè)機(jī)制,將所有版本信息統(tǒng)一在父工程中進(jìn)行管理。

4、操作

①創(chuàng)建父工程

創(chuàng)建的過程和前面創(chuàng)建 pro01-maven-java 一樣。

工程名稱:pro03-maven-parent

工程創(chuàng)建好之后,要修改它的打包方式:

    <groupId>com.www.maven</groupId>
    <artifactId>pro03-maven-parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!-- 當(dāng)前工程作為父工程,要去管理其他工程,打包方式必須是 pom  -->
    <packaging>pom</packaging>

只有打包方式為 pom 的 Maven 工程能夠管理其他 Maven 工程。打包方式為 pom 的 Maven 工程中不寫業(yè)務(wù)代碼,它是專門管理其他 Maven 工程的工程。

②創(chuàng)建模塊工程

模塊工程類似于 IDEA 中的 module,所以需要進(jìn)入 pro03-maven-parent 工程的根目錄,然后運(yùn)行 mvn archetype:generate 命令來創(chuàng)建模塊工程。

假設(shè),我們創(chuàng)建三個(gè)模塊工程:


image.png

③查看被添加新內(nèi)容的父工程 pom.xml

下面 modules 和 module 標(biāo)簽是聚合功能的配置

    <!-- 聚合的配置 -->
    <modules>
        <module>pro04-maven-module</module>
        <module>pro05-maven-modele</module>
        <module>pro06-maven-module</module>
    </modules>

④解讀子工程的pom.xml

    <!-- parent 標(biāo)簽給當(dāng)前工程 配置父工程-->
    <parent>
        <!-- 通過指定 父工程的坐標(biāo)找到父工程 -->
        <groupId>com.www.maven</groupId>
        <artifactId>pro03-maven-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <!--  子工程的 groupId 如果和父工程一樣 ,則可以省略-->
    <!--    <groupId>com.www.maven</groupId>-->
    <!--     省略 groupId 和 version 后 ,子工程自己的坐標(biāo)可以只保留 artifactId -->
    <artifactId>pro04-maven-module</artifactId>
    <!--  子工程的 groupId 如果和父工程一樣 ,則可以省略-->
    <!--    <version>1.0-SNAPSHOT</version>-->

⑤在父工程中配置依賴的統(tǒng)一管理

<!-- 使用dependencyManagement標(biāo)簽配置對依賴的管理 -->
<!-- 被管理的依賴并沒有真正被引入到工程 -->
<dependencyManagement>
    <dependencies>
        <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-context</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-aop</artifactId>
            <version>4.0.0.RELEASE</version>
        </dependency>
    </dependencies>
</dependencyManagement>

⑥子工程中引用那些被父工程管理的依賴

關(guān)鍵點(diǎn):省略版本號

<!-- 子工程引用父工程中的依賴信息時(shí),可以把版本號去掉。  -->
<!-- 把版本號去掉就表示子工程中這個(gè)依賴的版本由父工程決定。 -->
<!-- 具體來說是由父工程的dependencyManagement來決定。 -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
    </dependency>
</dependencies>

⑦在父工程中升級依賴信息的版本

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

然后在子工程中運(yùn)行mvn dependency:list,效果如下:

TIP
[INFO] org.springframework:spring-aop:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-core:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-context:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-beans:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-expression:jar:4.1.4.RELEASE:compile

⑧在父工程中聲明自定義屬性

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!--    創(chuàng)建自己定義的屬性標(biāo)簽    -->
        <!--        標(biāo)簽名  : 屬性名-->
        <!--        標(biāo)簽值 : 屬性值-->
        <!--        引用方式:${www.spring.version}-->
        <www.spring.version>5.2.14.RELEASE</www.spring.version>
    </properties>

在需要的地方使用${}的形式來引用自定義的屬性名:

        <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <!--  通過引用屬性表達(dá)式設(shè)定版本號,這樣版本號就成了一個(gè)動(dòng)態(tài)值-->
                <!--  通過屬性名解析后才知道具體是什么值-->
                <version>${www.spring.version}</version>
            </dependency>

真正實(shí)現(xiàn)“一處修改,處處生效”。

5、實(shí)際意義

image.png

編寫一套符合要求、開發(fā)各種功能都能正常工作的依賴組合并不容易。如果公司里已經(jīng)有人總結(jié)了成熟的組合方案,那么再開發(fā)新項(xiàng)目時(shí),如果不使用原有的積累,而是重新摸索,會(huì)浪費(fèi)大量的時(shí)間。為了提高效率,我們可以使用工程繼承的機(jī)制,讓成熟的依賴組合方案能夠保留下來。

如上圖所示,公司級的父工程中管理的就是成熟的依賴組合方案,各個(gè)新項(xiàng)目、子系統(tǒng)各取所需即可。

第十節(jié) 實(shí)驗(yàn)十:聚合

  • 1、聚合本身的含義
  • 2、Maven 中的聚合
  • 3、好處
  • 4、聚合的配置
  • 5、依賴循環(huán)問題

1、聚合本身的含義

部分組成整體

image.png

動(dòng)畫片《戰(zhàn)神金剛》中的經(jīng)典臺詞:“我來組成頭部!我來組成手臂!”就是聚合關(guān)系最生動(dòng)的體現(xiàn)。

2、Maven 中的聚合

使用一個(gè)“總工程”將各個(gè)“模塊工程”匯集起來,作為一個(gè)整體對應(yīng)完整的項(xiàng)目

  • 項(xiàng)目:整體
  • 模塊:部分

TIP

概念的對應(yīng)關(guān)系:
從繼承關(guān)系角度來看:
父工程
子工程

從聚合關(guān)系角度來看:
總工程
模塊工程

3、好處

  • 一鍵執(zhí)行 Maven 命令:很多構(gòu)建命令都可以在“總工程”中一鍵執(zhí)行。

以 mvn install 命令為例:Maven 要求有父工程時(shí)先安裝父工程;有依賴的工程時(shí),先安裝被依賴的工程。我們自己考慮這些規(guī)則會(huì)很麻煩。但是工程聚合之后,在總工程執(zhí)行 mvn install 可以一鍵完成安裝,而且會(huì)自動(dòng)按照正確的順序執(zhí)行。

  • 配置聚合之后,各個(gè)模塊工程會(huì)在總工程中展示一個(gè)列表,讓項(xiàng)目中的各個(gè)模塊一目了然。

4、聚合的配置

在總工程中配置** modules **即可:

    <modules>  
        <module>pro04-maven-module</module>
        <module>pro05-maven-module</module>
        <module>pro06-maven-module</module>
    </modules>

5、依賴循環(huán)問題

如果 A 工程依賴 B 工程,B 工程依賴 C 工程,C 工程又反過來依賴 A 工程,那么在執(zhí)行構(gòu)建操作時(shí)會(huì)報(bào)下面的錯(cuò)誤:

DANGER

[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:

這個(gè)錯(cuò)誤的含義是:循環(huán)引用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容