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 切換配置參數
(一)部署的環境
根據筆者的工作經驗,從寫完程式到上線,系統會依序在以下各種環境運行:
- 在本地寫完程式碼後,部署到「開發環境」,與前端串接。筆者前公司有 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
不好意思 看你的文章練習有一陣子 我有個問題想問 我運行結果是500的狀況下 看程式碼沒有問題 是否可能為防火牆阻礙code運行的可能因素?
回覆刪除嗨,我重新測試了本文的練習用專案,沒有遇到 HTTP Status 500 的情況。不過倒是發現文中提到的「低安全性應用程式存取權」,已經不是像先前那樣簡單地按下開啟或關閉就好。
刪除請點擊裡面的「瞭解詳情」,找到「使用應用程式密碼」的部份,根據指示產生16位數的密碼。接著在範例程式中,不要使用 Gmail 的密碼,改成應用程式密碼。
你再試試看吧!
這部分有使用過 QQ 但仍然是顯示500 再想是因為相關的配置檔沒有裝好嗎 還是真的是像上面所說的防火牆阻礙運行造成 我會再看看 謝謝 大大
刪除剛剛玩了一下 API如同大大做的樣式 但信箱沒收到半個信QQ
回覆刪除