Spring Boot 2.x (一):第一個 Web 應用 Hello Spring Boot 2

  • 2019 年 11 月 6 日
  • 筆記

一、開發環境

➜  ~ java -version  java version "1.8.0_144"  Java(TM) SE Runtime Environment (build 1.8.0_144-b01)  Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
➜  ~ mvn -version  Apache Maven 3.6.1

二、Spring Boot 簡介

Spring Boot 是由 Pivotal 團隊提供的全新框架,其設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Spring Boot致力於在蓬勃發展的快速應用開發領域(Rapid Application Development)成為領導者。

Spring Boot 具有以下特點:

  • 可以創建獨立的 Spring 應用程式,並且基於 Maven 或 Gradle 插件,可以創建可執行的 JARs 和 WARs;
  • 內嵌 Tomcat 或 Jetty 等 Servlet 容器;
  • 提供自動配置的 「starter」 項目對象模型(POMS)以簡化 Maven 配置;
  • 儘可能自動配置 Spring 容器;
  • 提供一些常見的功能、如監控、WEB容器,健康,安全等功能;
  • 絕對沒有程式碼生成,也不需要 XML 配置。

三、創建 Web 項目

3.1 首先啟動 Idea 找到 File -> New -> Project -> Spring Initializr

3.2 選擇 Next,填寫項目元資訊

  • Group: 組織 ID,一般分為多個段,第一段為域,第二段為公司名稱。域又分為 org、com 或 cn 等等,其中 org 為非營利組織,com 為商業組織
  • Artifact: 唯一標識符,一般是項目名稱。

3.3 繼續選擇 Next,勾選項目依賴,這裡選擇 Web -> Spring Web

3.4 填寫項目名和項目路徑

3.5 最後選擇 Finish

此時第一個 Web 項目就創建完成了,對應的目錄結構如下:

├── HELP.md  ├── chapter1.iml  ├── mvnw  ├── mvnw.cmd  ├── pom.xml  └── src      ├── main      │   ├── java      │   │   └── com      │   │       └── semlinker      │   │           └── chapter1      │   │               └── Chapter1Application.java # 項目啟動類,包含main函數      │   └── resources      │       ├── application.properties # 項目主要的配置文件      │       ├── static      │       └── templates      └── test          └── java              └── com                  └── semlinker                      └── chapter1                          └── Chapter1ApplicationTests.java

此外在根目錄下還存在一個 pom.xml 文件,POM(Project Object Model,項目對象模型)是 Maven 工程的基本工作單元,是一個 XML 文件,包含了項目的基本資訊,用於描述項目如何構建,聲明項目依賴,等等。

執行任務或目標時,Maven 會在當前目錄中查找 POM。它讀取 POM,獲取所需的配置資訊,然後執行目標。

POM 中可以指定以下配置:

  • 項目依賴
  • 插件
  • 執行目標
  • 項目構建 profile
  • 項目版本
  • 項目開發者列表
  • 相關郵件列表資訊

了解完 pom 相關的基礎知識,我們來一睹它的真容。打開項目中的 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">      <modelVersion>4.0.0</modelVersion>      <parent>          <groupId>org.springframework.boot</groupId>          <artifactId>spring-boot-starter-parent</artifactId>          <version>2.1.9.RELEASE</version>          <relativePath/> <!-- lookup parent from repository -->      </parent>      <groupId>com.semlinker</groupId>      <artifactId>chapter1</artifactId>      <version>0.0.1-SNAPSHOT</version>      <name>chapter1</name>      <description>Demo project for Spring Boot</description>        <properties>          <java.version>1.8</java.version>      </properties>        <!--  項目依賴  -->      <dependencies>          <!--  默認內嵌Tomcat容器      -->          <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-web</artifactId>          </dependency>          <!--  測試依賴包,執行mvn package的時候,該包並不會被打入,因為它的生命周期只在test之內-->          <dependency>              <groupId>org.springframework.boot</groupId>              <artifactId>spring-boot-starter-test</artifactId>              <scope>test</scope>          </dependency>      </dependencies>        <build>          <plugins>              <plugin>                  <groupId>org.springframework.boot</groupId>                  <artifactId>spring-boot-maven-plugin</artifactId>              </plugin>          </plugins>      </build>    </project>

說了那麼多,有些小夥伴估計已經按捺不住了,我們趕緊來啟動一下我們的第一個 Web 應用。

