Spring Boot 2.0 讀書筆記_03:MVC 上
2. MVC 上
寫在開頭,關於MVC,Model - View - Controller模式
- Model(模型) - 代表一個存取資料的物件或 JAVA POJO。它也可以帶有邏輯,在資料變化時更新控制器。
- View(檢視) - 代表模型包含的資料的視覺化。
- Controller(控制器) - 作用於模型和檢視上。它控制資料流向模型物件,並在資料變化時更新檢視。它使檢視與模型分離開。
這裡有幾個很容易混淆的概念:模式、框架、架構、平臺,它們之間究竟是什麼關聯?
- 模式(設計模式):包括本章講述的MVC模式,均屬於設計模式。設計模式說白了就是:告訴你針對特定問題如何組織類、物件和介面之間的關係,是前人總結的經驗。
- 框架:框架是為了解決特定問題而存在的,其它諸如模板框架、快取框架等。
- 架構:從大的層面來說,架構關注的是技術整合、擴充套件、可維護性。
- 平臺:類似框架,但又結合的架構的考慮,它是更高層面上的“框架”,準確說是一種應用。它是針對企業使用者,為解決企業業務需要而形成的產品。
概念比較:設計模式 < 框架 < 架構 < 平臺
從複用角度講:設計模式是程式碼級複用、框架是模組級複用、架構是系統級複用、平臺是企業應用級複用。
在專案中使用最多的就是Spring MVC框架了,Spring Boot已經將這一MVC框架進行了自動整合並實現了自動配置,可謂一步到位。
-
Web專案目錄結構及包結構規範
- 專案目錄結構
關於web專案,常規情況下采用maven專案構建工具的打包工具生成。有了Spring Boot這一整合框架,在IDEA中通過Spring Initializr可進行快速SpringBoot專案的搭建。
專案根目錄:src/main- java
- packageName
- conf
- controller
- entity
- service
- impl
- …
- dao
- …
- Application.java (啟動器類)
- packageName
- resources
- static (靜態資源預設)
- css
- js
- …
- template (頁面模板預設)
- application.properties (配置檔案)
- static (靜態資源預設)
- java
- 包結構規範:上述專案目錄結構為標準
- Spring Boot預設掃描規則是:自動掃描啟動器類的同包或者其子包的下的註解。
- 專案目錄結構
-
URL對映到方法
- @RequestMapping
- 用於類上的@RequestMapping註解用來標註請求路徑
- 用於方法上的@RequestMapping註解用來進一步對映特定的URL到具體的處理方法
- @RequestMapping 的屬性
- value :請求的URL路徑,支援URL模板、正則表示式
- method:HTTP請求方法 GET、POST、PUT等
- consumes:允許的媒體型別| consumes = “application/json” 對應HTTP請求的Content-type
- produces:響應的媒體型別| produces = “application/json” 對應HTTP請求的Accept欄位
- params:請求的引數,params = “action=update”
- headers:請求HTTP頭的值,headers = “myHeader=myValue”
- URL 路徑匹配
- 屬性value用於匹配URL對映,value支援簡單的表示式來匹配
例如:@RequestMapping(value = “/get/user.json”) - Ant路徑表示式
- Ant 用符號 " * " 來表示匹配任意字元,用 " ** " 來表示統配任意路徑,用 " ? " 來匹配單個字元。
- 屬性value用於匹配URL對映,value支援簡單的表示式來匹配
例子 說明 /user/*.html 匹配 /user/1.html、/user/2.html等 /**/1.html 匹配 /1.html、/user/1.html、/user/add/1.html等 /user/?.html 匹配 /user/1.html,不匹配 /user/11.html -
匹配優先順序:如果一個請求有多個 @RequestMapping 能夠匹配
- 有萬用字元的低於沒有萬用字元的,比如 /user/add.json 比 /user/*.json 優先匹配。
- 有 “**” 萬用字元的低於有 “*” 萬用字元的。
- 其他URL對映:通過外部配置檔案可以進行引數獲取
@Value("${paramName}")
private String name; // 將paramName對映到成員變數name屬性
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@Value("#{ }") SpEL表示式
通常用來獲取bean的屬性,或者呼叫bean的某個方法,也可以表示常量
-
HTTP method 匹配
- @RequestMapping 提供 method 屬性來對映HTTP的請求方法。
- 通常對於Web應用,GET和POST是經常使用的method,對於REST介面,則會採用PUT、DELETE等用來從語義上進一步區分操作。
- Spring 提供簡化後的 @RequestMapping ,提供了新的註解來表示 HTTP 方法。如:
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
- @PatchMapping
- …
-
consumes 和 produces
-
屬性 consumes 表示請求的HTTP頭的Content-type媒體型別與consumes的value匹配才能呼叫此方法
@GetMapping(value = "/consumes/test.json", consumes = "application/json") @ResponseBody public User forJson() { return userService.getUserById(1l); }
這裡對映指定請求的媒體型別是 application/json 。因此,此方法接收一個如下AJAX請求:
$.ajax({ type: "get", url: "/consumes/test.json", contentType: "application/json", ... });
-
屬性 produces 對應HTTP請求的Accept欄位,只有匹配成功才能進行方法呼叫。
@GetMapping(value = "/user/{userId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
將通常瀏覽器都會把 Accept 設定為 *.* ,因此通過瀏覽器直接訪問 “/user/1” ,瀏覽器總是返回對應資訊,並通過 @ResponseBody 轉換成JSON格式返回。
-
-
params 和 headers
不同於Servlet規範,在方法中通過 HttpServletRequest 獲取請求的URL、HTTP頭這些資訊再進行處理。Spring在方法簽名處提供了很多匹配方式,能進一步規範方法呼叫,提高程式碼可閱讀性。@GetMapping(value = "/update.json", headers = "action=update") // params 同理
- @RequestMapping
-
方法引數
-
@PathVariable
-
用於從請求URL中獲取引數,並對映到方法引數中
@GetMapping(path = "/{userId}.json", produces = "application/json") @ResponseBody public User getUserById(@PathVariable Long userId) { return userService.getUserById(userId); }
符號 {} 中的變數名與方法引數名字對應,若不想對應可以使用:@PathVariable(“userId”) Long id
-
-
Model & ModelAndView
- Model(結構類似Map),可以向檢視中新增需要的變數
- Model物件主要方法:
- Model addAttribute(String attributeName, Object attributeValue):向模型中新增一個變數,引數簽名列表前者指明變數名稱,可以在隨後的檢視中引用。後者代表變數。
- Model addAttribute(Object attributeValue):向模型中新增一個變數,變數的名字就是類名首字母小寫後專為的Java變數。
- Model addAllAttributes(Map attributes):新增多個變數,若變數存在,則覆蓋。
- Model mergeAttributes(Map attributes):新增多個變數,若變數存在,則忽略。
- Boolean containsAttribute(String attributeName):判斷是否存在變數。
-
如何使用:ModelAndView物件類似Model,但額外提供了一個檢視名稱的配置。
// Model model model.addAttribute("userInfo", user); // ModelAndView view view.addObject("userInfo", user); view.setViewName("/userInfo.html"); return view
-
JavaBean 接收HTTP引數 @RequestParam
-
通過 @RequestParam 限定HTTP引數
-
name:指明HTTP引數名稱
-
required:布林型別,宣告此引數是否必須有,如果該引數沒有,丟擲400錯誤
-
defaultValue:字元型別,如果HTTP引數沒有提供,可以指定一個預設字串
String getUser(@RequestParam(name = "name", required = false, defaultValue = "zhangsan") String name){...}
-
-
接收一個引數物件:HTTP引數名字對應POJO屬性名
@GetMapping("/getUser") @ResponseBody public String getUser(User user){...}
-
-
@RequestBody 接收JSON
-
方法引數使用 @RequestBody 指定引數型別為JSON資料,且對映的是一個實體POJO類。
-
Spring Boot預設使用Jackson來處理反序列化工作。
@PostMapping("/save.json") @ResponseBody public String saveUser(@RequestBody User user){...}
-
注意,和JavaBean接收HTTP引數(物件)區分開,接收JSON資料是字串,採用@RequestBody進行字串向物件的對映對應
-
-
MultipartFile:處理檔案上傳
-
案例程式碼
@PostMapping("/form") @ResponseBody public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) throws IOException { if (!file.isEmpty()) { String fileName = file.getOriginalFilename(); InputStream ins = file.getInputStream(); // 處理上傳內容 return "success"; } return "failure"; }
-
MultipartFile相關方法
-
方法名 說明 getOriginalFilename 獲取上傳檔名稱 getBytes 獲取上傳檔案內容,轉為位元組陣列 getInputStream 獲取一個InputStream isEmpty 檔案上傳內容為空,或者沒有檔案上傳 getSize 上傳檔案大小 transferTo(File dest) 儲存上傳檔案到目標檔案系統 -
多檔案上傳:使用MultipartFile陣列類來接收多個檔案上傳
@RequestParam("file") MultipartFile[] files
-
上傳檔案引數限制:通過配置檔案 application.properties 進行配置
-
-
@ModelAttribute
-
該註解通常作用在Controller的某個方法上,此方法會首先被呼叫,並將結果作為Model的屬性。
@ModelAttribute public void findUserById(@PathVariable Long id, Model model) { model.addAttribute("user", userService.getUserById(id)); } @GetMapping(path = "/{id}/get.json") @ResponseBody public String getUser(Model model) { System.out.println(model.containsAttribute("user")); return "success"; }
-
-
@InitBinder
- Spring框架通過WebDataBinder 類實現HTTP引數向JavaBean物件的繫結
- 可以通過@InitBinder宣告方法,進行繫結物件的特性拓展