位于 Spring 架构图中的 Web 模块,本质上是对 servlet 的封装
DemoController.java
/**
* 对原生servlet api的支持
* url:/demo/handle02?id=1
* 如果要在SpringMVC中使用servlet原生对象,直接在Handler方法形参中声明使用即可
*/
@RequestMapping("/handle02")
public ModelAndView handle02(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
String id = request.getParameter("id");
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
复制代码
success.jsp
<%@ page contentType="text/html; charset=utf-8" language="java" %>
<html>
<head>
<title>Success</title>
</head>
<body>
跳转成功!服务器时间:${date}
</body>
</html>
复制代码
springmvc.xml
<!--配置springmvc的视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
复制代码
/*
* SpringMVC 接收简单数据类型参数
* url:/demo/handle03?id=1
* 注意:接收简单数据类型参数,直接在handler方法的形参中声明即可,框架会取出参数值然后绑定到对应参数上
* 要求:传递的参数名和声明的形参名称保持一致
*/
@RequestMapping("/handle03")
public ModelAndView handle03(@RequestParam("ids") Integer id, Boolean flag) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
复制代码
/*
* SpringMVC接收pojo类型参数
* url:/demo/handle04?id=1&username=zhangsan
* 接收pojo类型参数,直接形参声明即可,类型就是Pojo的类型,形参名无所谓
* 但是要求传递的参数名必须和Pojo的属性名保持一致
*/
@RequestMapping("/handle04")
public ModelAndView handle04(User user) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
复制代码
/**
* SpringMVC接收pojo包装类型参数
* url:/demo/handle05?user.id=1&user.username=zhangsan
* 不管包装Pojo与否,它首先是一个pojo,那么就可以按照上述pojo的要求来
* 1、绑定时候直接形参声明即可
* 2、传参参数名和pojo属性保持一致,如果不能够定位数据项,那么通过属性名 + "." 的方式进一步锁定数据
*/
@RequestMapping("/handle05")
public ModelAndView handle05(QueryVo queryVo) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
复制代码
需要配置自定义类型转换器,实现Converter接口
springmvc.xml
<!--自动注册最合适的处理器映射器,处理器适配器(调用handler方法)-->
<mvc:annotation-driven conversion-service="conversionServiceBean"/>
<!--注册自定义类型转换器-->
<bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.lagou.edu.converter.DateConverter"></bean>
</set>
</property>
</bean>
复制代码
DemoController.java
/**
* 绑定日期类型参数
* 定义一个 SpringMVC 的类型转换器接口,扩展实现接口接口,注册你的实现
*/
@RequestMapping("/handle06")
public ModelAndView handle06(Date birthday) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
复制代码
之前
http://localhost:8080/user/queryUserById_action?id=3
之后
http://localhost:8080/user/3
get(查询),post(增加),put(更新),delete(删除)
先锁定资源,再根据请求方式不同决定操作
直观体验:传递参数方式的变化,参数可以在 uri 中
/*
* restful get
* url: /demo/handle/15
*/
@RequestMapping(value = "/handle/{id}", method = {RequestMethod.GET})
public ModelAndView handleGet(@PathVariable("id") Integer id) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
/*
* restful post
* url: /demo/handle
*/
@RequestMapping(value = "/handle", method = {RequestMethod.POST})
public ModelAndView handlePost(String username) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
/*
* restful put
* url: /demo/handle/15/lisi
*/
@RequestMapping(value = "/handle/{id}/{name}", method = {RequestMethod.PUT})
public ModelAndView handlePut(@PathVariable("id") Integer id, @PathVariable("name") String username) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
/*
* restful delete
* url: /demo/handle/15
*/
@RequestMapping(value = "/handle/{id}", method = {RequestMethod.DELETE})
public ModelAndView handleDelete(@PathVariable("id") Integer id) {
Date date = new Date();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("date", date);
modelAndView.setViewName("success");
return modelAndView;
}
复制代码
引入 Jackson 依赖
将 Handler 方法返回的对象转换为指定的格式之后,写入到 response 对象的 body 区,通常用来返回 JSON 数据或者是XML数据。在使用此注解之后不会再走视图处理器,而是直接将数据写入到输出流中,他的效果等同于通过 response 对象输出指定格式的数据。
@RequestMapping("/handle07")
// 添加@ResponseBody之后,不再走视图解析器那个流程,而是等同于response直接输出数据
@ResponseBody
public User handle07(@RequestBody User user) {
// 业务逻辑处理,修改name为张三丰
user.setName("张三丰");
return user;
}
复制代码
| 方法 | 操作 |
|---|---|
| CustomInterceptor::preHandle | 拦截,若返回 true 则放行 |
| HandlerAdaptor::handle | 处理器适配器处理请求 |
| CustomInterceptor::postHandle | 拦截 |
| DispatcherServlet::render | 前端控制器渲染视图 |
| CustomInterceptor::afterCompletion | 拦截 |
| 方法 | 操作 |
|---|---|
| Interceptor1::preHandle | 拦截器1进行拦截 |
| Interceptor2::preHandle | 拦截器2进行拦截 |
| HandlerAdaptor::handle | 处理器适配器处理请求 |
| Interceptor2::postHandle | 拦截器2进行拦截 |
| Interceptor1::postHandle | 拦截器1进行拦截 |
| DispatcherServlet::render | 前端控制器渲染视图 |
| Interceptor2::afterCompletion | 拦截器2进行拦截 |
| Interceptor1::afterCompletion | 拦截器1进行拦截 |
实现 HandlerInterceptor 接口
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 权限校验
}
}
复制代码
配置MultipartResolver,id固定为multipartResolver
<!--多元素解析器,id固定为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传文件大小上限,单位是字节,-1代表没有限制也是默认的-->
<property name="maxUploadSize" value="5000000"/>
</bean>
复制代码
@ControllerAdvice
@ExceptionHandler
// 可以让我们优雅的捕获所有Controller对象handler方法抛出的异常
@ControllerAdvice
public class GlobalExceptionResolver {
@ExceptionHandler(ArithmeticException.class)
public ModelAndView handle(ArithmeticException exception, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", exception.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
复制代码
DispatcherServelt extends FrameworkServlet extends HttpServletBean extends HttpServlet
FrameworkServlet 的 doGet 和 doPost 调用 doService 抽象方法
DispatcherServlet 的 doService 调用 doDispatch 方法
核心方法为 doDispatch
SpringMVC处理请求的流程即为 DispatcherServlet::doDispatch 方法的执行过程
1. 调用getHandler()获取到能够处理当前请求的执行链 HandlerExecutionChain(Handler + 拦截器) 2. 调用getHandlerAdapter();获取能够执行1 中 Handler 的适配器 3. 适配器调用 Handler 执行 ha.handle(总会返回一个ModelAndView对象) 4. 调用 processDispatchResult 方法完成视图渲染跳转 复制代码