在運行 Chapter1Application 應用後,我們將在控制台看到 Spring Boot 的啟動資訊:

  .   ____          _            __ _ _   /\ / ___'_ __ _ _(_)_ __  __ _      ( ( )___ | '_ | '_| | '_ / _` |       \/  ___)| |_)| | | | | || (_| |  ) ) ) )    '  |____| .__|_| |_|_| |___, | / / / /   =========|_|==============|___/=/_/_/_/   :: Spring Boot ::        (v2.1.9.RELEASE)  ...  ...  --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer: Tomcat started on port(s): 8080 (http) with context path ''  --- [main] c.s.chapter1.Chapter1Application: Started Chapter1Application in 1.532 seconds (JVM running for 2.045)

通過觀察啟動資訊,我們可知 Spring Boot 默認使用 Tomcat 作為 Servlet 容器,且使用 8080 作為默認埠。小夥伴們是不是覺得入門 So easy,但當你在瀏覽器中訪問 http://localhost:8080/ 地址,你將會看到以下不忍直視的畫面:

Whitelabel Error Page  This application has no explicit mapping for /error, so you are seeing this as a fallback.    Sat Oct 12 12:16:49 CST 2019  There was an unexpected error (type=Not Found, status=404).  No message available

This application has no explicit mapping for /error 錯誤資訊中,可知是由於我們未設置 映射資訊導致的,下面我們來著手解決這個問題。要解決這個問題,我們需要新建一個 HelloController 類,在該類下定義請求映射資訊,具體如下:

package com.semlinker.chapter1.controller;    import org.springframework.web.bind.annotation.RequestMapping;  import org.springframework.web.bind.annotation.RestController;    @RestController  public class HelloController {        @RequestMapping("/")      public String greet() {          return "Hello Spring boot 2.x";      }  }

在完成 HelloController 類的定義之後,我們需要重新啟動一下應用。當應用成功啟動之後,我們再來使用瀏覽器來訪問一下 http://localhost:8080/ 地址,如果不出意外的話,我們將在頁面中看到預期的結果:

Hello Spring boot 2.x

四、常見問題

4.1 埠被佔用怎麼辦

通過前面的介紹,我們可知 Spring Boot 默認使用的埠是 8080,所以如果你們本地的 8080 埠已經被佔用了,那麼你將不能正常啟動 Spring Boot 項目。對於這個問題,我們可以通過一個簡單的方式來解決,即通過配置文件 application.properties 來修改默認的埠。

server.port=8088

當修改完配置文件,重啟應用的時候,在控制台可以看到以下的輸出資訊:

embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8088 (http)

這就表明我們已經成功修改了 Tomcat 默認的埠。

4.2 如何進行單元測試

細心的小夥伴可能會注意到在 chapter1 項目的根目錄下的 pom.xml 文件中還配置了一個依賴 —— spring-boot-starter-test:

<dependency>     <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-test</artifactId>     <scope>test</scope>  </dependency>

顧名思義,這個依賴就是為我們項目提供單元測試支援。

package com.semlinker.chapter1;    import org.junit.Test;  import org.junit.runner.RunWith;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.boot.test.context.SpringBootTest;  import org.springframework.boot.test.web.client.TestRestTemplate;  import org.springframework.boot.web.server.LocalServerPort;  import org.springframework.http.ResponseEntity;  import org.springframework.test.context.junit4.SpringRunner;    import java.net.URL;    import static org.junit.Assert.assertEquals;    @RunWith(SpringRunner.class)  @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)  public class Chapter1ApplicationTests {        @LocalServerPort      private int port;        @Autowired      private TestRestTemplate template;        @Test      public void testGreet() {          ResponseEntity<String> response = template.getForEntity("http://localhost:" + port,            String.class);          assertEquals(response.getBody(), "Hello Spring boot 2.x");      }  }

在 Chapter1ApplicationTests 測試類中,我們通過注入 TestRestTemplate 對象,來發送 Http 請求。需要注意的是在使用 @SpringBootTest 註解時,需要設置 webEnvironment 屬性,否則運行單元測試時,會拋出異常,

詳細資訊可以參考 spring boot test unable to inject TestRestTemplate and MockMvc 這篇文章。

為了讓項目更加直觀,已對項目做了以下調整: Chapter1Application -> HelloSpringBoot2Application com.semlinker.chapter1 -> com.semlinker 項目地址:https://github.com/semlinker/springstack/tree/master/hello-springboot2

五、參考資源