在`Spring`中路由不叫路由,而叫做:`Request Mapping 請求映射`。路由(route)就是數據轉發,而路由在按自己的規則進行數發的,而這個規則在英文中習慣的稱為`map`,我們譯過來叫做`映射`。所以`angular`中的`路由`與`spring`在此的`請求映射`只是說法不同而已,解決的都是數據依照什么規則進行轉發的問題。
>[info] Thinking: 使用路徑參數并獲取參數中的路由;Coding: Angular及Spring中如寫組織代碼來實現該功能。
# 定義參數路由
在路由定義時,`spring`首先找到拉于控制器上的`@RequestMapping`注解,并獲取注解中的值;然后以此值為基礎,再找位于方法中的相關注解,比如:`@GetMapping`、`@PostMapping`等。
我們在前面的小節中,已經使用了如下代碼來定義獲取所有教師列表的路由地址:
```java
@RequestMapping("Teacher") ①
public class TeacherController {
...
@GetMapping ②
@CrossOrigin("*")
public List<Teacher> getAll() {
```
按照上述原則,最終得到的路由值為:`Teacher + ''` = `Teacher`。
# 獲取路徑變量的值
注解和有些語言的函數一樣,是可以設置默認值的,比如如果我們使用`@GetMapping`注解。則表示:全部使用默認值設置該注解的值。當我們使用`@GetMapping("{id}")`表示:使用`"{id}"`來設置`@GetMapping`的默認屬性`name`。`@GetMapping`除默認屬性`name`外,還存在諸如`value`、`path`、`params`等屬性。
在`spring`中通過設置`@GetMapping`注解的默認屬性來設置路徑變量,使用`@PathVariable`注解來獲取綁定后的值。
TeacherController
```java
@GetMapping("{id}") ?
public Teacher getById(@PathVariable Long id) { ?
logger.info(id.toString());
return null;
}
```
* ? 聲明映射路徑變量值為`id`,當請求地址為`Teacher/1`時,符合本條規則。
* ? 獲取綁定的`id`值。
## 測試
啟用系統并使用`REST Client`進行測試。

打開系統控制臺,查看生成的日志:

成功的打印了`id`的值。
## 使用SQL語句獲取
我們將前面學習過的獲取多條教師數據的代碼稍做修改:
```java
/**
* 根據ID獲取數據表中的教師數據并返回,用于查詢某個教師的數據
* 雖然在學習的過程中,我們將方法中的每條語句都加入注釋會有利于我們的理解。
* 但在生產的環境中,我們并不推薦在方法體中加入注釋。
* 我們認為:
* 1 每個方法都應該是足夠短小的。
* 2 每個方法的注釋都是可以在方法頭部說明的。
* 3 在代碼輸寫時,我們更注重的是業務邏輯層面的交流而非coding方法的交流。
* 如果我們認為方法中的代碼的確是需要注釋的(比如一些新的方法、新的思想的引入,我們想其它的成員能夠快速的學習到該技巧)
* 那么應該該代碼段抽離出來,變成一個新的方法,然后在該方法上加入注釋。
* @param id 教師ID
* @return
*/
@GetMapping("{id}")
@CrossOrigin("*") ①
public Teacher getById(@PathVariable Long id) {
Teacher teacher = new Teacher(); ?
RowCallbackHandler rowCallbackHandler = new RowCallbackHandler() { ②
@Override
public void processRow(ResultSet resultSet) throws SQLException {
teacher.setId(resultSet.getLong("id"));
teacher.setName(resultSet.getString("name"));
teacher.setSex(resultSet.getBoolean("sex"));
teacher.setUsername(resultSet.getString("username"));
teacher.setEmail(resultSet.getString("email"));
teacher.setCreateTime(resultSet.getLong("create_time"));
teacher.setUpdateTime(resultSet.getLong("update_time"));
}
};
String query = String.format("select id, name, sex, username, email, create_time, update_time from teacher where id = %d", id); ?
jdbcTemplate.query(query, rowCallbackHandler); ③
return teacher; ?
}
```
* ? 初始化返回數據。
* ? 撰寫查詢語句。`String.format()`為字符串格式化函數,該代碼中使用了`id`的值來替換了字符串中的`%d`。
* ? 返回數據。
> 由于獲取到的數據要么有0條要么有1條,所以該賦值語句要么不執行,如果執行那么只會執行1次。
## 測試
在程序的編寫中我們需要盡量規避一些人為的不穩定地、無法快速重現或是難以共享的因素。而`REST Client`由于是人為地在客戶端內進行輸入點擊,所以它是我們在開發中進行測試選擇的下策。 在`IDEA`中除了`REST Client`以外我們還可以選擇另外一個相對較抽象但卻更符合我們習慣的工作,這就是`HTTP Request`。在`IDEA`中可以輕松的將`REST Client`轉換為`HTTP Request`。

