1. 程式人生 > >Spring Boot 2.0 讀書筆記_03:MVC 上

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 (啟動器類)
      • resources
        • static (靜態資源預設)
          • css
          • js
        • template (頁面模板預設)
        • application.properties (配置檔案)
    • 包結構規範:上述專案目錄結構為標準
    • 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 用符號 " * " 來表示匹配任意字元,用 " ** " 來表示統配任意路徑,用 " ? " 來匹配單個字元。
    例子 說明
    /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 同理
      
  • 方法引數

    • @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宣告方法,進行繫結物件的特性拓展