Halo是一款現代化的我的獨立博客系統,給習慣寫博客的同窗一個更好的選擇。 聽說這是一個較容易讀懂的Spring-Boot項目,那我就但願經過這個項目學習前輩的經驗。java
若有幫助,不勝榮幸。若有錯誤,歡迎指正!web
最先看到這個博客的源碼的時候是經過B站up主-CodeSheep的一個視頻:Java企業級開源項目推薦,幫助你們從學習走向實踐,奈何當時本身知識有限,沒有仔細的閱讀源碼。近日Halo也推出了正式版,我也就抱着學習的心態拜讀一下。spring
首先打開工程,看到整個工程有如下兩個明顯的變化:api
能夠明顯的看到,在處理層級關係的時候,properties須要使用大量的路徑來描述層級(或者屬性),好比environments.dev.url和environments.dev.name。其次,對於較爲複雜的結構,好比數組(my.servers),寫起來更爲複雜。而對應的YAML格式文件就簡單不少:數組
由於此前有過Android的開發經驗,因此這一改變對個人影響並不大😄。gradle逐漸替代meavn應該是目前的趨勢,可是目前大部分教學和企業採用的仍是以meavn爲主,因此此前我也不曾嘗試過採用gradle構建項目。由此看出Halo仍是很Fashion的👍。tomcat
首先打開Application.java
文件,看看有什麼學習的地方🤤。bash
@SpringBootApplication
@EnableJpaAuditing
@EnableScheduling
@EnableAsync
@EnableJpaRepositories(basePackages = "run.halo.app.repository", repositoryBaseClass = BaseRepositoryImpl.class)
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
// Customize the spring config location
System.setProperty("spring.config.additional-location", "file:${user.home}/.halo/,file:${user.home}/halo-dev/");
// Run application
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.setProperty("spring.config.additional-location", "file:${user.home}/.halo/,file:${user.home}/halo-dev/");
return application.sources(Application.class);
}
}
複製代碼
發現與我以前Spring-Boot開發兩點不同的地方:服務器
其一:繼承SpringBootServletInitializer從而實現configure方法架構
可能找答案的姿式不對,只零星找到下面幾點描述:app
一、啓動類繼承SpringBootServletInitializer類,重寫 configure(SpringApplicationBuilder builder`)方法
二、由於想要用web容器啓動項目
三、使用外部 servlet 容器
結論:爲了Undertow容器!
緣由:
一、排除內置的tomcat容器-build.gradle
exclude module: 'spring-boot-starter-tomcat'
複製代碼
二、添加Undertow依賴-build.gradle
implementation 'org.springframework.boot:spring-boot-starter-undertow'
複製代碼
三、配置服務器
server:
port: 8090
use-forward-headers: true
undertow:
io-threads: 2
worker-threads: 36
buffer-size: 1024
directBuffers: true
複製代碼
結合此前在別人基礎上修改的網盤項目獲得了相同的印證。
其二:System.setProperty("spring.config.additional-location", "...");
開發者給瞭如下注釋:Customize the spring config location
(定製spring配置文件的位置)
存在如下三個疑問:
一、System.setProperty有何用?
setProperty (String prop, String value); 一、 設置指定鍵對值的系統屬性,其中prop:系統屬性的名稱,value:系統屬性的值。注:這裏的system,系統指的是 JRE (runtime)system,不是指 OS。 二、System.setProperty至關於一個靜態變量,存在內存裏面,能夠在項目的任何一個地方,經過System.getProperty("變量")來得到
二、爲什麼要設定這個變量?
加載外部配置文件。打包jar運行也不方便修改jar內部數據,經過設置環境變量spring.config.location。由於博客中也有不少配置選項,因此猜測須要從外部讀取某些會改變的配置,須要繼續閱讀源碼驗證猜測。
三、${user.home}從何而來?
如從前所示user.home應該是一個靜態變量,嘗試打印:
System.out.println(System.getProperty("user.home"));
//打印出:C:\Users\74472 驗證猜測成功
複製代碼
變量 | 含義 |
---|---|
java.version | Java 運行時環境版本 |
java.vendor | Java 運行時環境供應商 |
java.vendor.url | Java 供應商的 URL |
java.home | Java 安裝目錄 |
java.vm.specification.version | Java 虛擬機規範版本 |
java.vm.specification.vendor | Java 虛擬機規範供應商 |
java.vm.specification.name | Java 虛擬機規範名稱 |
java.vm.version | Java 虛擬機實現版本 |
java.vm.vendor | Java 虛擬機實現供應商 |
java.vm.name | Java 虛擬機實現名稱 |
java.specification.version | Java 運行時環境規範版本 |
java.specification.vendor | Java 運行時環境規範供應商 |
java.specification.name | Java 運行時環境規範名稱 |
java.class.version | Java 類格式版本號 |
java.class.path | Java 類路徑 |
java.library.path | 加載庫時搜索的路徑列表 |
java.io.tmpdir | 默認的臨時文件路徑 |
java.compiler | 要使用的 JIT 編譯器的名稱 |
java.ext.dirs | 一個或多個擴展目錄的路徑 |
os.name | 操做系統的名稱 |
os.arch | 操做系統的架構 |
os.version | 操做系統的版本 |
file.separator | 文件分隔符(在 UNIX 系統中是「/」) |
path.separator | 路徑分隔符(在 UNIX 系統中是「:」) |
line.separator | 行分隔符(在 UNIX 系統中是「/n」) |
user.name | 用戶的帳戶名稱 |
user.home | 用戶的主目錄 |
user.dir | 用戶的當前工做目錄 |
Spring-Boot的項目運行起來仍是比較簡單的🤪。頁面也很美觀👍
Spring-boot的項目一般都是從Controller讀起,發現一個共同的特色,就是代碼都是相似這樣一個結構:
private final PostService postService;
private final OptionService optionService;
... .... // 其餘的Service
private final ThemeService themeService;
public ContentIndexController(PostService postService, OptionService optionService, ThemeService themeService) {
this.postService = postService;
this.optionService = optionService;
... .... // 其餘的Service
this.themeService = themeService;
}
@GetMapping
public String index(Model model) {
return this.index(model, 1, Sort.by(DESC, "topPriority").and(Sort.by(DESC, "createTime")));
}
@GetMapping(value = "page/{page}")
public String index(Model model, @PathVariable(value = "page") Integer page, @SortDefault.SortDefaults({ @SortDefault(sort = "topPriority", direction = DESC), @SortDefault(sort = "createTime", direction = DESC) }) Sort sort) {
...//省略
}
複製代碼
學習收穫一:使用構造器注入須要用到的Service
學習收穫二:使用多態處理請求
真正起做用的是後者,前者只是爲用戶添加了參數後調用後者。
return this.index(model, 1, Sort.by(DESC, "topPriority").and(Sort.by(DESC, "createTime")));
複製代碼
學習收穫三:RESTful的api設計