SpringMVC框架
回顧
項目開發步驟:
- 准備maven項目
- 加入Spring MVC依賴
- 在web.xml添加大C的配置
- 創建配置類, 需要@Configuration, @ComponentScan, @EnableWebMvc
- 開發控制器
如何做靜態資源的處理[讓靜態資源的請求不經過大C]
- 詳見第一天筆記
控制器的開發
- 寫一個JAVA類,打上
@Controller
注解 - 在控制器,開發處理用戶請求的方法,這個方法上要打上
@RequestMapping
, 並且寫在請求的URI。
注:
@RequestMapping
即可以寫在類上面,也可以寫在 方法上面。@Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/abc") public String hello() { return "hello.jsp"; } }
如果在類上面和方法上面都有寫 @RequestMapping的話,則我們的請求URI是兩者的結合。
請求參數的處理
- 在SpringMVC的控制器方法中,可以使用Servlet時代的任意對象做為參數。比如:我們可以在方法中添加
HttpServletRequest
,HttpServletResponse
,HttpSession
, ... - 前台表單數據提交后,Spring MVC可以自動幫助我們封裝成JavaBean,我們可以直接以這個JAVABEAN做為方法的參數來接。要求是:表單域的名字要與JAVABEAN的屬性名保持一樣。
- 有關Model參數,它本質就是一個LinkedHashMap, key就是字符串,不允許為NULL,Value就是Object, 我們可以通過Model來添加任意的對象到前端頁面。
視圖處理器
SpringMVC框架默認的視圖是采用JSP。
我們可以配置視圖解析器。
編碼問題
- 請求的方式如果是GET的話,瀏覽器會把請求數據封裝到請求頭【Request Header】中傳輸到后端.
- 請求的方式如果是POST的話,瀏覽器會把請求數據封裝到請求體【Request Body】中傳輸到后端。
編碼過濾器中設置請求和響應的編碼,它只能影響請求體部,不能改變頭部的編碼。換句話說,它只對POST請求有效。
如果需要修改請求頭的編碼,只能修改容器的配置。Tomcat 的配置如下:
<Connector connectionTimeout="20000" port="8088" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
如果你使用的是maven的tomcat7插件,則只需要在 pom.xml中配置即可:如下:
<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8888</port> <path>/</path> <!-- 指定請求頭部的編碼 --> <uriEncoding>utf8</uriEncoding> </configuration> </plugin>
SpringMVC框架
請求的轉發和重定向處理
默認情況下,SPRINGMVC的請求都是以“轉發”到下一個資源的,如果在控制方法中,沒有指定@ResponseBody注解,則默認采用 jsp 為視圖。
如果我們要重定向一個請求,則需要使用 "redirect:" 開頭,后面再接 視圖的名字。如: "redirect:/user/list"
默認情況下,視圖解析器采用轉發來跳轉請求,那么使用了 forward關鍵字和默認情況的區別是什么 ?
使用了 forward: 或 redirect: 為前綴的話,則這個請求跳轉會忽略視圖解析器。如:
return "user/register"; //真正的URI: /WEB-INF/user/register.jsp
return "forward:/WEB-INF/user/register.jsp"; //自已寫完整的URI
使用redirect,相當於是重定向請求。
異常的處理
其實,在 容器層面也有全局的異常處理機制,它是通過在 web.xml中配置
的標簽來實現的,如下: <error-page> <exception-type>java.lang.Exception</exception-type> <location>/error.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page>
當容器收到控制器拋出的異常時或者容器出現了服務端錯誤【500】時,則根據配置把頁面轉發到 /error.jsp 中,在 這個頁面是,通過在 page 指令中加入 isErrorpage="true"屬性后,就可以拿到容器中出現的異常對象.
在SpringMVC中,我們也可以針對異常進行處理,這個處理是由大C來負責。有如下方式:
-
配置全局的異常處理器
在
WebMvcConfig.java
中,添加一個HandlerExceptionResolver
的 @Bean, 如下:@Bean public HandlerExceptionResolver exceptionHandler() { //創建 SimpleMappingExceptionResolver SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); //設置屬性 exceptionResolver.setDefaultErrorView("forward:/error.jsp"); //排除的異常 exceptionResolver.setExcludedExceptions(LoginException.class); // exceptionResolver.setDefaultStatusCode(500); // exceptionResolver.setWarnLogCategory("org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"); //返回 return exceptionResolver; }
注: exceptionResolver.setWarnLogCategory 是表示打開全局的異常日志功能
-
配置控制器級別的異常處理器
利用注解 @ExceptionHandler 來修飾一個方法,這個方法必需要在 @Controller修飾的類中,這樣一來,此 Controller中的方法有任何一個拋出異常后,框架都會回調 @ExceptionHandler 修飾的方法,這樣一來,我們就可以在此方法中做異常信息的日志、記錄或信息的展示,並把某些信息綁定一前台頁面中供用戶查看【這個由程序員決定】
它的代碼如下:
@ExceptionHandler(value = {RuntimeException.class, IOException.class}) public String initEx(Model model,Exception e) { System.out.println("---> ExceptionController中的方法出異常了..."); /* System.out.println(e.getMessage()); e.printStackTrace();*/ model.addAttribute("server.ex",e); // return "forward:/ex.jsp"; }
以上只是一個代碼片斷。
攔截器的使用[Interceptor]
注:
SpringMVC的攔截器是針對控制器級別的攔截,它由 大C 來處理,而不是由容器來處理。它主要是針對控制器的攔截,下面的圖示分別說明了 Filter, Interceptor, AOP 三種攔截的范圍
開發攔截器的步驟:
- 寫一個類實現
HandlerInterceptor
接口,並重寫它的三個方法- preHandle 方法 , 在調用目標小C 之前
- postHandle 方法, 在調用目標小C之后,但是視圖渲染之前
- afterCompletion 方法,視圖渲染之后
- 配置這個攔截器,采用 xml 的配置法
攔截器的使用:
把小C中需要執行的一些共性操作拿出來做為 攔截器的功能。比如:
日志,認證,授權,性能監測....
此處我們編寫一個攔截器,用來記錄每一次請求的處理時間,為了精切地記錄這個時間值,我們建議采用攔截器來完成,從 preHandle 方法中開始計算,在 afterCompletion 方法結束計時,並計算出兩個時間差,把這個時間差寫入到數據庫的性能監控表中。
注:
這里我們不去直接實現
HandlerInterceptor
類,而是繼承一個抽象父類HandlerInterceptorAdapter
注:
當我們配置多個攔截器時,它的 preHandle 方法是按順序執行的,而 postHandle和afterCompletion方法則是按逆序進行執行的。
json數據格式的使用
在SpringMVC框架中,@RequestMapping方法一般有如下幾種返回值:
- 返回 String, 表示視圖的邏輯名【前提是配置視圖解析器】
- 返回void,表示沒有返回值,此時,你需要在方法體中,通過request或是 response來編程進行跳轉或重定向,當然,也可以通過 response.getWriter.println(".....") 輸出內容到瀏覽器端。
- 返回ModelAndView, 表示返回一個模型和視圖,我們需要自己創建這個對象,並且設置Model數據和視圖的名字。
- 如果不是以上三種,那就是返回單個JAVABEAN或是它的集合體,這種情況一般都需要把這個數據轉換成JSON格式,這個過程是自動的,只需要在RequestMapping中,添加produce屬性,指定生成的內容就是 json,同時,還要加上 @ResponseBody 注解。
案例:
文件上傳和下載
構建SpringMVC框架的結構
- 構建maven項目
- 添加 spring mvc框架相關的依賴
- 在web.xml中配置大C以及編碼過濾器
Spring MVC框架的核心API和核心注解
- DispatcherServlet,俗稱大 C, 也就是前置控制器
- 核心注解:
- @EnableWebMvc
- @Import 導入另一個配置類
- @ImportResource 讀入 spring框架的 xml 配置
- @PropertySource 讀入 .properties 屬性文件
SpringMVC框架的注解配置類
一般的策略是: 把WEB層、業務層和持久層 分開配置,其中,AppConfig.java 配置類負責像數據源、持久層的支持類、事務、等。而在 WebMvcConfig.java 配置類中負責像 靜態資源處理器、視圖解析器、文件上傳處理器、BeanValidation處理器、全局異常處理等
SpringMVC的注解配置類需要繼承 WebMvcConfigurerAdapter
類,它的意義在於給我們一個機會,讓我們參與到配置的過程當中。
有關這個類的詳細的配置,請參考代碼。
有關大C的匹配規則
- 擴展名匹配, 如: *.do, *.action, *.xxx
- 通配匹配, 如: /
如何處理靜態資源?
只是針對大C采用 / 來做為請求匹配規則時才需要的操作。
控制器的開發
記住如下幾個核心注解:
- @Controller 它是 @Component 的一種
- @RequestMapping
- @ResponseBody
- @RequestParam
- @PathVariable
- @ModelAttribute
- @SessionAttribute
- @ExceptionHandler
- @RestController 支持RESTFul 風格URI的控制器,它相當於:@Controller+@ResponseBody
- ...
與業務層、持久層的整合
直接導入 AppConfig.java 即可。
SpringMVC中的重要功能點
1. 靜態資源處理
2. SpringMVC對請求參數的自動化封裝
3. 請求的轉發和重定向
4. 視圖解析器的配置
5. 異常的處理
6. 攔截器的開發
7. 返回 json 數據格式
8. 文件上傳和下載
9. Bean Validation
10. RESTFUL 風格的URI
文件上傳和下載
文件的上傳必需要使用 post方式提交,所以,我們需要定義一個表單
另外一個,表單的 enctype一定要指定為: multipart/form-data
在服務端,需要能過一個特殊對象: MultipartFile 來接收用戶的文件上傳請求。
Bean Validation
前端頁面的驗證是極其不安全的,可以輕易地跳過前端的驗證。
為了數據的有效性和一致性,我們在后端也需要對前端傳遞過來的數據進行驗證。
JSR303 規范就是定義了 Bean Validation的規范,目前,官方說明中,Hibernate Validator 組件是JSR303的參考實現。所以,Spring MVC框架結合 Hibernate Validator。
操作步驟
- 導入 hibernate-validtor 的依賴
- 在 WebMvcConfig.java 中重寫父類的 getValidator 方法, 在實現中返回 LocalValidatorFactoryBean
- 在需要驗證的對象中,使用 JSR303 的注解進行注解
- 在控制器的方法參數中,使用 @Validated 注解需要驗證的對象,並添加 BindingResult 對象為參數。