位于 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 方法完成视图渲染跳转 复制代码