一文講透SpringMVC

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"MVC基礎知識與應用"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"MVC體系結構"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"三層架構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在B / S架構中,系統標準的三層架構爲:表現層 、業務層、持久層。三層架構中,每一層各司其職,共同協作實現對功能的支持與實現。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"表現層"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業務層"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"持久層"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"MVC設計模式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MVC全稱是Model View Controller,就是模型 - 視圖 - 控制器的縮寫。是一種用於設計Web應用程序表現層的模式。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Model(模型):模型包含了數據模型和業務模型,數據模型用於封裝數據,業務模型用於處理業務。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"View(View ):通常指的是jsp或者html。用於展示數據。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Controller(Controller):負責應用程序與客戶端交互的核心入口。基本只負責接受請求和響應。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Spring MVC簡介"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ Spring MVC全稱是Spring Web MVC,是基於Java的實現MVC設計模式的請求驅動類型的輕量級Web框架,屬於Spring FrameWork的後續產品。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ Spring MVC已經成爲目前最流行的MVC框架之一,並且隨着Spring3.0的發佈,全面超過Struts2成爲最優秀的MVC框架。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ servlet / struts開發需要實現接口,Spring MVC可以實現接口Controller,也提供了註解方式,只需要一個註解就可以(簡便開發)。Spring MVC提供一整套註解,讓一個簡單的Java類成爲處理請求的控制器,不需要實現任何接口。並且對Restful編程風格提供了支持。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"本質"},{"type":"text","text":" Spring MVC其實就是對Servlet的封裝,簡化了我們Servlet的開發。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/58/58e5276cded89de23f4341864d96dd6a.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"開發流程"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"web.xml配置DispatcherServlet前端控制器"}]}]}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n \n dispatcherServlet\n org.springframework.web.servlet.DispatcherServlet\n \n \n \n \n dispatcherServlet\n /\n \n"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發具體的處理業務邏輯Handler(@Controller / @RequestMapper)"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Controller\n@RequestMapping(value = \"/demo\")\npublic class DemoController {\n\n /**\n * SpringMVC 項目配置(三大核心組件):\n * 1)配置前端控制器:org.springframework.web.servlet.DispatcherServlet(核心)\n * \n * dispatcherServlet\n * org.springframework.web.servlet.DispatcherServlet\n * \n * contextConfigLocation\n * classpath:springmvc.xml\n * \n * \n * \n * dispatcherServlet\n * /\n * \n * 2)配置配置視圖處理器:\n * \n * \n * \n * \n * 3)配置映射處理器(不指定,將自動匹配合適的映射處理器):\n * \n */\n /**\n * 數據返回方式一:model和view封裝到對象中\n * ModelAndView對象內部包含了:ModelMap 和 Object view兩個屬性,分別用於封裝Model數據模型和View視圖\n * @return\n */\n @RequestMapping(value = \"/handler01\")\n public ModelAndView handler01() {\n LocalDateTime now = LocalDateTime.now();\n // 封裝了Model和View視圖\n ModelAndView modelAndView = new ModelAndView();\n // 封裝返回結果到Model中\n modelAndView.addObject(\"date\", now);\n // 設置返回的視圖名稱\n modelAndView.setViewName(\"success\");\n return modelAndView;\n }\n\n /**\n * 探究ModelMap / Model / Map之間的關係,爲什麼可以將數據存儲到域並且被視圖解析器讀取到???\n * class ModelMap extends LinkedHashMap 繼承了LinkedHashMap,LinkedHashMap又實現了Map接口\n * interface Model 只是一個接口\n * interface Map 只是一個接口\n *\n * ModelMap / Model / Map 在SpringMVC注入的時候打印的都是org.springframework.validation.support.BindingAwareModelMap對象\n * 探究 BindingAwareModelMap\n * class BindingAwareModelMap extends ExtendedModelMap\n * class ExtendedModelMap extends ModelMap implements Model\n *\n * 探究結果:BindingAwareModelMap繼承了ModelMap類,實現了Model接口,最終封裝數據的是BindingAwareModelMap\n *\n */\n\n /**\n * 數據返回方式二:view視圖路徑直接return,使用ModelMap封裝數據\n * ModelMap對象:org.springframework.validation.support.BindingAwareModelMap\n * @param modelMap\n * @return\n */\n @RequestMapping(value = \"/handler11\")\n public String handler11(ModelMap modelMap) {\n LocalDateTime now = LocalDateTime.now();\n modelMap.addAttribute(\"date\",now);\n System.out.println(\"--------------\" + modelMap.getClass());\n return \"success\";\n }\n\n /**\n * 數據返回方式三:view視圖路徑直接return,使用Model封裝數據\n * Model對象:org.springframework.validation.support.BindingAwareModelMap\n * @param model\n * @return\n */\n @RequestMapping(value = \"/handler12\")\n public String handler12(Model model) {\n LocalDateTime now = LocalDateTime.now();\n model.addAttribute(\"date\",now);\n System.out.println(\"--------------\" + model.getClass());\n return \"success\";\n }\n\n /**\n * 數據返回方式四:view視圖路徑直接return,使用Map封裝數據\n * Map對象:org.springframework.validation.support.BindingAwareModelMap\n * @param map\n * @return\n */\n @RequestMapping(value = \"/handler13\")\n public String handler13(Map map) {\n LocalDateTime now = LocalDateTime.now();\n map.put(\"date\",now);\n System.out.println(\"--------------\" + map.getClass());\n return \"success\";\n }\n\n /**\n * BindingAwareModelMap也可以封裝數據,因爲最終Spring就是通過這個對象將數據放入域中\n * @param bindingAwareModelMap\n * @return\n */\n @RequestMapping(value = \"/handler14\")\n public String handler14(BindingAwareModelMap bindingAwareModelMap) {\n LocalDateTime now = LocalDateTime.now();\n bindingAwareModelMap.put(\"date\",now);\n System.out.println(\"--------------\" + bindingAwareModelMap.getClass());\n return \"success\";\n }\n}\n"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"springmvc.xml配置註解掃描、配置InternalResourceViewResolver視圖解析器、"},{"type":"codeinline","content":[{"type":"text","text":""}]},{"type":"text","text":"映射處理器"}]}]}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\t\n \n\n \n \n \n \n \n \n\n \n \n"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在web.xml的DispatcherServlet中配置springmvc.xml路徑"}]}]}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":" \n \n dispatcherServlet\n org.springframework.web.servlet.DispatcherServlet\n \n \n contextConfigLocation\n classpath:springmvc.xml\n \n \n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Spring MVC請求處理流程"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9b/9b48264b0f03e3759c7b5b8e2fd2f555.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"流程說明"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1)用戶發送請求到前端控制器DispatcherServlet"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2)DispatcherServlet接受到用戶發起的請求後調用HandlerMapping映射處理器"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3)映射處理器根據請求的url找到具體的Handler(後端控制器),生成處理器對象以及處理器攔截器(有就生成)並將Handler返回給DispatcherServlet"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4)DispatcherServlet調用HandlerAdapter處理器適配器去調用Handler"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5)處理器適配器執行Handler"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6)Handler處理完畢後返回ModelAndView給處理器適配器"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7)處理器適配器將ModelAndView返回給前端控制器DispatcherServlet"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8)前端控制器DispatcherServlet請求視圖解析器ViewResolver解析視圖"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9)視圖解析器將解析後的視圖View返回給前端控制器DispatcherServlet"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10)前端控制器DispatcherServlet對視圖渲染,就是將數據模型填充到request域中"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"11)前端控制器DispatcherServlet想用戶響應結果"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Spring MVC九大組件"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HandlerMapping(處理器控制器)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HandlerAdapter(處理器適配器)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HandlerExceptionResolver(異常解析器)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ViewResolver(視圖解析器)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RequsetToViewNameTranslator"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"LocalResolver"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ThemeResolver"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MultipartResolver"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"FlashMapManager"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"請求參數綁定"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"基礎數據類型綁定"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ 簡單的基礎數據類型:八種基礎數據類型及其包裝類型,參數類型推薦使用包裝類類型,因爲基礎數據類型不可以爲null。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ Short / short 、Long / long 、Integer / int 、Float / float 、Double / double 、Char / char 、Boolean / boolean 、String"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"說明"},{"type":"text","text":":對於布爾值類型的參數,參數值只能爲trur / false / 1 / 0。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意"},{"type":"text","text":":綁定基礎數據類型,只需要直接聲明形參即可。建議請求參數和形參參數名稱一致,如不一致使用"},{"type":"codeinline","content":[{"type":"text","text":"@RequestParam"}]},{"type":"text","text":"註解。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n

測試用例:SpringMVC 接收簡單數據類型參數

\n 點擊測試\n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@RequestMapping(\"/handle03\")\npublic ModelAndView handle03(@RequestParam(\"ids\") Integer id,Boolean flag) {\n Date date = new Date();\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"date\",date);\n modelAndView.setViewName(\"success\");\n return modelAndView;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Pojo類型參數綁定"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n

測試用例:SpringMVC接收pojo類型參數

\n 點擊測試\n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/*\n * SpringMVC接收pojo類型參數 url:/demo/handle04?id=1&username=zhangsan\n * 接收pojo類型參數,直接形參聲明即可,類型就是Pojo的類型,形參名無所謂\n * 但是要求傳遞的參數名必須和Pojo的屬性名保持一致\n */\n@RequestMapping(\"/handle04\")\npublic ModelAndView handle04(User user) {\n Date date = new Date();\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"date\",date);\n modelAndView.setViewName(\"success\");\n return modelAndView;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Pojo包裝對象綁定"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n

測試用例:SpringMVC接收pojo包裝類型參數

\n 點擊測試\n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/*\n * QueryVo中有User user 屬性,需要將請求參數封裝到queryVo中\n * SpringMVC接收pojo包裝類型參數 url:/demo/handle05?user.id=1&user.username=zhangsan\n * 不管包裝Pojo與否,它首先是一個pojo,那麼就可以按照上述pojo的要求來\n * 1、綁定時候直接形參聲明即可\n * 2、傳參參數名和pojo屬性保持一致,如果不能夠定位數據項,那麼通過屬性名 + \".\" 的方式進一步鎖定數據\n *\n */\n@RequestMapping(\"/handle05\")\npublic ModelAndView handle05(QueryVo queryVo) {\n Date date = new Date();\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"date\",date);\n modelAndView.setViewName(\"success\");\n return modelAndView;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"日期類型綁定"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n

測試用例:SpringMVC接收日期類型參數

\n 點擊測試\n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 綁定日期類型參數\n * 定義一個SpringMVC的類型轉換器 接口,擴展實現接口接口,註冊你的實現\n * @param birthday\n * @return\n */\n@RequestMapping(\"/handle06\")\npublic ModelAndView handle06(Date birthday) {\n Date date = new Date();ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"date\",date);\n modelAndView.setViewName(\"success\");\n return modelAndView;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"自定義類型轉化器"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * Converter\n * S : 是傳遞進來的數據類型\n * T : 是處理後需要返回的數據類型\n * @Author zhang yong jun\n * @time 2020/6/11 11:25\n */\npublic class DateConverter implements Converter {\n\n private static final SimpleDateFormat SDF = new SimpleDateFormat(\"yyyy-MM-dd\");\n\n @Override\n public Date convert(String s) {\n Date parse = null;\n try {\n parse = SDF.parse(s);\n } catch (ParseException e) {\n e.printStackTrace();\n }\n return parse;\n }\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"配置自定義類型轉換器"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n\n\n\n \n \n \n \n \n\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"對Restful風格請求的支持"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ Restful是一種web軟件架構風格,它不是標準也不是協議,只是倡導url設計的時候使用資源定義以及資源操作的風格。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Restful是什麼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ REST(Representational State Transfer)描述了一個架構樣式的網絡系統。它由Roy Fielding在2000年的博士論文中提出,Roy Fielding是HTTP規範的主要編寫者之一。REST相比SOAP(Simple Object Access protocol,簡單對象訪問協議)和XML-RPC更加簡單明瞭,REST更傾向於簡單輕量的方法設計和實現。所以REST是一種設計風格。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Restful的優點"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"結構清晰、符合標準、易於理解、方便擴展"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Restful的特徵"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"資源(Resources):"},{"type":"text","text":" 網絡上的一個實體,可以是一段文本、一張圖片、一首歌曲、一種服務。可以用URI(統一資源定位符)指定它,每種資源對應一個特定的URI。要獲得資源只需要訪問這個資源的URI即可。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"表現層(Representation):"},{"type":"text","text":" 把資源呈現出來的形式,叫做表現層。比如:文本用txt格式、HTML格式、XML格式、JSON格式表現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"狀態轉化(State Transfer):"},{"type":"text","text":" 每一個請求,就代表了客戶端和服務器的一次交互。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HTTP協議是一個無狀態協議,所有的狀態都保存在服務器端。如果客戶端想要操作服務器,就必須通過一些手段,讓服務器端發生"},{"type":"text","marks":[{"type":"strong"}],"text":"狀態轉化"},{"type":"text","text":"。具體在HTTP協議中有四個表示操作方式的動詞:PUT / DELETE / GET / POST。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Restful風格URL"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"互聯網所有的一切都是資源,要求URL中只有表示資源的名稱,沒有動詞。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Restful資源操作"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用HTTP請求中的method方法put(更新) / delete(刪除) / post(新增) / get(查詢)來操作資源。但是由於安全性問題主要使用post和get。put和delete基本不使用。如果強制要使用put和delete,可以在請求中使用post並攜帶參數_method=put,服務端再配置請求方式過濾器,如果請求參數中有"},{"type":"codeinline","content":[{"type":"text","text":"__method"}]},{"type":"text","text":"就會轉換請求方式"},{"type":"codeinline","content":[{"type":"text","text":"org.springframework.web.filter.HiddenHttpMethodFilter"}]},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"Restful請求方式轉換"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n
\n \n \n
\n
\n \n \n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"web.xml"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n\n hiddenHttpMethodFilter\n org.springframework.web.filter.HiddenHttpMethodFilter\n\n\n hiddenHttpMethodFilter\n /*\n\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/*\n * restful put /demo/handle/15/lisi\n */\n@RequestMapping(value = \"/handle/{id}/{name}\",method = {RequestMethod.PUT})\npublic ModelAndView handlePut(@PathVariable(\"id\") Integer id, @PathVariable(\"name\") String username) {\n Date date = new Date();\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"date\",date);\n modelAndView.setViewName(\"success\");\n return modelAndView;\n}\n/*\n * restful delete /demo/handle/15\n */\n@RequestMapping(value = \"/handle/{id}\",method = {RequestMethod.DELETE})\npublic ModelAndView handleDelete(@PathVariable(\"id\") Integer id) {\n Date date = new Date();\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"date\",date);\n modelAndView.setViewName(\"success\");\n return modelAndView;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Ajax Json交互"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"什麼是Json"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"JSON 指的是 JavaScript 對象表示法("},{"type":"text","marks":[{"type":"strong"}],"text":"J"},{"type":"text","text":"ava"},{"type":"text","marks":[{"type":"strong"}],"text":"S"},{"type":"text","text":"cript "},{"type":"text","marks":[{"type":"strong"}],"text":"O"},{"type":"text","text":"bject "},{"type":"text","marks":[{"type":"strong"}],"text":"N"},{"type":"text","text":"otation)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"JSON 是輕量級的文本數據交換格式"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"JSON 獨立於語言:JSON 使用 Javascript語法來描述數據對象,但是 JSON 仍然獨立於語言和平臺。JSON 解析器和 JSON 庫支持許多不同的編程語言。 目前非常多的動態(PHP,JSP,.NET)編程語言都支持JSON"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Json的語法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"JSON 語法是 JavaScript 對象表示語法的子集。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據在名稱/值對"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據由逗號分隔"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大括號保存對象"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中括號保存數組"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"@RequestBody註解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"@ReqeustBody註解是Spring MVC對Json的支持,作用是將用戶請求的Json格式數據解析轉換爲對應的參數對象。這個註解解析的是Post請求的body區域參數。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"@ResponseBody註解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"@ResponseBody註解是Spring MVC對Json的支持,作用是將Controller返回的對象通過轉換器轉換爲指定的格式之後,寫入到reqsponse對象的body區域。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意"},{"type":"text","text":" 使用這個註解後返回結果不走視圖處理器,而是直接將數據寫入到輸出流中響應給客戶端。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Spring MVC使用Json交互"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"pom引入jar"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n\n com.fasterxml.jackson.core\n jackson-core\n 2.9.0\n\n\n com.fasterxml.jackson.core\n jackson-databind\n 2.9.0\n\n\n com.fasterxml.jackson.core\n jackson-annotations\n 2.9.0\n\n\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n

Ajax json交互

\n
\n \n
\n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"javascript"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"$(function () {\n $(\"#ajaxBtn\").bind(\"click\",function () {\n // 發送ajax請求\n $.ajax({\n url: '/demo/handle07',\n type: 'POST',\n data: '{\"id\":\"1\",\"name\":\"李四\"}',\n contentType: 'application/json;charset=utf-8',\n dataType: 'json',\n success: function (data) {\n alert(data.name);\n }\n })\n })\n})\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@RequestMapping(\"/handle07\")\n// 添加@ResponseBody之後,不再走視圖解析器那個流程,而是等同於response直接輸出數據\npublic @ResponseBody User handle07(@RequestBody User user) {\n // 業務邏輯處理,修改name爲張三丰\n user.setName(\"張三丰\");\n return user;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"攔截器(Interceptor)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"攔截器需要實現"},{"type":"codeinline","content":[{"type":"text","text":"HandlerInterceptor"}]},{"type":"text","text":"接口,其中包含三個方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"preHandle"}]},{"type":"text","text":" : 在Handler方法執行前執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"postHandle"}]},{"type":"text","text":" : 在Handler方法返回前執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"afterCompletion"}]},{"type":"text","text":" : 在Handler方法返回後執行。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"自定義攔截器"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class MyInterceptor01 implements HandlerInterceptor {\n\n @Override\n public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n System.out.println(\"MyInterceptor01 preHandle......\");\n return true;\n }\n\n @Override\n public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {\n System.out.println(\"MyInterceptor01 postHandle......\");\n }\n\n @Override\n public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {\n System.out.println(\"MyInterceptor01 afterCompletion......\");\n }\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"配置攔截器"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n\n \n \n \n \n \n \n \n \n\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"multipart文件形式數據處理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"引入jar"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n\n commons-fileupload\n commons-fileupload\n 1.3.1\n\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"配置springmvc.xml"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n\n \n \n\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"文件上傳寫法一"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n

multipart 文件上傳,寫法一

\n
\n \n
\n \n \n
\n
\n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 從文件上傳的request中獲取文件\n *\n * @param req\n * @param resp\n * @return\n * @throws Exception\n */\n@RequestMapping(\"/upload01\")\npublic String fileUpload01(MultipartHttpServletRequest req, HttpServletResponse resp) throws Exception {\n // 獲取上傳的文件\n MultipartFile uploadFile = req.getFile(\"uploadFile\");\n // 獲取上傳文件的名稱\n String originalFilename = uploadFile.getOriginalFilename();\n // 獲取文件的流\n InputStream inputStream = uploadFile.getInputStream();\n // 獲取磁盤路徑, / 表示WEB-INF目錄\n String realPath = req.getServletContext().getRealPath(\"/upload\") + \"/\";\n System.out.println(\"磁盤目錄爲:\" + realPath);\n // 將文件輸出到這個目錄,這裏文件沒有重命名處理,但是生產中對文件需要重命名\n uploadFile.transferTo(new File(realPath + originalFilename));\n return \"success\";\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"文件上傳寫法二"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"html"}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"
\n

multipart 文件上傳,方式二

\n
\n \n
\n \n \n
\n
\n
\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"java"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * 直接定義MultipartFile對象\n *\n * @param multipartFile\n * @param session\n * @return\n * @throws Exception\n */\n@RequestMapping(\"/upload02\")\npublic String fileUpload02(MultipartFile multipartFile, HttpSession session) throws Exception {\n // 獲取上傳的文件名稱\n String originalFilename = multipartFile.getOriginalFilename();\n // 獲取磁盤路徑, / 表示WEB-INF目錄\n String realPath = session.getServletContext().getRealPath(\"/upload\") + \"/\" + originalFilename;\n System.out.println(\"磁盤目錄爲:\" + realPath);\n // 將文件輸出到這個目錄,這裏文件沒有重命名處理,但是生產中對文件需要重命名\n multipartFile.transferTo(new File(realPath));\n return \"success\";\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"控制器異常處理"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"局部異常處理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"局部異常處理是在單個Controller中使用"},{"type":"codeinline","content":[{"type":"text","text":"@ExceptionHandler"}]},{"type":"text","text":"標記一個方法爲這個Controller的局部異常處理Handler。可以定義多個異常處理器,分別處理不同類型的異常。"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@ExceptionHandler(value = {IOException.class})\npublic ModelAndView methodException(Exception exception) {\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"msg\", exception.getMessage());\n modelAndView.setViewName(\"error\");\n return modelAndView;\n}\n@ExceptionHandler(value = {ArithmeticException.class})\npublic ModelAndView arithmeticException(Exception exception) {\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"msg\", exception.getMessage() + \" / 局部異常處理器:arithmeticException\");\n modelAndView.setViewName(\"error\");\n return modelAndView;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"全局異常處理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"全局異常處理是創建一個Class,並且使用註解"},{"type":"codeinline","content":[{"type":"text","text":"@ControllerAdvice"}]},{"type":"text","text":"標記這個Controller增強類。這樣可以在類中定義多個異常處理器,分別處理不同的異常。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意"},{"type":"text","text":" 如果同時定義了局部異常和全局異常,那麼優先匹配的是局部異常。"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@ControllerAdvice\npublic class GlobalExceptionHandler {\n @ExceptionHandler(value = {ArithmeticException.class})\n public ModelAndView arithmeticException(Exception exception) {\n ModelAndView modelAndView = new ModelAndView();\n modelAndView.addObject(\"msg\", exception.getMessage() + \" / 全局異常處理器:arithmeticException\");\n modelAndView.setViewName(\"error\");\n return modelAndView;\n }\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"基於Flash屬性的重定向數據傳遞"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​ 對於重定向後的參數傳遞問題,一般都是重定向後拼接參數,這種方式效率不高,而且使用get方式對於參數有長度限制而且不安全。spring mvc在Controller的方法參數中提供了"},{"type":"codeinline","content":[{"type":"text","text":"RedirectAttributes"}]},{"type":"text","text":"參數用於解決重定向後的參數傳遞問題。傳遞後的參數使用"},{"type":"codeinline","content":[{"type":"text","text":"@ModelAttribute"}]},{"type":"text","text":"註解接收。"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * SpringMVC 重定向時參數傳遞的問題\n */\n@RequestMapping(\"/handleRedirect\")\npublic String handleRedirect(String name, RedirectAttributes redirectAttributes) {\n // addFlashAttribute方法設置了一個flash類型屬性,該屬性會被暫存到session中,在跳轉到頁面之後該屬性銷燬\n redirectAttributes.addFlashAttribute(\"name\",name);\n return \"redirect:handleRedirect01\";\n}\n\n/**\n * 重定向後用@ModelAttribute註解取出屬性:ModelAttribute\n * @param name\n * @return\n */\n@RequestMapping(\"/handleRedirect01\")\npublic ModelAndView handleRedirect01(@ModelAttribute(\"name\") String name) {\n LocalDateTime now = LocalDateTime.now();\n // 封裝了Model和View視圖\n \n ModelAndView modelAndView = new ModelAndView();\n // 封裝返回結果到Model中\n modelAndView.addObject(\"date\", now);\n // 設置返回的視圖名稱\n modelAndView.setViewName(\"success\");\n return modelAndView;\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"SpringMVC學習思維導圖"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/71/712aee43773896f2f2c12966b5a6238b.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章