SpringBoot系列四:SpringBoot開發(改變環境屬性、讀取資源文件、Bean 配置、模版渲染、profile 配置)
1、概念
SpringBoot 開發深入
2、具體內容
在之前已經基本上了解了整個 SpringBoot 運行機制,但是也需要清楚的認識到以下的問題,在實際的項目開發之中,尤其是 Java 的 MVC 版項目裏面,所有的項目都一定需要滿足於如下幾點要求:
· 訪問的端口不能夠是 8080,應該使用默認的 80 端口;
· 在項目之中為了方便進行數據的維護,建議建立一系列的*.properties 配置文件,例如:提示消息、跳轉路徑;
· 所有的控制器現在都采用了 Rest 風格輸出,但是正常來講,信息的顯示應該交給頁面(不再是 JSP)負責完成;
· 在進行項目打包的時候應該考慮到不同的 profile 配置(不同的環境使用不同的端口訪問,如生產環境80端口,beta環境8090端口,dev環境8080端口)。
2.1、改變環境屬性
通過當前的執行可以發現,默認情況下,在 SpringBoot 裏面啟動 WEB 容器為 Tomcat:
INFO 4448 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
INFO 4448 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
從實際的開發來講,我們的 WEB 部署項目如果是單獨運行不可能運行在 8080 端口上。從正常來講我們的服務器應該運行在80 端口上,所以如果要想修改這樣的默認環境,則必須編寫與之對應的配置文件,該配置文件一定要寫在 classpath 之中,例如: 項目中的“src/main/resources”就是一個 classpath 路徑,那麽在這個目錄之中直接創建有一個 application.properties(文件名稱絕對 不要改變
範例:定義 application.properties 配置文件
1 # 設置Tomcat的運行服務所在端口 2 3 server.port=80
隨後重新運行程序會出現有如下的提示信息:“Tomcat started on port(s): 80 (http)”。
範例:如果有需要也可以配置 contextPath 的信息
# 設置Tomcat的運行服務所在端口
server.port=80
# 可以配置ContextPath訪問路徑,但是在實際開發之中是不能夠進行配置的
server.context-path=/hello
此時的訪問路徑需要追加 contextPath 前綴:http://localhost/hello/;
嚴格來講在 SpringBoot、SpringCloud 裏面可以使用兩類配置文件:application.properties、application.yml。
YAML 文件: 這是一種結構化的數據文件,其在很多的地方上都使用過,例如:Apache Storm 開發組件上進行配置的時候使用的就是yml 配置文件,該配置文件的全稱(Yet Another Markup Languange、仍然是一種標記語言)。
範例:定義 application.yml 配置文件
server:
port: 80 # 此處設置的服務的訪問端口配置
如果 application.properties 和 application.yml 兩個文件同時存在使用那個?
那麽這個時候將優先進行application.properties配置文件的加載,如果現在兩個配置項的作用沖突了,則以 properties 為主,如果不沖突,則以存在的為主。
在之前默認使用的 WEB 容器是 Tomcat 容器,實際上在 SpringBoot 裏面如果用戶有需要也可以將容器更換為 jetty 容器,如果 現在要想使用這個容器,則只需要追加一些依賴即可:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
如果在以後項目以微服務的方式進行打包發布的時候,強烈建議大家使用 jetty 服務進行發布。
2.2、讀取資源文件
在實際的項目開發之中資源文件一定不可或缺,因為所有的提示文字信息都要求在資源文件之中進行定義,而且資源文件是 實現國際化技術的主要手段。如果要想在 SpringBoot 裏面進行資源文件的配置只需要做一些簡單的 application.yml 配置即可,而且 所有註入的資源文件都可以像最初的 Spring 處理那樣直接使用 MessageSource 進行讀取。
1、 為了統一管理資源文件,在“src/main/resources”目錄之中建立有一個 i18n 的存儲目錄;
2、 在“src/main/resources/i18n”目錄之中建立有兩個資源文件:
· 建立 Messages.properties:
welcome.url=www.study.cn
welcome.msg=歡迎{0}光臨!
· 建立 Pages.properties 配置文件:
member.add.page=/pages/back/admin/member/member_add.jsp
member.add.action=/pages/back/admin/member/member_add.action
3、 修改 application.yml 配置文件:
spring: # 表示該配置直接為Spring容器負責處理
messages: # 表示進行資源配置
basename: i18n/Messages,i18n/Pages # 資源文件的名稱
server:
port: 80 # 此處設置的服務的訪問端口配置
4、 當執行完以上的配置之後會自動為用戶創建 MessageSource 對象,那麽用戶在使用的時候直接註入此對象即可。
· 考慮到實際開發的標準型,所以現在建議創建一個父的控制器的抽象類;AbstractBaseController,而後在此抽象類之中進 行資源讀取類的配置;
package cn.study.microboot.util.controller; import java.util.Locale; import javax.annotation.Resource; import org.springframework.context.MessageSource; public abstract class AbstractBaseController { @Resource private MessageSource messageSource; // 自動註入此資源對象 public String getMessage(String key, String... args) { return this.messageSource.getMessage(key, args, Locale.getDefault()); } }
5、 在控制器的子類之中讀取以上的配置信息:
package cn.study.microboot.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import cn.mldn.microboot.util.controller.AbstractBaseController; @RestController public class MessageController extends AbstractBaseController { @RequestMapping(value = "/echo", method = RequestMethod.GET) public String echo(String mid) { System.out.println("【*** 訪問地址 ***】" + super.getMessage("member.add.action")); return super.getMessage("welcome.msg", mid); } }
6、 編寫一個 junit 測試類,來測試以上的控制器程序是否正確:
package cn.study.microboot.test; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import cn.mldn.microboot.StartSpringBootMain; import cn.mldn.microboot.controller.MessageController; @SpringBootTest(classes = StartSpringBootMain.class) @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration public class TestMessageController { @Resource private MessageController messageController; @Test public void testEcho() { System.out.println(this.messageController.echo("lgs")); } }
輸出:
【*** 訪問地址 ***】/pages/back/admin/member/member_add.action
歡迎lgs光臨!
通過 SpringBoot 執行可以清楚的發現,在 SpringBoot 裏面所有對象信息的註入配置操作,都直接通過一行簡單的字符串實現 了,而且最終也能夠保持與之前同樣的運行效果。
2.3、Bean 配置
在使用 Spring 進行開發配置的時候有兩類選擇:*.xml 配置文件、配置的 Bean(@Configure),於是在 SpringBoot 的開發世界 裏面,為了繼續崇尚所謂的“零配置”,提供有一種簡單的支持,也就是說如果現在你真的有配置需要通過*.xml 文件編寫,但是又 不想出現配置文件的話,這個時候最簡單的做法就是使用 Bean 的方式來進行類的配置。
前提:該配置程序的 Bean 所在的包必須是程序啟動類所在包的子包之中,這樣才可以自動掃描到。
1.在傳統的開發中我們一般使用註解@service和@Resource即可完成bean的配置和註入
2.在SpringBoot中使用@Configuration和@Bean配置bean
package cn.study.microboot.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import cn.mldn.microboot.service.impl.MessageServiceImpl; @Configuration // 此處為配置項 public class ServiceConfig { @Bean(name="configService") // 此處返回的是一個Spring的配置Bean,與xml的“<bean>”等價 public MessageServiceImpl getMessageService() { // 方法名稱隨便寫 return new MessageServiceImpl() ; } }
此時采用了自動掃描 Bean 的模式來進行了相關對象的配置。
3、 SSM 或 SSH 開發框架出現的時間比較長,現在遷移到 SpringBoot 之中,那麽如果說現在你已經有一個非常完善的 xml 配置文件出現了,那麽難道還需要將整個的 xml 配置文件轉換為 Bean 配置嗎?為了防止這類情況出現, SpringBoot 也支持有配置文件的 讀取,例如:下面創建一個 spring-common.xml 配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="messageService" class="cn.mldn.microboot.service.impl.MessageServiceImpl" /> </beans>
4、 隨後可以在程序啟動類上使用 xml 進行配置加載:
package cn.study.microboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ImportResource; @SpringBootApplication // 啟動SpringBoot程序,而後自帶子包掃描 @ImportResource(locations={"classpath:spring-common.xml"}) public class StartSpringBootMain { public static void main(String[] args) throws Exception { SpringApplication.run(StartSpringBootMain.class, args); } }
如果此時所配置的兩個 bean 都沒有名字那麽在進行註入的時候一定會出現重復的錯誤,而這個錯誤在新版本裏面將其做了完 善,不過如果要想在開發之中準確的註入指定的對象,則需要使用名字完成:
@Resource(name="messageService") private IMessageService messageService ;
2.4、模版渲染
在之前所見到的信息顯示發現都是以 Rest 風格進行顯示,但是很明顯在實際的開發之中,所有數據的顯示最終都應該交由頁 面完成,但是這個頁面並不是*.jsp 頁面,而是普通的*.html 頁面,而且最為重要的是,此處所使用的渲染的頁面采用的是模版方式 的顯示,而在 Java 開發行業,對於前臺的顯示模版常見的一共有三類技術:FreeMarker、Velocity、thymeleaf(推薦使用),於是下 面就利用 thymeleaf 實現一個簡單的模版渲染操作。
1、 如果要想在項目之中去使用 thymeleaf 模版,那麽應該首先進行相關支持依賴庫的導入,修改 pom.xml 配置文件:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
2、 本次的開發依然要通過一個控制層跳轉到頁面之中進行信息顯示。在 SpringMVC 的時代使用的是 ModelAndView 傳遞,而現 在在 SpringBoot 裏面如果要傳遞直接在方法中定義一個 Model 參數即可。
package cn.study.microboot.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import cn.mldn.microboot.util.controller.AbstractBaseController; @Controller public class MessageController extends AbstractBaseController { @RequestMapping(value = "/show", method = RequestMethod.GET) public String show(String mid, Model model) { model.addAttribute("url", "www.study.cn"); // request屬性傳遞包裝 model.addAttribute("mid", mid); // request屬性傳遞包裝 return "message/message_show"; // 此處只返回一個路徑, 該路徑沒有設置後綴,後綴默認是*.html } }
3、 現在的控制器之中使用的是“@Controller”註解,所以此時執行該控制器的方法後會進行跳轉處理。如果現在要進行跳轉 頁面的定義,有嚴格要求:在CLASSPATH路徑下(src/main/resources、src/main/view)必須建立有一個templates的目錄,在這個目 錄裏面保存有thymeleaf的所有相關頁面,這些頁面可以按照文件目錄保存;
建立一個源代碼目錄:src/main/view;
4、 編寫 message_show.html 頁面(重要提示:該頁面編寫的時候所有的元素一定要完結)
<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>SpringBoot模版渲染</title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> </head> <body> <p th:text="‘官方網站:‘ + ${url}"/> <p th:text="‘用戶名:‘ + ${mid}"/> </body> </html>
5、 運行服務,而後輸入訪問路徑:http://localhost/show?mid=lgs;
6、 如果現在我們所定義的要訪問的頁面不是通過控制器跳轉的怎麽辦?那麽為了解決這樣的問題,可以考慮在 thymeleaf 所在的 父路徑之中“src/main/view”建立一個 static 的子目錄,該目錄保存的是所有靜態頁面;
在以後的實際開發之中,像 js、css、images 等信息文件都要求放在 static 目錄裏面。
7、 thymeleaf 默認的訪問的頁面路徑的後綴為*.html,那麽也可以通過修改 application.yml 配置文件進行變更:
spring: # 表示該配置直接為Spring容器負責處理 thymeleaf: suffix: .htm messages: # 表示進行資源配置 basename: i18n/Messages,i18n/Pages # 資源文件的名稱 server: port: 80 # 此處設置的服務的訪問端口配置
這個時候你需要修改“src/main/view/templates/message”下的 message_show.html 頁面為 message_show.htm 才可以正常訪問。
2.5、profile 配置
在實際的開發之中,由於開發(dev)、測試(beta)、運行(product)的環境不同,有可能需要選擇不同的配置文件,所以在 SpringBoot 裏面充分的考慮到了此類問題,那麽就專門提供有多個 profile 配置,但是對於多 profile 配置一定給要區分出是 yml 還 是 properties,這兩種資源的配置是不同的。
1、 基於 yml 實現 profile 的配置處理:
· 在使用 yml 配置文件的時候所有可以使用的 profile 配置項都要求在一個文件之中編寫;
spring: profiles: active: product --- spring: messages: basename: i18n/Messages,i18n/Pages profiles: dev server: port: 8080 --- spring: messages: basename: i18n/Messages,i18n/Pages profiles: beta server: port: 9090 --- spring: messages: basename: i18n/Messages,i18n/Pages profiles: product server: port: 80
最初進行 profile 切換的處理可以通過 maven 的編譯工具動態選擇,但是在 Spring 裏面可以方便的實現這種切換。
2、 此時所有的 thymeleaf 頁面都保存在“src/main/view”目錄之中,而且所有的 SpringBoot 配置文件(*.yml)這個文件也應該都 一起輸出到 jar 文件裏面,那麽就需要配置一個資源的引用,修改“microboot”中的 pom.xml 配置文件:
<resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.yml</include> <include>**/*.xml</include> <include>**/*.tld</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.tld</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/view</directory> <includes> <include>**/*.*</include> </includes> <filtering>false</filtering> </resource> </resources>
3、 隨後可以將項目進行打包處理,在打包之後也可以動態切換 profile 配置;
· Maven 打包:clean package;
· 隨後如果現在要使用默認的 profile 就正常執行:java -jar microboot.jar;
· 難道以後每一次訪問都需要重新打包嗎?也就是說為了方便用戶的動態進行 profile 切換,可以在程序執行的時候設置一個 執行的處理參數:java -jar microboot.jar --spring.profiles.active=beta;
4、 【趣味問題】現在當運行完成之後你會發現程序之中默認采用的圖標是 Spring 的圖標。
但是很多的公司應該去更換為自己的圖標,所以這個時候可以單獨準備出一個 ico 配置文件,可以將這個配置文件拷貝到 “src/main/view/static/images”目錄之中,隨後在頁面之中進行引入:
<link rel="icon" type="image/x-icon" href="/images/study.ico"/>
5、 在進行 profile 配置的時候特別需要註意一點,如果你使用的是 application.properties 配置,這樣的配置處理過程是不一樣的, 也就是說如果你基於屬性文件完成配置,那麽就需要編寫多個屬性文件內容:
隨後還是需要有一個公共的 application.properties 配置文件出現,用於指派可以使用的 profile 配置:
spring.profiles.active=beta
如果現在將開發程序打成*.jar 文件的話,也同樣可以在執行的時候使用“--spring.profiles.active=beta”動態指派不同的 profile 配置文件。
SpringBoot系列四:SpringBoot開發(改變環境屬性、讀取資源文件、Bean 配置、模版渲染、profile 配置)