SpringMVC簡介
SpringMVC是Spring提供的一套建立在Servlet基礎上,基于MVC模式的web解決方案
SpringMVC核心組件
DispatcherServlet
:前置控制器,來自客戶端的所有請求都經由DispatcherServlet進行處理和分發Handler
:處理器,包括了攔截器和控制器中的方法,主要負責處理請求HandlerMapping
:映射器,解析文件和掃面注解,內部緩存了handler和handler的訪問路徑,被DispatcherServlet調用,用于查找路徑對應的handlerHandlerAdapter
:適配器,處理請求參數和處理響應數據,DispatcherServlet就是通過HandlerAdapter間接調用handlerViewResolver
:視圖解析器,返回的視圖是邏輯視圖,需要進行解析、渲染之后才是給用戶看的頁面
SpringMVC的工作流程
前端發送的請求由DispatcherServlet接收到,然后DispatcherServlet調用HnadlerMapping映射器,通過URL去匹配對應的handler,因為無法確定處理的類型,所以調用HandlerAdapter適配器去適配handler,適配之后就會調用這個handler處理器(實際就是攔截器和控制器下的方法),如果返回的類型是ModelAndView,就會將這個ModelAndView返回給ViewResolver視圖解析器進行解析,得到視圖的位置,然后對這個視圖進行渲染,最后將渲染好的視圖交給DispatcherServlet返回給前端展示;如果在控制器(比如說類或者某個方法上)中加上了@ResponseBody這個注解,就代表handler的返回值是直接返回給前端的,不會經過視圖解析器
SpringMVC的使用
第一步:引入依賴
<properties><lombok-vesion>1.18.24</lombok-vesion><fastjson-version>2.0.42</fastjson-version><spring-context-version>5.3.8</spring-context-version><spring-context-supprt-version>5.3.8</spring-context-supprt-version><spring-aop-version>5.3.23</spring-aop-version><project.compile.source>1.8</project.compile.source><project.compile.target>1.8</project.compile.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring-context-version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring-context-supprt-version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok-vesion}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring-aop-version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>${aspectJ-version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring-context-version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson-version}</version></dependency>
</dependencies>
第二步:創建spring.xml
在resources文件夾下創建spring.xml文件
錯誤一:命名空間的標簽不匹配,比如
xmlns:mvc="http://www.springframework.org/schema/c"
,mvc應該對應的是../schema/mvc
錯誤二:沒有添加對應的xsi:schemaLocation,比如引入了
xmlns:mvc="http://www.springframework.org/schema/mvc"
,但是沒有在最后添加http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--視圖解析器:在控制器返回視圖的時候生效--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--視圖資源的前綴--><property name="prefix" value="/"/><!--視圖資源的后綴--><property name="suffix" value=".jsp"/></bean><!-- 映射器 --><!-- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/> --><!-- 適配器 --><!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> --><!-- 較新的版本支持注解驅動,效果等同于上面兩句 --><mvc:annotation-driven><mvc:message-converters><ref bean="stringHttpMessageConverter"/><ref bean="jsonConverter"/></mvc:message-converters></mvc:annotation-driven><!-- 添加需要掃描的包 --><context:component-scan base-package="cn.cnmd.controller, cn.cnmd.exception"/><!-- 編碼轉換器 --><!-- 字符串數據轉換器 --><bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/><!-- JSON格式數據轉換器 --><bean id="jsonConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json;charset=UTF-8</value></list></property></bean></beans>
第三步:編寫controller類
報錯:415-不支持的媒體類型
解決方案:在spring.xml中配置編碼轉化器
<!--在注解驅動中添加編碼轉換器--> <mvc:annotation-driven><mvc:message-converters><ref bean="stringHttpMessageConverter"/><ref bean="jsonConverter"/></mvc:message-converters> </mvc:annotation-driven><!-- 字符串數據轉換器 --> <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/><!-- JSON格式數據轉換器 --> <bean id="jsonConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json;charset=UTF-8</value></list></property> </bean>
UserController類
@RestController//@RestController = @Controller + @ResponseBody
@RequestMapping("/user")
public class UserController {/*** 獲取一個學生的信息** @param id 學生編號* @return 學生對象*/@GetMappingpublic Student getStudent(@RequestParam("id") int id) {// System.out.println(1/0); => 遇到異常會被帶有@RestControllerAdvice注解的ExceptionController處理return new Student();}/*** 添加一個學生** @param student 學生對象的JSON數據* @return 狀態碼*/@PostMappingpublic int addStudent(@RequestBody Student student) {System.out.println("student = " + student);return 0;}/*** 更新一個學生的信息** @param student 更新后的學生信息* @return 狀態碼*/@PutMappingpublic int updateStudent(@RequestBody Student student) {System.out.println("student = " + student);return 0;}/*** 通過學生id刪除一個學生** @param id 學生編號* @return 狀態碼*/@DeleteMapping("/{id}")public int deleteStudent(@PathVariable("id") int id) {System.out.println("id = " + id);return 0;}/*** 批量查詢學生** @param currentPage 當前頁數* @param pageSize 當頁數據條數* @return 學生集合*/@GetMapping("/stuList")public List<Student> getAllStudent(@RequestParam("currentPage") int currentPage,@RequestParam("pageSize") int pageSize) {System.out.println("currentPage = " + currentPage + ", pageSize = " + pageSize);return new ArrayList<>();}/*** 獲取請求頭中的數據** @param ua 請求頭中的User-Agent*/@GetMapping("/header")public void getHeader(@RequestHeader("User-Agent") String ua) {System.out.println("ua = " + ua);}/*** 獲取cookie中的數據** @param status cookie中的key:status*/@GetMapping("/cookie")public void getCookie(@CookieValue("status") String status) {System.out.println("status = " + status);}}
全局異常處理
@RestControllerAdvice
public class ExceptionController {/*** 處理全局異常的方法** @param e 異常對象* @return 異常信息*/@ExceptionHandler(Exception.class)public String exceptionHandler(Exception e) {return e.getMessage();}
}
常用的注解
實例都在上方
//用于標記是否是一個控制器
@Controller//匹配請求中的URL地址來調用對應的handler
@RequestMapping//用于匹配URL地址中的parameter參數
@RequestParam//用于匹配URL路徑上的參數
@PathVariable//用于匹配前端發送給后端的JSON數據
@RequestBody//用于匹配請求頭中的數據
@RequestHeader//用于匹配Cookie中的數據
@CookieValue//用于標記一個方法的返回值是否直接返回給前端
@ResponseBody//RESTFul風格下的注解,等同于@Controller + @ResponseBody
@RestController//RESTFul風格下的用于匹配不同請求方式
@GetMapping/@PostMapping/@PutMapping/@DeleteMapping//該注解只能應用在類上,表示這個類就是處理異常的控制器
@ControllerAdvice//RESTFul風格下的用于表示這個類就是處理異常的控制器,并且返回值直接返回給前端,等同于@ControllerAdvice + @ResponseBody
@RestControllerAdvice//該注解只能應用在@ControllerAdvice或者說@RestControllerAdvice標識的類的方法上,用來處理異常
@ExceptionHandler
靜態資源訪問解決
為什么靜態資源無法訪問?
因為在Tomcat的自帶的web.xml中有這樣一個配置
<!--.......-->
<servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<!--.......-->
<!-- The mapping for the default servlet -->
<servlet-mapping><servlet-name>default</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>
說明在創建webapp項目時,我們在web.xml中配置的DispathcerServlet的映射覆蓋了DefaultServlet的映射,所以就不會再使用默認的DefaultServlet,造成了靜態資源無法訪問
解決方案
方案一:修改@XxxMapping
中的url,比如加上后綴.do
、.action
方案二【推薦】:在web.xml中配置靜態資源的訪問地址,比如將js、css、圖片等靜態資源放在static文件夾下
<!-- web.xml -->
<servlet-mapping><servlet-name>default</servlet-name><url-pattern>/static/*</url-pattern>
</servlet-mapping>
方案三:在spring.xml文件中配置 default-servlet-handler
<!--
這個handler就是處理靜態資源的,它的處理方式就是將請求轉會到tomcat中名為default的Servlet
-->
<mvc:default-servlet-handler/>
<!-- mapping是訪問路徑,location是靜態資源存放的路徑 -->
<mvc:resources mapping="/static/**" location="/static/" />
中文亂碼問題
解決方案:編碼轉換器
<!-- 編碼轉換器 -->
<!-- 字符串數據轉換器 -->
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/><!-- JSON格式數據轉換器 -->
<bean id="jsonConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json;charset=UTF-8</value></list></property>
</bean>
<!--在注解驅動中添加編碼轉化器-->
<mvc:annotation-driven><mvc:message-converters><ref bean="stringHttpMessageConverter"/><ref bean="jsonConverter"/></mvc:message-converters>
</mvc:annotation-driven>