利用Postman和Chrome的開發者功能探究專案
controller層研究
前兩天忙著寫開題報告,沒有來得及做專案,今天繼續研究一下這個專案。
上次研究到後端的DAO層,研究了一下後端和資料庫互動的過程,service層封裝了一些DAO層的函式,沒有什麼太多的東西,今天研究一下controller層和前端的程式碼。
首先,一個典型的controller層程式碼是這樣的:
package...
import ...
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class LibraryController {
@Autowired
BookService bookService;
@CrossOrigin
@GetMapping("/api/books")
public List<Book> list() throws Exception {
return bookService.list();
}
...
}
按照慣例,首先看一下各個註解:
@RestController:相當於@ResponseBody+@Controller註解
@ResponseBody:@ResponseBody的作用其實是將java物件轉為json格式的資料。將controller的方法返回的物件通過適當的轉換器轉換為指定的格式之後,寫入到response物件的body區。
@Controller:用於標記在一個類上,使用它標記的類就是一個SpringMVC Controller物件。分發處理器將會掃描使用了該註解的類的方法,並檢測該方法是否使用了@RequestMapping註解。@Controller只是定義了一個控制器類,而使用@RequestMapping註解的方法才是真正處理請求的處理器。
@Autowired:自動裝配,和控制反轉什麼的有關係,這個這裡不展開了。
@CrossOrigin:跨域,這個問題大概就是說前後端不用一個伺服器,瀏覽器對這種行為會出於安全考慮不允許跨域訪問,所以需要設定一下,具體細節比較瑣碎,這裡不展開了。
@GetMapping:SpringMVC以前版本的@RequestMapping,到了新版本被下面新註釋替代,相當於增加的選項:@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping,從命名約定我們可以看到每個註釋都是為了處理各自的傳入請求方法型別,即@GetMapping用於處理請求方法的GET型別,@PostMapping用於處理請求方法的POST型別等。如果我們想使用傳統的@RequestMapping註釋實現URL處理程式,那麼它應該是這樣的:@RequestMapping(value = "/get/{id}", method = RequestMethod.GET),新方法可以簡化為:@GetMapping("/get/{id}")。
後面的函式中還有一些其他的註解,一起看一下:
@CrossOrigin
@PostMapping("/api/books")
public Book addOrUpdate(@RequestBody Book book) throws Exception {
bookService.addOrUpdate(book);
return book;
}
@CrossOrigin
@PostMapping("/api/delete")
public void delete(@RequestBody Book book) throws Exception {
bookService.deleteById(book.getId());
}
@CrossOrigin
@GetMapping("/api/categories/{cid}/books")
public List<Book> listByCategory(@PathVariable("cid") int cid) throws Exception {
if (0 != cid) {
return bookService.listByCategory(cid);
} else {
return list();
}
}
@CrossOrigin
@GetMapping("/api/search")
public List<Book> searchResult(@RequestParam("keywords") String keywords) {
// 關鍵詞為空時查詢出所有書籍
if ("".equals(keywords)) {
return bookService.list();
} else {
return bookService.Search(keywords);
}
}
@RequestBody:@RequestBody主要用來接收前端傳遞給後端的json字串中的資料的(請求體中的資料的);GET方式無請求體,所以使用@RequestBody接收資料時,前端不能使用GET方式提交資料,而是用POST方式進行提交。
@PathVariable是spring3.0的一個新功能:接收請求路徑中佔位符的值
@RequestParam:@RequestParam有三個配置引數:required
表示是否必須,預設為true,
必須。defaultValue
可設定請求引數的預設值。value
為接收url的引數名(相當於key值。這個好像用法比較複雜,之後再仔細看一下。
Postman和chrome測試
首先我們登入進入系統,我這裡前後端互動使用的8443埠,後續測試也在8443埠上進行。
可以看到傳送了一個請求報文,收到了一個回覆報文,回覆報文的內容是一些json鍵值對,下面放了一個樣例:
{
"id": 69,
"category": {
"id": 1,
"name": "文學"
},
"cover": "https://i.loli.net/2019/04/10/5cad63931ce27.jpg",
"title": "謀殺狄更斯",
"author": "[美] 丹·西蒙斯 ",
"date": "2019-4",
"press": "上海文藝出版社",
"abs": "“狄更斯的那場意外災難發生在1865年6月9日,那列搭載他的成功、平靜、理智、手稿與情婦的火車一路飛馳,迎向鐵道上的裂隙,突然觸目驚心地墜落了。”"
}
與Pojo中的book和category完全對應,這裡放一下程式碼。
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
int id;
//把 category 物件的 id 屬性作為 cid 進行了查詢
@ManyToOne
@JoinColumn(name="cid")
private Category category;
String cover;
String title;
String author;
String date;
String press;
String abs;
...
}
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
int id;
String name;
...
}
前端的EditForm.vue中有這麼一段程式碼顯然是和這個相對應的,這裡我們先不去管這個:
我們接著測試一下其他方法:
構造了一個post報文,返回200表示成功了,有趣的是雖然傳入了id,但是由於id是自增的,並沒有起作用,再使用get方法查詢一下。
下一個方法表示要刪除一本書,我們從程式碼這個大概知道是拿到一個json物件,轉換成javabean的book,然後根據id把書刪除了,我們應該傳入一個json物件的書,試一下:
成功了,但是有趣的是在chrome瀏覽器中,對於前端的行為不完全是這樣:
根據網上的教程,F12開啟後,在Network下勾選Preserve log就可以監控報文。
我們開啟後刪除一本書。
雙擊點開後發現Request只傳遞了id,因為原來函式裡只需要id,所以只傳id是完全沒毛病的,這個我在postman裡面測過了,就不發上來了:
這個就是拿一個從url路徑裡面拿一個引數,測試了一下不存在的分類號,不會報錯,而是給一個空集合。
這個沒太看懂引數是怎麼傳遞的,我們用Chrome看一下。
是通過在路徑後面加上“?keyword=關鍵詞”實現的。
去postman裡面試一下,成功!
今天的探索到這裡就結束了,後面再看一下前端程式碼的邏輯,這個互動過程就比較清楚了。