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 学生对象
*/
@GetMapping
public Student getStudent(@RequestParam("id") int id) {
// System.out.println(1/0); => 遇到异常会被带有@RestControllerAdvice注解的ExceptionController处理
return new Student();
}
/**
* 添加一个学生
*
* @param student 学生对象的JSON数据
* @return 状态码
*/
@PostMapping
public int addStudent(@RequestBody Student student) {
System.out.println("student = " + student);
return 0;
}
/**
* 更新一个学生的信息
*
* @param student 更新后的学生信息
* @return 状态码
*/
@PutMapping
public 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>