【Spring Boot】第13課-在 application.properties 配置檔提供參數(以 Java Mail 為例)#2024 年更新


https://unsplash.com/photos/LmyPLbbUWhA

在專案中串接資料庫或其他第三方服務,通常都需要那些平台的主機位址、帳密或其他設定值,有些人稱之為「連線字串」(connection string)。

若有一些像這樣的參數,我們希望在不同場合啟動程式時(如開發環境、測試環境),能彈性切換成不同值,那麼可以將其寫在一個叫「配置檔」的地方,再由程式去引用。

本文以透過 Java Mail 寄送純文字郵件為例,示範如何配置參數,並利用 Profile 的功能來切換。最後講解在啟動 JAR 檔時,如何引入配置檔。

本文的練習用專案:
https://github.com/ntub46010/SpringBootTutorial/tree/Ch13-start-v2


一、準備程式專案

(一)範例專案介紹

在本文的練習用專案,能找到筆者事先準備好的範例程式。

第一個是「MailController」,裡面有一支 RESTful API。我們預期它會接收 request,並執行一段寄送 email 的程式。

第二個是「SendMailRequest」,它會在 controller 接收 request body,包含 email 的收件人、主旨與內容。

(二)匯入函式庫

請在 pom.xml 檔案添加「Spring Mail」的依賴。

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

這項依賴其實是 Spring Boot 對 Java Mail 進行封裝後的產物,讓我們容易使用。


二、取得 Google 應用程式密碼

在程式中串接外部服務時,通常都需要那個平台的帳密,郵件服務也不例外。筆者在本文採用 Gmail 來寄信。然而 Google 為了安全性考量,不讓我們直接在程式中使用 Google 密碼。因此接下來請依照指示,產生「應用程式密碼」。

在 Google 帳戶的首頁,前往「安全性」的頁籤,找到「登入 Google 的方式」,進入「兩步驟驗證」畫面。

從畫面最下方,進入「應用程式密碼」畫面。

在畫面中為這次要建立的密碼取個名字。

按下「建立」後,即可得到 16 個字的應用程式密碼。

請讀者將這組密碼記在別的地方,因為離開此畫面後,便無法再看到了。

三、認識 Java Mail 的用法

本節展示如何使用 Java Mail 發送純文字郵件,藉此讓讀者知道需要哪些設定值。

上面的範例程式中,在「createMailSender」方法初始化了 JavaMailSenderImpl 物件,它需要一些有關郵件服務的參數。例如主機、port 號、帳密等。

而 API 處理方法「sendPlainText」,則建立了 SimpleMailMessage 物件,填入郵件的寄件人、收件人、主旨與內容,最後寄出。

其中透過 setFrom 方法,在寄件人填入 名稱<信箱> 格式的字串,可以讓收件人看到我們自定義的寄件人名稱,而不是一個 email 地址。

完成後,讀者可用 Postman 之類的工具呼叫該 API。

POST http://localhost:8080/mail
{
    "receivers": ["foo@gmail.com", "bar@gmail.com"],
    "subject": "Hello",
    "content": "World"
}

確認一下目前的程式能夠寄出,並送到目標 email。

四、使用配置檔

(一)撰寫參數

第三節把寄送郵件的所需參數寫死在程式碼中(hard code),這樣的做法有一些缺點:

  • 若串接各種服務的參數都散落在專案的各個地方,以後若要變更,就不容易找到當初那些參數寫在哪裡。
  • 承上,即使集中寫在一個 Java 類別,但每次修改,交付時就得重新打包一次 JAR 檔。

為了便於管理參數,可以將它們集中寫在一個叫做「application.properties」的配置檔中。該檔案位於「src\main\resources」資料夾下。若讀者沒有該檔案,請自行建立一個。

這份配置檔是以 key=value 的格式撰寫,參數名稱的單字可用「.」符號來區隔出階層。

Spring Mail 函式庫提供了「自動配置」的功能,它會讀取配置檔中,名稱以「spring.mail」為開頭的參數,用來建立 JavaMailSenderImpl 元件。

也就是說,除了上面的「mail.display-name」參數是筆者自己取名,其他的名稱都是特別規定的。

(二)注入元件與配置檔參數

以下是將 Spring Mail 自動配置的 JavaMailSenderImpl 元件注入進來。而使用 @Value 注解,則能注入配置檔中的參數。

在上面的程式中,首先注入了自動配置的 JavaMailSenderImpl。由於它其實實作了 JavaMailSender 介面,因此直接以介面宣告也無妨。

此外也注入了「spring.mail.username」與「mail.display-name」這兩個參數,用來填寫寄件人資訊。使用 @Value 注解時,需傳入 ${名稱:預設值} 格式的字串,來指定參數名稱。

而先前用來建立 JavaMailSenderImpl 物件的 createMailSender 方法,則可以移除了。

(三)封裝到配置類別

直接使用 @Value 注解來注入配置檔參數,在小型專案是相當便捷。然而一旦注入到元件的參數變多,該類別的程式碼行數將逐漸變得冗長。

又或者是當一個參數在多個地方被使用,那麼在各處用 @Value 注解來注入,日後可能有不容易維護的問題。

