SpringMVC概述
什么是MVC设计
-
Controller
: 负责接收并处理请求, 响应客户端 -
Model
: 模型数据, 业务逻辑 -
View
: 呈现模型, 与用户进行交互
SpringMVC
- 目前最好的实现MVC设计模式的框架
-
Spring
框架的一个后续产品 -
Spring
框架的一个子模块, 二者可以很好的结合使用, 不需要整合
详解
SpringMVC核心组件
-
DispatcherServlet
: 前置控制器 -
Handler
: 处理器, 完成具体的业务逻辑 -
HandlerMapping
: 将请求映射到Handler
-
HandlerInterceptor
: 处理器拦截器 -
HandlerExecutionChain
: 处理器执行链 -
HandlerAdapter
: 处理器适配器 -
ModelAndView
: 装载模型数据和视图信息 -
ViewResolver
: 视图解析器
SpringMVC的实现流程/原理
- 客户端请求被
DispatcherServlet
接收 -
DispatcherServlet
将请求映射到Handler
- 生成
Handler
以及HandlerInterceptor
- 返回
HandlerExecutionChain(Handler + HandlerInterceptor)
-
DispatcherServlet
通过HandlerAdapter
执行Handler
- 返回一个
ModelAndView
-
DispatcherServlet
通过ViewResolver
进行解析 - 返回填充了模型数据的
View
, 响应给客户端
SpringMVC的使用
基于XML配置的使用
-
SpringMVC
基础配置 -
XML
配置Controller
,HandlerMapping
组件映射 -
XML
配置ViewResolver
组件映射 - 具体代码实现
- 配置pom.xml
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.0.0.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> </dependencies>
- 设置web.xml
<web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
- 设置SpringMVC
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置HandlerMapping, 将url请求映射到Handler--> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <!--配置mapping--> <property name="mappings"> <props> <!--配置test请求对应的handler--> <prop key="/test">testHandler</prop> </props> </property> </bean> <!--配置Handler--> <bean id="testHandler" class="com.rui.handler.MyHandler"> </bean> <!--配置视图解析器, 将逻辑视图解析为UI视图--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置前缀--> <property name="prefix" value="/" /> <!--配置后缀--> <property name="suffix" value=".jsp" /> </bean> </beans>
- 实现Controller的handleRequest方法, 拦截请求
public class MyHandler implements Controller { public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws Exception { // 装在模型数据和逻辑视图 ModelAndView modelAndView = new ModelAndView(); // 添加模型数据 modelAndView.addObject("name", "Tom"); // 添加逻辑视图, 显示show.jsp modelAndView.setViewName("show"); return modelAndView; } }
- show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page isELIgnored="false" %> <html> <head> <title>Title</title> </head> <body> ${name} </body> </html>
-
项目结构
- 访问
localhost:8080/test
即可访问到show.jsp
基于注解方式的使用
- SpringMVC基础配置
- Controller, HandlerMapping通过注解进行映射
- XML配置ViewResolver组件映射
- 具体代码实现
- 配置Spring servlet拦截器, web.xml
<web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
- 配置spring配置文件
<!--将AnnotationHandler自动扫秒进来--> <context:component-scan base-package="com.rui.handler" /> <!--配置视图解析器, 将逻辑视图解析为UI视图--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置前缀--> <property name="prefix" value="/" /> <!--配置后缀--> <property name="suffix" value=".jsp" /> </bean>
- Controller, @RequestMapping映射到jsp上
@Controller public class AnnotationHandler { /** * 业务方法: ModelAndView完成数据的传递, 视图的解析 */ @RequestMapping("/modelAndView") public ModelAndView modelAndView() { // 创建ModelAndView对象 ModelAndView modelAndView = new ModelAndView(); // 填充模型 modelAndView.addObject("name", "Tom"); // 设置逻辑视图 modelAndView.setViewName("show"); return modelAndView; } /** * 另外一种 */ @RequestMapping("/modelTest") public String ModelTest(Model model) { // 填充模型 model.addAttribute("name", "jerry"); // 设置逻辑视图 return "show"; } /** * 第三种 */ @RequestMapping("/modelMap") public String ModelMap(ModelMap modelMap) { // 填充模型 modelMap.put("name", "your baba"); return "show"; } }
- 项目的目录结构如上
SpringMVC数据绑定
-
什么是数据绑定
将HTTP请求中的参数绑定到Handler业务方法的形参.
-
SpringMVC
初始化时,RequestMappingHandlerAdapter
类会把一些默认的参数解析器添加到argumentResolvers
中。当SpringMVC
接收到请求后首先根据url查找对应的HandlerMethod
。 - 遍历
HandlerMethod
的MethodParameter
数组 - 根据
MethodParameter
的类型来查找确认使用哪个HandlerMethodArgumentResolver
,遍历所有的argumentResolvers
的supportsParameter(MethodParameter parameter)
方法。。如果返回true
,则表示查找成功,当前MethodParameter
,使用该HandlerMethodArgumentResolver
。这里确认大多都是根据参数的注解已经参数的Type
来确认。 - 解析参数,从
request
中解析出MethodParameter
对应的参数,这里解析出来的结果都是String
类型。 - 转换参数,把对应
String
转换成具体方法所需要的类型,这里就包括了基本类型、对象、List、Set、Map。
-
- 常用的数据绑定类型
- 基本数据类型
- 包装类
- 数组
- 对象
- 集合(
List
,Set
,Map
) JSON
RESTful API
RESTful风格概述
-
REST: Representational State Transfer
(表述性状态转移) -
REST
并不是一种创新技术, 它指的是一组架构约束条件和原则 - 符合
REST
的约束条件和原则的架构, 被称为RESTful架构
RESTful核心内容
- 资源与URI: URI就是资源的地址
- 资源的表述: 客户端和服务器之间传送就是资源的表述
- 状态转移: 资源在客户端发生变迁, 进入后续的状态, 即客户端获取资源以后可能对资源进行修改
RESTful架构特点
- 统一了客户端访问资源的接口
- url更加简洁, 易于理解, 便于扩展
- 有利于不同系统之间的资源共享
RESTful的四种基本操作
-
GET: 获取资源, 获取数据的时候, 跟的参数为
/参数
, 没有问号 - POST: 新建资源
- PUT: 修改资源
- DELETE: 删除资源
@GetMapping(value="/getById/{id}")
public ModelMap getById(@PathVariable(value="id") int id) {
}
SpringMVC 拦截器
- Maven中设置版本
<properties>
<spring-version>4.3.4.RELEASE</spring-version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
- 配置DispatcherServlet
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springmvc.xml
<?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"
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">
<!--自动扫秒-->
<context:component-scan base-package="com.rui" />
<!--配置视图解析器, 将逻辑视图解析为UI视图-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置前缀-->
<property name="prefix" value="/" />
<!--配置后缀-->
<property name="suffix" value=".jsp" />
</bean>
</beans>
拦截器与过滤器
-
拦截器与过滤器之间的区别
- 拦截器是使用JDK动态代理实现的, 拦截的是对应调用方法的拦截
- 过滤器是使用Filter实现的, 拦截的是request对象
SpringMVC拦截器的配置和应用
-
SpringMVC
也可以使用拦截器对请求进行拦截处理, 用户可以自定义拦截器来实现特定的功能, 自动以的拦截器必须实现HandlerInterceptor
接口-
preHandler()
: 这个方法在业务处理器处理请求之前被调用, 在该方法中对用户请求request
进行处理, 返回值为Boolean
, 返回false
不继续执行, 返回true
会继续执行 -
postHandler():
这个方法在业务处理器处理完请求后, 但是DispatcherServlet
向客户端返回响应前被调用, 在该方法中对用户请求request
进行处理 -
afterCompletion():
这个方法在DispatcherServlet
完全处理完请求后被调用, 可以在该方法中进行一些资源清理的操作. 多个拦截器的时候, 等拦截器执行完毕以后才会执行这个方法
-
- 拦截器的配置
<?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/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--自动扫秒-->
<context:component-scan base-package="com.rui" />
<!-- 拦截器的注册-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<!-- update这个方法不走拦截器 -->
<mvc:exclude-mapping path="/user/update"/>
<bean class="com.rui.Interceptor.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
<!--配置视图解析器, 将逻辑视图解析为UI视图-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置前缀-->
<property name="prefix" value="/" />
<!--配置后缀-->
<property name="suffix" value=".jsp" />
</bean>
</beans>
- 拦截器的实现
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o) throws Exception {
System.out.println("preHandler");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
System.out.println("afterCompletion");
}
}
当用户访问类似user/search
或user/search/11
接口的时候就会进入拦截器, 可以在用户进入以后进行处理登录等操作.
SpringMVC 全局异常
无SpringMVC全局异常的流程图
有SpringMVC全局异常的流程图
Spring和SpringMVC包扫描隔离
# Spring配置文件
<context:component-scan base-package="com.rui" annotation-config="true">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
# SpringMVC配置文件
<context:component-scan base-package="com.rui.controller"
use-default-filters="false"
annotation-config="true">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
代码实现
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJacksonJsonView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class ExceptionResolver implements HandlerExceptionResolver {
Logger logger = LoggerFactory.getLogger(ExceptionResolver.class);
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o, Exception e) {
logger.error("{} Exception", httpServletRequest.getRequestURI(), e);
ModelAndView modelAndView = new ModelAndView(new
MappingJacksonJsonView());
// 当使用是jackson2.x的时候后, 使用MappingJackson2JsonView
modelAndView.addObject("status", ResponseCode.ERROR.getCode());
modelAndView.addObject("msg", "接口异常");
modelAndView.addObject("data", e.toString());
return modelAndView;
}
}