[Java-Kit] Web Framework — Spring Boot
閱讀程度 : ★★★☆☆
適合族群 : 學習架站的初學者/開發者、Web框架趨勢、軟體架構模式(MVC)
※注意事項 — 前言
1. 筆者習慣稱 Spring Boot 為 SpBoot,SpBoot 也代表 超級(Super) Web 開發框架 ( Context(任務管理器)工具管理、Restful API(微服務)、內建Server,可以參考 使用簡介 2、3、4 )
2. 筆者經驗: Java 採用 MVC 架構,Golang 採用 三層式開發(PBD-L) 架構。(SpBoot 為 Java框架,應屬 MVC架構 較為適合; Gin 為 Golang 框架,應屬 PBD-L架構 較為適合。SpBoot 適合中小(偏小)型系統(單一功能); Gin 適合大中小型系統(產品))
3. 網路系統性介紹 SpBoot 資料甚少,因此筆者將 SpBoot 框架 (專案簡介、專案結構、SpBoot核心技術Annotations) 系統性依次介紹並方便讀者閱讀
● 使用簡介
- Spring Boot (SpBoot) 由 Spring、Stuts、Hibernete 構成 Java 微服務與 Web應用程式開發套件
- Spring (全端應用程式框架和控制反轉容器(IoC容器)框架)
- Stuts (MVC框架)
- Hibernete (Java — ORM套件)
1–1. SpBoot 套件意義
- Spring 採用 Stuts MVC
- Boot 簡化 Spring 基礎配置 (包含 ORM 套件)
- Spring Boot 採用 Spring MVC
2. SpBoot 使用 Java 的 Annotation(標註)特性 降低 基礎配置 對 XML 需求。Annotation(標註)特性為一種元數據形式(數據的數據),元數據(照片、文件、音頻、標題、標籤、裝置等)提供日期、來源、收集、轉換等方法幫助 Programming Language 的上下文(Context)工具管理程式的任務行程(EX: 中斷處理)。所以 SpBoot 達成 DI(依賴注入) 實現 IoC(控制反轉) 機制。
3. SpBoot 透過 Annotation 實現基於 Restful API 的微服務(微服務: 透過URI(標識某一網際網路資源名稱的字串)使用單一功能服務) 與實現自動配置路徑(Bean、類別、套件),以此簡化對 XML 需求。
4. SpBoot 擁有 內建Server (Tomcat、Jetty等)。Tomcat 屬於 Apache 基金會開發 Servlet 的 Web容器,Web容器 為 Web Server 的 Agency,負責管理HTTP協定、Servlet 物件的生命週期、安全管理 等。Tomcat 實現對Servlet和 JavaServer Page(JSP)的支援。
※ 注意事項
1. DI(依賴注入): OOP(物件導向程式)中,物件依賴其他物件完成實體化
2. SpBoot 學習與開發過程,開發者容易逐漸脫離物件導向、結構導向思維訓練。(因為 SpBoot 加入太多關於套件的開發約束,開發者需要另外學習其他程式語言沒有的意義)
3. 微服務: 輕量化業務邏輯層、資料存取層節點的溝通訊息機制。透過業務邏輯層與資料存取層 解構 Restful API,目的為擴展與簡化設計服務
4. 輕量: 訊息處理設計,系統節點的溝通過程為較容易設計與擴展
● 開發 — 1 (專案架構)
筆者透過 專案架構 介紹 SpBoot 開發 Web應用程式。
- Stuts (MVC框架)
- src/main/java: 撰寫 MC 程式
- src/main/resources: 撰寫 V 程式
- src/test/java: 撰寫單元測試(一個功能)、整合測試(一個完整連線)
2. Annotation (標註)
- pom.xml
■ 檔案目錄 — src/main/java
此目錄的通常分類習慣。(開發者可以依照所需而分類)
- 應用主類/啟動類(創建時已有): Application.java (處理框架配置掃描、減少額外撰寫配置加載) (EX: DemoApplication.java (專案名+Application))
- controller: Web層 (頁面調度、管理。處理 http協定、接收請求(Request)與響應(Response)) (圖中 HelloWorld.java 為controller層,可以放置在啟動層)
- domain(又稱為 Repository): 實體層 (處理資料庫儲取的資料(持久層(JPA,SpBoot又稱為repository)、資料訪問對象(DAO)、資料傳輸對象(DTO))、輔助業務邏輯的協助層(POJO))
- service: 邏輯層 (處理業務邏輯,包含邏輯介面、邏輯實作)
- utils: 共用工具層 (開發時,團隊、個人經常會使用到的類class(EX: 基礎設定類別、業務適配器 (Business Adapter)))
※ 注意事項
★ 0. controller、domain、service、utils 資料夾需要與 應用主類/啟動類 建立在同一層
★ 0–1. Web層應有一個跳轉路徑類別並且內部屬性應為常數(constant),此類別可以快速 設定路徑 與 控制
1. JPA(Java Persistence API): 它為一個標準規範 (介面API) 實現 ORM (object-relational mapping) 並且透過 Annotation (@Entity、@Table、@Column等)、XML描述物件的映射關係,最後將執行期的物件持久化至資料庫。JPA通稱持久層。JPA類別實現讀取某資料庫的某資料表的指定資料。
2. DAO(Data Access Object): 它為一個資料庫的抽象介面並且呼叫持久層。目的為無須暴露資料庫細節並支援單一功能原則(每個類都應該有一個單一的功能,並且封裝此功能)。DAO類別實現某一功能(EX: 訂餐),功能可能需要讀取多個資料庫、資料表取得功能需要的資料。
3. DTO(Data Transfer Object): 它為一個Web服務的傳輸物件並且不包含業務邏輯、只包含可序列化、反序列化邏輯。目的為重新封裝傳輸資料並降低服務之間的通信成本,所以通常DTO資訊內容較少。(EX: 成本是 Client 和 Server 之間的來回通信時間)
4. POJO(Plain old Java object): 它為一個單純只有私有屬性、公開方法(setter、getter method) 的 Java物件。其他物件(Object) 都基於 POJO 開始延伸。(最初 POJO 表示不遵循任何主要 Java的對象模型、框架)。筆者偏向放置在 domain 資料夾 (也可以放在 utils)。
5. POJO 與 Bean
- Bean 目的: 它為一個單純封裝 Java 存取類別私有屬性的對象,它為一種獨立對象並且它不與 其他Bean 的屬性、功能交錯。此對象可以為許多 JPA、DAO、DTO、POJO 提供一個基礎序列化對象。(Bean 為 特殊的 POJO 類別)
- POJO 目的: 它為一個封裝 Java 業務邏輯 的對象,它可以自身為Bean或者成為Bean收集體 (功能複合體,它可以收集一至多個Bean,甚至也收集POJO)。例如對象可以為 JPA、DAO 提供一個資料表實體。(※它主要功能為序列化(實現Serializable interface (可以不實現)),因為 Java 的 POJO 關係,所以使 SpBoot 一些標註擁有 @Bean 輔助對象序列化)
- 所有 Java Bean 都為 POJO,但是不是所有 POJO 都為 Java Bean。因為 POJO 可以擁有比 Bean 更多功能
- POJO 只能提供無參數建構子 並 只能由無參數建構子、getter、setter 訪問私有屬性
- POJO 與 Bean 有共通性: 可讀性、可重用性
6. 功能層級順序
- 資料庫: DAO > JPA
- Web 溝通: DTO
- 封裝能力: POJO(Bean收集體) > Bean
■ 檔案目錄 — src/main/resources
此目錄管理專案的前端網頁內容與表現格式、基礎配置。
- static: SpBoot 存放網頁的內容與資源 (Javascript, css, image等)
- templates(模板引擎): SpBoot 構建網頁的表現格式 (EX: Thymeleaf、FreeMarker、Velocity、Groovy、Mustache) (SpBoot 避免使用 Jsp)
- application.properties: SpBoot 設定專案的初始化基礎配置,SpBoot 啟動時自動默認加載主要配置參數/初始化參數文件 (EX: Server Port、資料庫連線資訊)
※ 注意事項
1. 官方推薦 application.yml 取代 application.properties
2. 模板引擎 (templates): HTML5 的 Web模板
推薦選擇這兩個套件。
◆ 1. Thymeleaf (筆者採用)
- 可擴展性較佳 (可加入自定義功能)
- 豐富的網路教學資料
- 學習曲線較低
- 擁有不錯的IDE支持
◆ 2. Freemarker
- 擁有網路教學資料 (較零散)
- 因為語法較乾淨,學習曲線較低
- 擁有不錯的IDE支持
■ 檔案目錄 — src/test/java
此目錄管理專案的測試程式。
※由於此篇主要講解 SpBoot專案架構 與 SpBoot Annotation,未來或許會寫一篇介紹 SpBoot 如何測試程式。
■ pom.xml (專案依賴)
為了方便開發者對照,底下為 JDK1.7版 SpBoot 的 完整 pom.xml。
◆ 筆者載入初始依賴套件
- spring-boot-starter-thymeleaf: HTML模板
- spring-boot-starter-web: RESTful 應用、內建Server(EX: Tomcat)、websocket與logging服務(spring-boot-starter-tomcat所有)
- spring-boot-devtools: 自動配置(EX:默認屬性值)、自動重啟、嵌入式 LiveReload 服務器(資源更改觸發瀏覽器刷新)、全域設定(spring-boot-devtools.properties)、HTTP遠程調試
- spring-boot-starter-test: 單元測試 (mock功能)
- lombok: 省略常用方法的語法糖 (EX: getter、setter)
<?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>3.1.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<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>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
◆ pom.xml — 介紹
- pom 全名為 Project Object Model (專案物件模型),它主要管理專案的任務依賴(俗稱:專案依賴)、plugin、配置。
- pom 主要為 Maven (自動化建構工具) 的必要文件。(Maven 為 Apache 專案管理 與 自動建構工具)
- SpBoot 透過 pom.xml 與 Annotation 簡化基礎配置並降低對 XML 需求。
◆ pom.xml — Tag (又稱 Task 任務) 講解
- Maven 工具
- modelVersion: Maven — 版本
2. Project 專案
- parent: 專案 — 父專案
- version: 專案 — 版本
- name: 專案 — 名稱
- description: 專案 — 描述 (細步描述 package 意義)
- properties: 專案 — 其他參數設定 (EX: JDK版本)
- dependencies: 專案 — 依賴套件
- build: 專案 — 建構方式
3. Package 套件
- groupId: 專案 package — 所屬群體名稱
- artifactId: 專案 package — 識別名 alias (初步描述 package 意義)
● 開發 — 2 (Annotations)
筆者分類 Annotation(標註) 功能並介紹 SpBoot 核心技術。
SpBoot 使用 Annotation(標註) 管理常見Web應用,比如: 路徑配置、物件的生命週期、Context任務管理器(EX: 任務中斷處理、AOP等)、MVC框架設計、物件導向依賴設計(DI、IoC)。
※SpBoot 透過 Annotations (大多為介面(介面與抽象有關)) 使 變數、DI 達成全域溝通,如同 Golang 的 Channel。
■ 配置
◆ @Configuration
- 標註對象: 類別
- 特性 (※底下標註為當下介紹的標註 (EX: @Configuration),後面依此類推)
- 標註幫助 SpBoot 設定 基礎配置 (EX: 基礎類別、Bean、方法)
- 標註為 Spring 的標註
- 標註通常應用 Context 管理、IoC容器 (EX: Service、其他元件)
- 標註對象可以包含一個 or 多個 Bean
- 標註對象不能為實例對象
- 標註對象根據擁有 field、Method 區分不同 Configuration 意義
◆ @ComponentScan
- 標註對象: 類別
- 特性
- 標註掃描指定套件(package) 擁有元件、Bean、Annotations 並加載至 SpBoot 的 IoC容器。
- 標註掃描 特定package 以至於加快掃描Bean速度。(SpBoot 預設會掃描 @Compoment、@Repository、@Service、@Controller、@Configuration,所以 SpBoot 加載較慢)
◆ @EnableAutoConfiguration
- 標註對象: 類別
- 特性
- 標註對象自動配置符合條件的 Bean 並加載至 SpBoot 的 IoC容器
◆ @SpringBootConfiguration
- 標註對象: 類別
- 特性
- 標註為 SpBoot 的標註
- 標註繼承 @Configuration 並將其擁有 Bean 注入 SpBoot 的 IoC 容器
- 標註主要應用 Context 管理
- 標註簡化 SpBoot 不同基礎配置功能(較全面) 並 可以自定義、修改應用程序的屬性
◆ @SpringBootApplication (常用)
- 標註對象: 類別
- 特性
- 包含 @ComponentScan、@EnableAutoConfiguration、@SpringBootConfiguration
■ MVC (MC 管理)
◆ @Component (元標註: 所有標註的基礎)
- 標註對象: 類別
- 特性
- 標註為其它標註的元標註,標註自動偵測自定義 Bean 並實例化 Bean,再收集至 SpBoot 的 IoC容器。目的為開發者可以隨時注入與管理 Bean (EX: 生命週期(初始化、創建、銷毀))
- 標註對象可以為 @Service、@Controller
- 因為元標註的功能較少,開發者偏向使用元標註子類(擁有較多功能)
◆ @Repository
- 標註對象: 類別
- 特性
- 標註對象視為持久層 (又稱 數據訪問層,EX: 資料庫)
- SpBoot 自動創建 標註對象 並添加至 Context
◆ @Service
- 標註對象: 類別
- 特性
- 標註對象視為邏輯層 (商業邏輯功能開發)
◆ @Bean (常用)
- 標註對象: 方法
- 特性
- 標註在 @Configuration類別 中才能使用
- 標註對象被實例化一次並收集至 SpBoot 的 IoC容器,標註對象獲得類似 Java Bean特性(序列化) 並使用 Context 訪問此標註對象
- [★] 標註主要使用情境: 標註對象採取回傳一個新物件 (主要功能)
■ 頁面轉換/跳轉
◆ @Controller
- 標註對象: 類別
- 特性
- 標註繼承 @Component 並使 標註對象 成為 Controller 層
- 標註擁有 View(視圖)解析器(輔助渲染結果) 並且可以將資料返回 指定/相對應頁面 Web Page (e.g. Jsp) (View解析器: 解析 HTML畫面,它偏向為模板(Template))
無加入 @ResponseBody
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class SampleController {
@RequestMapping("/")
public String home() {
return "index.html"; // 指定頁面: localhost:/8080/inedx.html
}
}
加入 @ResponseBody (@Controller + @ResponseBody = @RestController)
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SampleController {
@RequestMapping("/")
@ResponseBody
public String home() {
return "Hello World"; // 無指定頁面 localhost:8080/
}
}
◆ @RestController (常用)
- 標註對象: 類別
- 特性
- 標註主要使用情境: RESTful API (Spring 4 加入)
- 標註包含 @Controller、@ResponseBody 並且 標註可以返回 JSON格式 至 client
- 標註被使用時,頁面單純顯示 JSON格式
- 標註無法指定回傳頁面
◆ @ResponseBody ( Java對象 -> JSON、XML 格式) (常用)
- 標註對象: 方法
- 特性
- 標註主要使用情境: 標註用於 @Controller方法 並且透過 異步通信(EX: Ajax) 獲取數據
- 標註將 Java對象 轉成 JSON格式數據 並 寫入 HTTP response
- 標註使用時,@Controller 不會使用 View解析器。標註直接將數據寫進輸出串流stream (等同直接透過 response 輸出 JSON、XML格式,HTML 頁面不會進行渲染)
- 標註不使用時,頁面根據相對應 URL路徑 跳轉
◆ @RequestMapping (常用)
- 標註對象: 類別、方法
- 特性
- 標註主要使用情境: RESTful API
- 開發者一般將 長Mapping 用於類別,短Mapping 用於方法
- 標註可被替換成短Mapping (Spring 4.3 引入)
- 標註設定 HTTP Request 指定 URL 映射至 MVC、@RestController 方法
- 標註對象為類別,此類別 所有Response 將 標註指定 URL 視為 父路徑
3. 範例
@RequestMapping(value = "/get" , method = RequestMethod.GET) (筆者習慣稱為長Mapping)
=> @GetMapping(value= "/get") (筆者習慣稱為短Mapping)
@RequestMapping(value = "/post" , method = RequestMethod.POST)
=> @PostMapping(value="/post")
@RequestMapping(value = "/put" , method = RequestMethod.PUT)
=> @PutMapping(value="/put")
@RequestMapping(value = "/delete" , method = RequestMethod.DELETE)
=> @DeleteMapping(value="/delete")
■ 網址請求
◆ @PathVariable
- 標註對象: 方法參數
- 特性
- 標註主要使用情境: 取得URL的變數值
- 標註可搭配 @RequestMapping 並 存取指定資料
- 標註對象的變數值與標註所屬方法使用的URL相同,標註可省略標註的變數值。如果不同,則不可省略
◆ @RequestParam (常用)
- 標註對象: 方法參數
- 特性
- 標註主要使用情境: 取得URL的參數值(RESTful 的 GET、POST)
- 標註可搭配 @RequestMapping 並 存取指定資料
- 標註可搭配 Postman 並 進行驗證URL
範例1. 簡單取值
@GetMapping("/api/thing")
public String getThing(@RequestParam String id){
return "ID: " + id;
}
curl http://localhost:8080/api/thing?id=abc
ID: abc
範例2. 指定參數名稱
@PostMapping("api/foods")
public String getFood(@RequestParam("name="id") String foodId, @ReuqestParam String name){
return "ID: " + foodId + "Name: " + name;
}
範例3. 請求參數可能沒有收到 (使用required 設定,可避免錯誤)
@GetMapping("/api/foods")
public String getFood(@RquestParam("name=id" required=false) String foodId){
return "ID: " + foodId + "foodName: " + name;
}
http://localhost:8080/api/foods?id=abc
=> ID: abc
http://localhost:8080/api/foods
=> ID: null
範例4: 設定默認預設值
@GetMapping("/api/foods")
public String getFoods(@RequestParam(defaultvalue="test") String id){
return "ID: " + id;
}
http://localhost:8080/api/foods
=> ID: test
http://localhost:8080/api/foods?id=abc
=> ID: abc
範例5: 映射所有參數
@PostMapping("/api/foods")
public String updateFoods(@RequestParam Map<String, String> allParams){
return "Parameters are " + allParams.entrySet();
}
curl -X POST -F 'name=abc' -F 'id=123' http://localhost:8080/api/foos
Parameters are {[name=abc], [id=123]}
範例6: 映射多值參數
@GetMapping("/api/foods")
public String getFood(@RequestParam List<String> id){
return "IDs are " + id;
}
http://localhost:8080/api/foods?id=1,2,3
=> IDs are [1,2,3]
https://localhost:8080/api/foods?id=1&id=2
=> IDs are [1,2]
◆ @Requestbody ( JSON格式 -> Java對象 ) (常用)
- 標註對象: 方法參數
- 特性
- 標註主要使用情境: 請求的 JSON格式 並將它轉換成 Java對象 (通常用於 POST)
- 標註最多接收一個 Request,但是不限定其Request擁有的參數數量。@RequestParam可以接收多個 Request
- 標註 與 @RequestParam 搭配使用時,標註接收 Request 數據,@RequestParam 接收 key-value 的參數
※如果參數放在請求,application/json傳入後台,後台透過 @Requestbody 接收; 如果參數不放在請求,後台透過 @RequestParam 接收
◆ @RequestAttribute
- 標註對象: 方法參數
- 特性
- 標註主要使用情境 — 1: 取得 Filter(過濾器)、Interceptor(攔截器) 建立預先存在的Request屬性 (通常為 已經實例化父類別的屬性)
- 標註主要使用情境 — 2: 用於 Server 訪問一段時間並在同一HTTP Request 的對象
- 標註不適用搭配 Postman、curl (當下傳遞新 Request)
■ 提供實例化物件 — @ModelAttribute (跟 @Bean 思維有些相像)
- 標註對象: 方法、方法參數
- 特性
- 標註主要使用情境: 在執行類別其他方法、方法參數之前,標註對象提前執行
- 標註在方法,此方法比其它方法先執行 並且 方法結果 存放至 Model
- 標註在方法,標註經常用於公共屬性、資料 (EX: 下拉列表的預設狀態、HTML表單渲染的命令對象)
- 標註在方法參數,標註可以接收任何參數類型 (EX: Model、Map、String、一般類別等)
- 標註在方法參數,開發者可以直接從方法參數取值 (因為標註實例化方法參數並加入 Model,所以 Model 可以找到此方法參數)
- 標註沒有使用時,開發者可能取不到方法參數
- 標註在方法參數,其作法類似 Golang 的 Channel 傳過來已實例化對象
※ 注意事項
先實例化對象,使SpBoot 的 Model 擁有此對象的物件。之後的方法可以直接拿取此對象的物件。
■ Spring 中心思想 ( DI(依賴注入) 實現 IoC(控制反轉) )
◆ @Autowired (Spring 2.5 提供) (常用)
- 標註對象: 屬性(Field)、方法(Method — setter)、建構子(Constructor)、方法參數
- 特性
- 標註主要使用情境: 對標註對象進行 注入(injection) 並 自動裝配內容
- 標註無法判斷使用哪個 Bean 時,SpBoot 透過 @Qualifier 選擇相對應的 Bean
- 標註無法找到適當 Bean 時,標註屬性 required = true,SpBoot 執行時可能會出現 NoSuchBeanDefinitionException。required = false,SpBoot 執行時不會顯示 Exception (預設為 true)
- 標註對象為屬性(Field): 可省略使用 UserDAO setter 方法取得過程,直接取得 setter 的值 (標註類似簡化序列化做法) (常用)
- 標註對象為方法(Method — setter): 自動找尋匹配方法參數 Bean 注入至標註對象中的 Bean
- 標註對象為建構子(Constructor): 直接將建構子注入 (較少看過)
■ Others (輔助開發 Bean、Logger、AOP)
◆ @Before
- 標註對象: 方法
- 特性
- 標註通常用於 AOP(切面導向程式設計) 的流程控管
- 標註通常在 PointCut 之前處理
◆ @Data
- 標註對象: 類別
- 特性
- 標註對象可以生成讀寫方法、equals、hashCode()、toString() 並且標註對象可以成為 POJO (因為自動生成 POJO 樣板)
◆ @Getter、@Setter
- 標註對象: 類別
- 特性
- 標註對象自動為標註對象的屬性生成讀寫方法
◆ @toString
- 標註對象: 類別
- 特性
- 標註對象自動生成 toString() 方法
◆ @Slf4j (Simple Logging Facade for Java)
- 標註對象: 類別
- 特性
- Simple Logging Facade for Java 為日誌框架(java.util.logging、logback、log4j)的應用介面
- 標註對象自動生成一個 log4j型態 的 log屬性的日誌對象
- 標註對象提供 TRACE, DEBUG, INFO, WARN, ERROR 五種紀錄等級
◆ @Log4j (Apache Log4j)
- 標註對象: 類別
- 特性
- Apache Log4j 為一個非常古老的日誌框架並且受到歡迎
- 標註對象自動生成一個 log4j型態 的 log屬性的日誌對象
- 標註對象提供 TRACE, DEBUG, INFO, WARN, ERROR 及 FATAL 六種紀錄等級
◆ @Value
- 標註對象: 類別屬性
- 特性
- 標註對象將外部資源注入,注入方法分成兩種不通過配置文件、通過配置文件(文件資源、URL)
- 注入對象可以為字串、操作系統屬性、表達式結果、其他Bean屬性、文件資源、URL
範例: Spring Boot系列四 Spring @Value 属性注入使用总结一
// 注入 - 字串
@value("normal")
private String normal;
// 注入 - 操作系統屬性
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName;
// 注入 - 表達式
@Value("#{T(java.lang.Math).random() * 1000.0}")
private double randNum;
// 注入 - 其他屬性
@Value("#{BeanInj.another}")
private String fromAnotherBean;
// 注入 - 文件資源
@Value("classpath:com/hry/spring/configInject/config.txt")
private Resource resourceFile;
// 注入 - URL
@Value("http://www.baidu.com")
private Resource testUrl;
@Component
public class BeanInj{
@Value("其他Bean屬性")
private String another;
}
// 文件: com/hry/spring/configInject/config.txt
test configuration file
◆ @Required (Spring 5.1 版已經棄用)
- 標註對象: 類別方法
- 特性
- 標註對象為 setter,Bean屬性必須設定在 XML (e.g. Beans.xml(筆者定義)),否則會拋出 BeanInitializationException
- Spring 5.1 版已經棄用支援使用建構子注入 或者 自訂 InitializingBean 實作
範例: Spring @Required Annotation
- Bean
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Required;
public class Student {
private Integer age;
private String name;
@Required
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
- Main
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Student student = (Student) context.getBean("student");
System.out.println("Name : " + student.getName() );
System.out.println("Age : " + student.getAge() );
}
}
// 輸出結果
Name : Zara
Age : 11
- Beans.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"
xmlns:context = "http://www.springframework.org/schema/context"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<!-- Definition for student bean -->
<bean id = "student" class = "com.tutorialspoint.Student">
<property name = "name" value = "Zara" />
<property name = "age" value = "11"/>
</bean>
</beans>
■ 資料庫類
◆ @Entity
- 標註對象: 類別、枚舉的介面 (e.g. Serializable)
- 特性
- 標註對象宣告為持久層,並指定標註對象為一個實體。目的為輔助業務服務 (※實體為資料庫的表,實體的每個實例為表中的一行)
- 標註對象為儲存至資料庫的POJO
- Spring容器透過實體管理關聯式資料庫的持久性並自動儲存資料庫資料
- 使用 JPA 時,建議使用標註綁定類別並建立一個主鍵欄位 @id
- 開發者可以使用實體表示細顆粒度的持久對象 並且建立單一業務流程的業務實體或者為多個操作進行建模
◆ @Table
- 標註對象: 類別
- 特性
- 標註對象被指定為資料庫的資料表,開發者可以自由選擇使用此標註,如果不使用,則需要使用 @Entity 表示資料表名稱。
- 開發者不使用 @Table,Hibernate 預設會使用 @Entity 名稱視為表名
範例
// 第一種 (允許編寫 HQL 或 JPQL 時存取與實體同名的表。)
@Entity(name = "someThing") => this name will be used to name the Entity
@Table(name = "someThing") => this name will be used to name a table in DB
// 第二種 (編寫查詢需要使用 @Entity 設定的名稱 並且 應用 @Table 名稱用於資料表)
// HQL 中,someThing 將引用資料表 otherThing
@Entity(name = "someThing")
@Table(name = "otherThing")
// 第三種 (一般常用),可以使用 SQL、HQL、JPQL
@Entity
@Table(name="someThing")
// 第四種,可以使用 SQL
@Entity(name="")
◆ @Id
- 標註對象: 類別屬性
- 特性
- 標註對象被指定為實體的主鍵。
◆ @GeneratedValue
- 標註對象: 類別屬性
- 特性
- 標註時常與 @Id 搭配使用
- 標註對象可以指定主鍵產生策略。(TABLE、SEQUENCE、IDENTITY、AUTO)
- TABLE: 使用一個特定的資料庫的資料表保存主鍵
- SEQUENCE: 根據底層資料庫的序列生成主鍵 (資料庫需要支持序列)
- IDENTITY: 主鍵由資料庫自動生成 (主要為自動增長型)
- AUTO: 主鍵由程式開發者控制 (GeneratedValue 的預設)
// IDENTITY
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
// AUTO
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
◆ @Column
- 標註對象: 類別屬性
- 特性
- 標註對象被指定為資料表的欄位並且標註的Name屬性為表的列名稱。
◆ 事務(交易) REQUIRES_NEW & REQUIRED
- 標註對象: 類別方法
- 特性
- REQUIRES_NEW: 創建一個新事務(交易),如果當前事務存在,則會掛起當前事務。內部不受外層調用者影響,但會影響外層的事務。
- REQUIRED: 支持當前事務,如果不存在,則創建一個新事務。內部受外層調用者影響,也會影響外層的事務。
[實務上]
- REQUIRES_NEW: 少數情境使用。其中一個事務與其他事務無關。假設其他事務異常,此事務不會被影響與回滾
- REQUIRED: 多數情境使用。一系列事務保證全部成功,全部失敗。假設其他事務異常,此事務也會被影響與回滾
3. 參考
■ Java 與 關聯式資料庫 — 操作關係
- SQL(Structured Query Language): 透過 SQL 提供關聯式資料庫(實體)操作分類(DML、DDL、DCL、TCL、DQL)並且管理關聯式資料庫的儲取與查詢。
- HQL(Hibernate Query Language): 透過 HQL 提供 Hibernate (關聯式資料庫的物件導向式ORM方案) 模擬 SQL 並且處理對象為 JPA實體、實體屬性。 (※ HQL: 物件關係查詢語言)
- JPQL (Java Persistence Query Language): 透過 JPQL 提供 Java 模擬 SQL 並且 JPQL 基於 HQL 創造,不直接影響關聯資料庫。
- Spring Data JPA — @Query: 可以使用 JPQL,JPA默認使用 Hibernate (HQL)
◆ 三者差異
- HQL 允許 select 將 table 替換成 類別屬性、類別名稱
- JPQL 允許 select 將 table 替換成 類別屬性、類別名稱並支持 inner join、outer join 與 支持刪、查、改操作
◆ JPA & Spring Data JPA
- JPA(Java Persistence API): 它為 Java 提供物件與關聯式資料庫之間持久化、讀取和管理資料的標準。其中定義一組概念與API,使開發者能處理應用程式的關聯式資料。
- Spring Data JPA: 它為 Spring 採用 JPA概念實作而成的串接資料庫樣板。它優化使用 JPA 原則最大程度減少開發程式碼的數量。
■ Spring — byName、byType
開發者可以自訂 xml 為 Beans.xml,會比較好分類。
- byName: 找尋 xml 的 bean 節點 <bean id="">,如果找不到會丟出 NullPointerException。
- byType: 找尋 xml 的 bean 節點 <bean class="">,如果找不到會丟出 NullPointerException。bean 透過 <bean autowire="byType"> 使用。開發者需要保證Spring容器中同一類型的對象只能唯一。
- @Quailfier: 輔助 @Autowired (根據 byName 自動裝配),標註不能單純使用。標註對象為類別屬性。
※Spring 預設會找尋 byType (e.g. @Autowired),其中應用 <bean class=""> 自動裝配。
// Cat 類別
public class Cat{
public void say(){
System.out.println("This is Cat class");
}
}
// Dog 類別
public class Dog{
public void say(){
System.out.println("This is Dog class");
}
}
// People 類別
public class People{
@Autowired(required=false)
@Qualifier(value="cat2")
private Cat cat;
@Autowired(required=false)
@Qualifier(value="dog2")
private Dog dog;
private String name;
public Cat getCat(){
var tmpCat = new Cat();
return tmpCat;
}
public Dog getDog(){
var tmpDog = new Dog();
return tmpDog;
}
public String getName(){
return this.name;
}
}
// 輸出結果
this is Cat class
this is Dog class
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:context = "http://www.springframework.org/schema/context"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/> <!--開啟屬性標註支持-->
<!-- Definition for student bean -->
<bean id = "cat" class="com.hello.pojo.Cat"/>
<bean id = "cat2" class="com.hello.pojo.Cat"/>
<bean id = "dog" class="com.hello.pojo.Dog"/>
<bean id = "dog2" class="com.hello.pojo.Dog"/>
<!--Bean & Bean屬性-->
<bean id = "people" class="com.hello.pojo.People" autowire="byName">
<property name="cat" ref="cat"/>
<porperty name="dog" ref="dog"/>
<property name="name" value="wsh"/>
</bean>
</beans>
◆ @Resource
- 標註對象: 類別屬性、類別方法
- 特性
- 標註可以透過 byName、byType 注入,使用順序: byName > byType。如果找不到 byName,才會使用 byType。
- 標註功能如同 @Autowired,@Autowired 使用 byType 注入。
- 標註 與 @Autowired 可以用於 setter 方法
範例: Spring中 javax.annotation.Resource注解用法
// 屬性 - 字串
@Resource(name="userDao")
private UserDao userDao;
// 方法 - setter
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
■ Spring Boot — 測試 (注意事項)
- 單元測試: 在 Junit測試時,透過 @RunWith(SpringRunner.class) 標註啟用 spring boot 功能@Autowire,例如@MockBean等。一般測試對象為 Service(業務邏輯)
- 整合測試: 在 Junit測試時,透過 @SpringBootTest 標註載入完整的應用程式 Context(任務管理器) 並進行端到端的整合測試。一般測試對象為 DAO(資料持久層 (與資料庫串接))
- @Test 標註對象類別方法,目的為開發者撰寫測試案例(test case)。
■ Spring Boot — AOP (注意事項)
- AOP (特性導向程式設計): 從業務流程的某步驟分析多個業務邏輯的觀點,觀點分離業務主體的核心關注點,藉此提高程式碼的模組化。
- 範例: 對所有以set*開頭的方法添加Server紀錄檔,以泛型形式記錄。目的為降低程式碼的核心功能負擔(e.g. 紀錄log功能不是核心功能),同時不降低業務邏輯的可讀性。 (※紀錄log功能融入至業務流程)
● 結論/心得
- SpBoot 適合建立微服務(單一服務),但是它不適合中大型專案。
- SpBoot 核心 Annotation 為一種全域機制,它是一個非常先進技術。如果開發者有結構導向(EX: Golang)開發經驗,開發者可以知道 Annotation 完成 Golang 的 Channel 曾經想做的開發方向 (全域 Channel ),不過 全域 Channel可能難以系統化功能設計。
- SpBoot 透過 Annotation 完成 DI 實現 IoC,如同 Golang 開發的 Taskfile (自動化建構工具),其目的為開發者需要撰寫 task內容 (Java Code) 並使用 序列化 完成任務(task),其過程宛如將 task內容 注入至 task,然後呼叫此任務task。
- SpBoot 核心技術 Annotation 創造許多有趣詞彙提供開發者在其他語言稱呼相對應意義。
- ▲ 筆者大致已完成此篇 SpBoot 介紹,介紹還須打磨其內容(格式化)並加入圖片、程式碼幫助開發者了解其意義 (※之後補充)
● 參考資料 — 1 (J.J.’s Blogs)
● 參考資料 — 2 (cailiwu)
● 參考資料 — 3 (模板)
● 參考資料 — 4 (Annotations (標註、註解))
1. [極推薦] 2023 年最常用的 10 個 Spring Boot 註解
2. javatpoint — Spring Boot Annotations
3. stackOverflow — 如何使用postman或feign客戶端在Spring boot中設置@RequestAttribute的值
5. [Day 11] — @GetMapping 和 @RequestMapping 的比較及使用
6. Spring Boot教程(9) — Model的用法
7. [推薦] [SpringMVC]@ModelAttribute 2種用法與解釋( @ModelAttribute — Used on Method and Parameter )
8. [推薦]【Spring】@ModelAttribute三种使用场景
10. [@ComponentScan 範例] Spring系列(三):@ComponentScan注解用法介绍
11. [@ComponentScan 範例] Spring Boot注解之@ComponentScan用法和实现原理
12. [@ComponentScan 介紹] Spring 之 @Component 和 @ComponentScan 注解用法介绍和注意事项
13. [@ComponentScan 範例] Spring注解 — — 使用@ComponentScan自动扫描组件
14. [推薦 — DI、IoC] Spring 註解 之 @Autowired
15. [推薦 — @RequestBody] @RequestBody是干嘛的,作用是甚麼?
16. [推薦 — @RequestBody & @RequestParam 比較] @RequestBody的使用
17. [推薦 — @Bean 範例] 就是要让你彻底学会 @Bean 注解
18. Spring系列第十九講@Configuration和@Bean註解詳解
19. [推薦 — Java 基礎標註 Annotations] Day 08 — Spring Boot 常用註釋(上)
20. [推薦 — Beans 範例] Spring 系列之 Bean 注解用法介绍
21. [Component 範例] Spring @Component 註解
22. [大推薦 — @PathVariable 範例] @PathVariable注解的用法和作用(Demo详解)
23. [大推薦 — @RequestAttribute 範例] 从原理层面掌握@RequestAttribute、@SessionAttribute的使用【享学Spring MVC】
24. [大推薦 — SpBoot 回應與接收 JSON] 回應與接收 JSON
25. [推薦 — 注入方式] Springboot中一些註解的作用 (@Autowired、@Inject、@Resource)
26. Spring基于@Configuration的类配置的用法
27. [推薦 — @ModelAttribute 與 HTML 用法] TPIU — Thymeleaf & 資料傳遞
● 參考資料 — 5 (Others (AOP、DataBase、Log))
1. [AOP] spring boot AOP @Before @After 最简单的切面
2. [AOP] wiki — 特性導向程式設計 (將交叉切入關注點與作為業務主體的核心關注點進行分離,以提高程式碼的模組化程度)
4. [推薦 — AOP] [Day 27] 遠征 Kotlin × Spring Boot 介紹 Spring AOP 機制
5. Azure — 什麼是 Java Spring Boot?
8. [推薦 JPA、Hibernate 圖解] [Day 13] — 認識Spring Data JPA, JPA, Hibernate
9. Spring Boot EP 10:透過Spring Data JPA與Hibernate讀取(select)資料庫
11. wiki — 單一功能原則
12. [推薦 — POJO 解釋] 一次搞懂POJO、PO、DTO、VO、BO
13. wiki — Plain old Java object(POJO)
15. wiki — 網頁模板
18. [推薦 — 何謂是 Beans] wiki — JavaBeans
19. [大推薦 — Spring IOC] Spring Boot 零基礎入門學習筆記 — IoC
21. Spring MVC的简单用法
22. [推薦 Spring Boot 如何發布 可執行檔] SpringBoot發佈將靜態資源及設定抽離
23. SpringBoot — 探究Spring Boot應用是如何通過 java -jar 啟動
26. [推薦 SpBoot 返回對象都為 ModelAndView] Spring MVC视图和视图解析器
27. [推薦 — SpBoot 官方 DOC (最良心,雖然不好看)] Web MVC framework
29. [大推薦 SpBoot學習教材] openhome — SpBoot
30. POJO 與 Java Bean
31. 了解 Spring Boot @Autowired 註解
32. caterpillar — 11.1 常數設置與列舉型態
33. springboot使用@data註解,減少不必要程式碼
34. [詳細] Spring Boot系列四 Spring @Value 属性注入使用总结一
36. [不錯] Spring @Required Annotation
● 參考資料 — 5.1 (byName、byType)
1. Spring 註解 javax.annotation.Resource和@Autowired
2. Spring Autowiring byName & byType Example
3. Spring Bean Autowire byName, byType, constructor and default Example