點擊紅色的按鈕便可以發起`http`請求協助我們的完成測試工作。更重要的是該請求是以文件形式存在的,我們可以很方便地重新運行測試或是將自己的測試文件與伙伴們進行分享,或是共同完成某個測試。
由于啟用了`Http Request`,所以本次測試我直接把測試的代碼給大家即可:
```
GET http://localhost:8080/Teacher/1 ?
```
* ? 請求方法為`GET`,請求地址為: `http://localhost:8080/Teacher/1`
重新啟動應用并運行測試代碼,得到的結果如下:
```
GET http://localhost:8080/Teacher/1
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 24 Oct 2019 06:18:39 GMT
{
"id": 1,
"name": "張三",
"sex": true,
"username": "zhangsan",
"email": "zhangsan@mail.com",
"createTime": 1569721598000,
"updateTime": 1569721598000
}
Response code: 200; Time: 31ms; Content length: 135 bytes
```
在返回的結果中,我們看到了想要的教師信息,測試成功。
# 本節作業
將在新增教師測試中使用`REST Client`轉換為`HTTP Request`測試方法,查看轉換后的代碼并嘗試找出使用`HTTP Request`測試的規律。
# 參考文檔
| 名稱 | 鏈接 | 預計學習時長(分) |
| --- | --- | --- |
| 使用JDBC訪問數據庫 | [https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/data-access.html#jdbc-core](https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/data-access.html#jdbc-core) | 15 |
| 使用Spring創建REST服務 | [https://spring.io/guides/tutorials/bookmarks/](https://spring.io/guides/tutorials/bookmarks/) | 15 |
| 請求映射 | [https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#mvc-ann-requestmapping](https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#mvc-ann-requestmapping) | 15 |
| HTTP Request | [https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html) | 15 |
| 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step2.4.2](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step2.4.2) | - |
- 序言
- 第一章:Hello World
- 第一節:Angular準備工作
- 1 Node.js
- 2 npm
- 3 WebStorm
- 第二節:Hello Angular
- 第三節:Spring Boot準備工作
- 1 JDK
- 2 MAVEN
- 3 IDEA
- 第四節:Hello Spring Boot
- 1 Spring Initializr
- 2 Hello Spring Boot!
- 3 maven國內源配置
- 4 package與import
- 第五節:Hello Spring Boot + Angular
- 1 依賴注入【前】
- 2 HttpClient獲取數據【前】
- 3 數據綁定【前】
- 4 回調函數【選學】
- 第二章 教師管理
- 第一節 數據庫初始化
- 第二節 CRUD之R查數據
- 1 原型初始化【前】
- 2 連接數據庫【后】
- 3 使用JDBC讀取數據【后】
- 4 前后臺對接
- 5 ng-if【前】
- 6 日期管道【前】
- 第三節 CRUD之C增數據
- 1 新建組件并映射路由【前】
- 2 模板驅動表單【前】
- 3 httpClient post請求【前】
- 4 保存數據【后】
- 5 組件間調用【前】
- 第四節 CRUD之U改數據
- 1 路由參數【前】
- 2 請求映射【后】
- 3 前后臺對接【前】
- 4 更新數據【前】
- 5 更新某個教師【后】
- 6 路由器鏈接【前】
- 7 觀察者模式【前】
- 第五節 CRUD之D刪數據
- 1 綁定到用戶輸入事件【前】
- 2 刪除某個教師【后】
- 第六節 代碼重構
- 1 文件夾化【前】
- 2 優化交互體驗【前】
- 3 相對與絕對地址【前】
- 第三章 班級管理
- 第一節 JPA初始化數據表
- 第二節 班級列表
- 1 新建模塊【前】
- 2 初識單元測試【前】
- 3 初始化原型【前】
- 4 面向對象【前】
- 5 測試HTTP請求【前】
- 6 測試INPUT【前】
- 7 測試BUTTON【前】
- 8 @RequestParam【后】
- 9 Repository【后】
- 10 前后臺對接【前】
- 第三節 新增班級
- 1 初始化【前】
- 2 響應式表單【前】
- 3 測試POST請求【前】
- 4 JPA插入數據【后】
- 5 單元測試【后】
- 6 惰性加載【前】
- 7 對接【前】
- 第四節 編輯班級
- 1 FormGroup【前】
- 2 x、[x]、{{x}}與(x)【前】
- 3 模擬路由服務【前】
- 4 測試間諜spy【前】
- 5 使用JPA更新數據【后】
- 6 分層開發【后】
- 7 前后臺對接
- 8 深入imports【前】
- 9 深入exports【前】
- 第五節 選擇教師組件
- 1 初始化【前】
- 2 動態數據綁定【前】
- 3 初識泛型
- 4 @Output()【前】
- 5 @Input()【前】
- 6 再識單元測試【前】
- 7 其它問題
- 第六節 刪除班級
- 1 TDD【前】
- 2 TDD【后】
- 3 前后臺對接
- 第四章 學生管理
- 第一節 引入Bootstrap【前】
- 第二節 NAV導航組件【前】
- 1 初始化
- 2 Bootstrap格式化
- 3 RouterLinkActive
- 第三節 footer組件【前】
- 第四節 歡迎界面【前】
- 第五節 新增學生
- 1 初始化【前】
- 2 選擇班級組件【前】
- 3 復用選擇組件【前】
- 4 完善功能【前】
- 5 MVC【前】
- 6 非NULL校驗【后】
- 7 唯一性校驗【后】
- 8 @PrePersist【后】
- 9 CM層開發【后】
- 10 集成測試
- 第六節 學生列表
- 1 分頁【后】
- 2 HashMap與LinkedHashMap
- 3 初識綜合查詢【后】
- 4 綜合查詢進階【后】
- 5 小試綜合查詢【后】
- 6 初始化【前】
- 7 M層【前】
- 8 單元測試與分頁【前】
- 9 單選與多選【前】
- 10 集成測試
- 第七節 編輯學生
- 1 初始化【前】
- 2 嵌套組件測試【前】
- 3 功能開發【前】
- 4 JsonPath【后】
- 5 spyOn【后】
- 6 集成測試
- 7 @Input 異步傳值【前】
- 8 值傳遞與引入傳遞
- 9 @PreUpdate【后】
- 10 表單驗證【前】
- 第八節 刪除學生
- 1 CSS選擇器【前】
- 2 confirm【前】
- 3 功能開發與測試【后】
- 4 集成測試
- 5 定制提示框【前】
- 6 引入圖標庫【前】
- 第九節 集成測試
- 第五章 登錄與注銷
- 第一節:普通登錄
- 1 原型【前】
- 2 功能設計【前】
- 3 功能設計【后】
- 4 應用登錄組件【前】
- 5 注銷【前】
- 6 保留登錄狀態【前】
- 第二節:你是誰
- 1 過濾器【后】
- 2 令牌機制【后】
- 3 裝飾器模式【后】
- 4 攔截器【前】
- 5 RxJS操作符【前】
- 6 用戶登錄與注銷【后】
- 7 個人中心【前】
- 8 攔截器【后】
- 9 集成測試
- 10 單例模式
- 第六章 課程管理
- 第一節 新增課程
- 1 初始化【前】
- 2 嵌套組件測試【前】
- 3 async管道【前】
- 4 優雅的測試【前】
- 5 功能開發【前】
- 6 實體監聽器【后】
- 7 @ManyToMany【后】
- 8 集成測試【前】
- 9 異步驗證器【前】
- 10 詳解CORS【前】
- 第二節 課程列表
- 第三節 果斷
- 1 初始化【前】
- 2 分頁組件【前】
- 2 分頁組件【前】
- 3 綜合查詢【前】
- 4 綜合查詢【后】
- 4 綜合查詢【后】
- 第節 班級列表
- 第節 教師列表
- 第節 編輯課程
- TODO返回機制【前】
- 4 彈出框組件【前】
- 5 多路由出口【前】
- 第節 刪除課程
- 第七章 權限管理
- 第一節 AOP
- 總結
- 開發規范
- 備用