一、SpringMVC的特点
SpringMVC和Struts都是MVC框架,轻量级,有入下特点:
- 是spring框架的一部分,可以方便的使用spring的其他部分
- 灵活性强,便于集成框架
- 提供前端控制器,开发者不需要写控制器部分代码
- 自动绑定用户输入,正确转换数据类型
- 内置校验器
- 支持国际化
- 支持多种视图技术(JSP、FreeMarker等)
- 使用基于XML的配置文件
二、SpringMVC的工作流程
-
SpringMVC执行流程图
- 用户通过浏览器向服务器发送请求,请求会被Spring MVC的前端控制器DispatcherServlet所拦截。
- DispatcherServlet拦截到请求后,会调用HandlerMapping处理器映射器。
- 处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器(如果有就生成)一并返回给DispatcherServlet
- DispatcherServlet会通过返回信息选择合适的HandlerAdapter(处理器适配器)。
- HandlerAdapter会调用并执行Handler(处理器),这里的处理器就是程序中编写的Controller类,也被称为后端控制器。
- Controller执行完成后,会返回一个ModelAndView对象,该对象中包含视图名或包含模型与视图名。
- HandlerAdapter将ModelAndView对象返回给DispatcherServlet。
- DispatcherServlet会根据ModelAndView对象选择一个合适的ViewResolver(视图解析器)。
- ViewResolver解析后,会向DispatcherServlet中返回具体的View(视图)。
- DispatcherServlet对View进行渲染(即将模型数据填充至视图中)。
- 视图渲染结果会返回给客户端浏览器显示。
-
前端控制器(DispatcherServlet)
- 接受用户请求,返回给用户结果
- 前端控制器是Servlet类的一个子类,包含doPost()和doGet(,DispercherServlet类主要有三类方法:
- 初始化相应处理的方法(如:initMultipartResolver())
- 响应HTTP请求的方法
- 执行处理请求逻辑的方法
-
处理映射器(HandlerMapping)和适配器(HandlerAdapter)
- 请求到处理器的映射时,允许有多个实例,如果映射成功则返回一个HandlerExecutionChain对象(包括页面控制器和拦截器)
- HandlerMapping实现类(列举两个):
- BeanNameUrlHandlerMapping:默认的映射器,根据请求的URL和Spring容器中定义的处理器Bean的name属性值进行匹配,从而在Spring容器中找到处理器的Bean实例
- SimpleUrlHandlerMapping:根据浏览器的URL匹配prop标签中的key,通过key找到对应的Controller
- 处理适配器(HandlerAdapter)允许多个实例,HandlerAdapter会把处理器包装为适配器,以支持多种类型的适配器,HandlerAdapter的实现类(列举三个):
- SimpleControllerHandlerAdapter:支持所有实现Controller接口的Handler控制器,是Controller实现类的适配器类,执行Controller类中的handleRequest方法
- HttpRequestHandlerAdapter:调用HttpRequestHandler的的handleRequest方法
- RequestMappingHandlerAdapter:
-
视图解析器(ViewResolver)
- 解析流程
- SpringMVC调用方法将目标方法返回的String、View、ModelMap或ModelAndView都转换为一个ModelAndView
- 通过视图解析器将ModelAndView对象中的View进行解析,将逻辑视图View对象解析成一个物理视图View对象
- 调用物理视图View对象的render()方法进行视图渲染,得到响应结果
- 常用的视图解析器
- ViewResolver
- AbstructCachingViewResolver
- UrlBasedViewResolver、ResourceBundleViewResolver、XmlViewResolver
- TilesViewResolver、GroovyMarkupViewResolver、FreeMarkerViewResolver、InternalResourceViewResolver
- ViewResolver链:同时调用多个视图解析器会形成一个ViewResolver链,当Controller处理器方法返回一个逻辑视图名称后,ViewResolver链会根据其中的优先级来进行处理
- 解析流程
三、SpringMVC常用注解
-
请求映射注解
-
@Controller注解:控制器Controller负责处理前端控制器分发的请求,把数据经过业务处理层处理后封装成一个Model,将该Madel返回给对应的视图View进行展示
@Controller @RequestMapping("/hello") public class liuController{ }
-
@RequestMapping注解:将HTTP请求映射到MVC和RES控制器的处理方法上
@Controller @RequestMapping("/test") public class liuController{ @RequestMapping("/hello") public String hello(){ return "hello"; } }
-
@GetMapping和@PostMapping注解:该注解将GET/POST请求映射到特定的处理方法上,是组合注解;
- @GetMapping相当于@RequestMapping(method = RequestMethod.GET)
- @PostMapping相当于@RequestMapping(method = RequestMethod.POST)
- @PutMapping相当于@RequestMapping(method = RequestMethod.PUT)
- @DeleteMapping相当于@RequestMapping(method = RequestMethod.Delete)
@Controller @RequestMapping("/user") public class liuController{ @GetMapping("findById/{id}") public String findById(@PathVariable String id){ //... return ""; } }
-
Model和ModelMap
@Controller @RequestMapping("/user") public class liuController{ @ModelAttribute public void redirectTest(Model model){ model.addAttribute("name","liu"); } @RequestMapping("hello") public String hello(Model model, ModelMap modelMap, Map map){ return "hello"; } }
-
ModelAndView:当处理器处理完请求时,会将包含模型信息和视图信息的ModelAndView对象返回,Springmvc将使用视图对模型数据进行渲染
@Controller @RequestMapping("/user") public class liuController{ @RequestMapping("/hello") public ModelAndView hello(){ ModelAndView mv = new ModelAndView(); mv.addObject("name","liu"); mv.setViewName("hello"); return mv; } }
-
-
-
参数绑定注解
-
@RequestParam注解:用于将指定请求参数赋值给方法的形参
@Controller @RequestMapping("/user") public class liuController{ @GetMapping("findById") public String findById(@Requestparam(value="id") String id){ //... return ""; } }
-
@PathVariable注解:将URL动态参数绑定到控制器处理方法的入参中
@Controller @RequestMapping("/user") public class liuController{ @GetMapping("findById/{id}") public String findById(@PathVariable String id){ //... return ""; } }
-
@RequestHeader注解:将请求的头信息数据映射到处理的方法参数上
@Controller @RequestMapping("/user") public class liuController{ @RequestMapping("requestHeader") public String handle(@RequestHeader("Accept-Encoding") String[] encoding, @RequestHeader("Accept") String[] accept){ //... return ""; } }
-
@CookieValue注解:将请求的Cookie信息映射到处理的方法参数上
@Controller @RequestMapping("/user") public class liuController{ @RequestMapping("/cookieValue") public String hello(@CookieValue("") String cookie){ //... return ""; } }
-
@ModelAttribute注解:将请求参数绑定到Model对象上
-
@SessionAtribute注解和@SessionAtrributes注解:作用在方法或方法的参数上,表示被注解的方法的返回值或被注解的参数作为Model的属性加入Model中,Spring框架将Model返回给前端;@SessionAtrributes注解可以让参数在多个请求间共享,只能声明在类上
-
@ResponseBody注解和@RequestBody注解:
- @ResponseBody注解用于将Controller方法返回的对象,通过HttpMessageConverter转换为指定格式后,写入到Response对象的Body数据区
- @RequestBody注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把想用的数据绑定到Controller方法的参数上
-
-
信息转换详解
- HttpMessageConverter
- RequestMappingHandlerAdapter
- 自定义HttpMessageConverter
四、数据绑定
-
数据绑定的步骤
- Spring MVC将ServletRequest对象传递给DataBinder。
- 将处理方法的入参对象传递给DataBinder。
- DataBinder调用ConversionService组件进行数据类型转换、数据格式化等工作,并将ServletRequest对象中的消息填充到参数对象中。
- 调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验。
- 校验完成后会生成数据绑定结果BindingResult对象,Spring MVC会将BindingResult对象中的内容赋给处理方法的相应参数。
-
简单数据绑定
-
绑定默认数据类型:默认参数类型如下:
- HttpServletRequest
- HttpServletResponse
- HttpSession
- Model/ModelMap
-
绑定简单数据类型(Integer、Short等基本数据类型)
-
绑定POJO类型(简单的java,如:User)
public calss User{ private int id; private String name; private String sex; //getter和setter //toString() }
-
绑定包装POJO(在一个POJO中包含另一个POJO)
public calss Orders{ private int order_id; private User user; //getter和setter //toString() }
-
自定义数据绑定(日期数据等特殊类型参数需要自定义)
-
Converter:将一种类型的对象转换为另一种类型的对象,需要实现Converter接口
//S表示源对象,T表示目标对象 public interface Converter(S T){ T converter(S source); }
-
Formatter:需要实现Converter接口
//源类型必须是一个String类型,T表示目标类型 public interface Formatter<T> extends Printer<T> Parser<T>{}
-
-
-
复杂数据绑定
- 绑定数组(批量删除同一数据类型):形参用数组表示
- 绑定集合(批量删除不同数据类型):先定义一个集合将要返回的数据都存在里面,然后形参用该集合表示
五、JSON数据交互
-
JSON是轻量级的数据交换格式,基于JavaScript的一个子集采用完全独立于编程语言的文本格式来存储和表示数据,基于纯文本的数据格式,有下面两种数据结构
-
对象结构
{ key1:value1, key2:value2, key3:value3 }
-
数组结构
[ value1, value2, value3
-
-
JSON的数据转换:通过HttpMessageConverter接口的实现类来完成,JSON是用spring默认的处理JSON数据的MappingJackson2HttpMessageConverter实现类来进行数据转换的
-
静态资源访问的三种配置方式
六、拦截器
-
拦截器的作用
- 相当于Servlet中的过滤器,用于拦截用户请求并作出相应的处理(权限验证、记录请求信息日志、判断用户是否登录)
-
拦截器的定义和配置
-
拦截器的定义
-
实现HandlerInterceptor接口、实现WebRequestInterceptor接口
-
继承HandlerInterceptor接口的实现类、继承WebRequestInterceptor接口的实现类
-
实现HandlerInterceptor接口的实例
public class UserInterceptor implements HandlerInterceptor{ @Override // 在控制器方法前执行,当返回值为true时,继续向下执行,当返回值为false时,中断后续的所有操作 public boolean preHandle(HttpServletRequest request, HttpServletresponse response,Object handler) throws Exeception{ return false; } //在控制器方法调用后,且解析视图之前执行,可以对请求域中的模型和视图作进一步修改 @Override public void postHandle(HttpServletRequest request, HttpServletresponse response,Object handler, ModelAndView modelAndView) throws Exeception{ } //在整个请求完成,视图渲染后执行,进行资源清理和记录日志信息等 @Override public void afteCompletion(HttpServletRequest request, HttpServletresponse response,Object handler, Exeception ex) throws Exeception{ } }
-
-
拦截器的配置
<!-- 配置拦截器 --> <mvc:interceptors> <!-- 使用bean直接拦截所有请求 --> <bean class="com.liu.x.x" /> <!-- 拦截器1 --> <mvc:interceptor> <!-- 配置拦截器作用的路径 --> <mvc:mapping path="/**" /> <!-- 配置不需要拦截器作用的路径 --> <mvc:exclude-mapping path="" /> <!-- 对匹配路径的请求才进行拦截 --> <bean class="com.liu.x.x" /> </mvc:interceptor> <!-- 拦截器2 --> <mvc:interceptor> <!-- 配置拦截器作用的路径 --> <mvc:mapping path="/**" /> <!-- 配置不需要拦截器作用的路径 --> <mvc:exclude-mapping path="" /> <!-- 对匹配路径的请求才进行拦截 --> <bean class="com.liu.x.x" /> </mvc:interceptors>
-
-
拦截器的执行流程
-
单个拦截器的执行流程
-
多个拦截器的执行流程
-
七、文件上传和下载
-
文件上传
-
配置文件上传解析器
<!-- 配置上传解析器 --> <bean id="multipartReaolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置请求编码格式 --> <property name="defaultEncoding" value="UTF-8" /> </bean>
-
前端页面
-
控制器类
@Controller public class FileUploadController{ //文件上传 @RequestMapping("/fileUpload") public String handleFormUpload(@RequestParam("name") String name, @RequestParam("uploadfile") List<MultipartFile> uploadfile, HttpServletRequest request){ //判断上传文件是否存在 if(!uploadfile.isEmpty() && uploadfile.size() >0){ //输出上传的文件 for(MultipartFile: uploadfile){ //获取文件的原始名称 String originalFilename = file.getOriginalFilename(); //设置上传文件的保存地址目录 String dirPath = request.getServletContext.getRealPath("/upload/"); File filePath = new File(dirPath); //如果保存文件的地址不存在,就先创建目录 if(!filePath.exists()){ filePath.mkdirs(); } //重命名上传文件的名称 String newFliename = name + "_" +UUID.randomUUID() + "_"+ originalFilename; try{ //文件上传到指定位置 file.TransferTo(new File(dirPath+newFilename)); }catch(Exception e){ e,printStackTrace(); return "error"; } //跳转到成功页面 return "sussess"; }else{ return "error"; } } } }
-
-
文件下载
- 文件下载的实现
- 中文名称文件下载的实现