考慮到這兩點,讀者也可選擇將配置檔參數,依照用途集中注入到一個元件類別來管理。

以上建立一個叫做「MailConfig」的類別,並冠上 @Configuration 注解,代表這是與配置有關的元件類別。另外也提供 getter 方法供外部呼叫。

之後便可將配置類別注入到需要使用的地方。


四、使用 Profile 切換配置參數

(一)部署的環境

根據筆者的工作經驗,從寫完程式到上線,系統會依序在以下各種環境運行:

  1. 在本地寫完程式碼後,部署到「開發環境」,與前端串接。筆者前公司有 3 臺這種用途的伺服器。
  2. 部署到「測試環境」,讓測試人員驗證功能正常。
  3. 部署到「正式環境」,提供服務給真實使用者。

每個伺服器環境所需要的參數值可能不同,比方說第三方服務的 IP 位址或帳密。而像資料庫或本文的郵件服務正是典型的例子。

不論在哪一個階段,如果發現 bug,我們會想要在本地連接到這些環境的資料庫,搭配開發工具的偵錯模式(debug mode)追蹤資料,找出問題的成因。

Spring Boot 提供了「Profile」的功能,幫助我們在啟動程式時,切換不同配置檔的參數。

(二)切換配置

以下準備了兩份不同的配置檔,取名為「application-dev.properties」與「application-test.properties」,分別用於開發和測試環境。

這兩個配置檔只有一個叫做「mail.display-name」的參數,它會在範例程式中做為寄件者的名稱。

接著只要在原本的 application.properties 配置檔中,添加「spring.profiles.active」的參數,就能指定啟動時要用哪一份配置檔了,如下:

以上例子使用了「dev」當作參數值,則啟動時,Spring Boot 便會去讀取「application-dev.properties」。至於其他未定義在該配置檔的參數,則會回頭採用 application.properties 當成預設值。


五、啟動 JAR 檔時指定配置檔

上一節的做法適用於在開發工具中運行時,切換不同的配置。而本節將說明如何在啟動 JAR 檔時,指定配置參數。

(一)指定 Profile

事實上,前面所建立的那幾個 application.properties 配置檔,會連同程式專案一起被打包成 JAR 檔。因此在命令列環境啟動時,可提供 -Dspring.profiles.active 這項參數,指定要採用的配置檔。

java -Dspring.profiles.active=test -jar demo.jar

此處指定使用「test」這個 profile,代表要採用「application-test.properties」配置檔。

(二)自行提供配置檔

若讀者自己有準備一份配置檔,可在啟動 JAR 檔時進行指定。假設配置檔與 JAR 檔位於同一個資料夾中,示意如下:

|_ demo.jar
|_ application.properties

啟動時,需切換到該資料夾,執行以下指令:

java -jar demo.jar --spring.config.name=application --spring.config.location=./

此處加上 --spring.config.name--spring.config.location 兩項參數。前者代表配置檔的主檔名,後者為配置檔之於 JAR 檔的相對路徑。

(三)Config 資料夾

若讀者不想輸入太長的啟動指令,也可在 JAR 檔的位置建立一個叫做「config」的資料夾,直接將配置檔放到裡面。相對位置如下:

|_ demo.jar
|_ config
    |_ application.properties

啟動時,只要執行以下簡短的指令即可,Spring Boot 將會優先讀取該資料夾的配置檔。

java -jar demo.jar

六、YAML 檔

YAML 檔是一個常被用來提供配置參數的一種檔案格式,副檔名為「yml」。我們也可將 application.properties 配置檔,改寫成 YAML 檔的格式。Spring Boot 支援以這類檔案做為配置參數的來源。

從內容便可清楚地看出階層之分。該檔案以換行加兩個半形空格縮排為一個階層,相當於 properties 檔的「.」。YAML 格式有時具有較好的可讀性。

本文的完成專案:
https://github.com/ntub46010/SpringBootTutorial/tree/Ch13-fin-v2

上一篇:【Spring Boot】第12課-使用 Jackson 控制回傳的 JSON 欄位

下一篇:【Spring Boot】第14課-自行控制元件的建立方式

留言

  1. 不好意思 看你的文章練習有一陣子 我有個問題想問 我運行結果是500的狀況下 看程式碼沒有問題 是否可能為防火牆阻礙code運行的可能因素?

    回覆刪除
    回覆
    1. 嗨,我重新測試了本文的練習用專案,沒有遇到 HTTP Status 500 的情況。不過倒是發現文中提到的「低安全性應用程式存取權」,已經不是像先前那樣簡單地按下開啟或關閉就好。
      請點擊裡面的「瞭解詳情」,找到「使用應用程式密碼」的部份,根據指示產生16位數的密碼。接著在範例程式中,不要使用 Gmail 的密碼,改成應用程式密碼。
      你再試試看吧!

      刪除
    2. 這部分有使用過 QQ 但仍然是顯示500 再想是因為相關的配置檔沒有裝好嗎 還是真的是像上面所說的防火牆阻礙運行造成 我會再看看 謝謝 大大

      刪除
  2. 剛剛玩了一下 API如同大大做的樣式 但信箱沒收到半個信QQ

    回覆刪除

張貼留言