11月08, 2017

SpringMVC读书笔记

DispatcherServlet

  1. DispatcherServlet 的初始化过程中,Spring MVC会在你web应用的 WEB-INF 目录下查找一个名为[servlet-name]-servlet.xml的配置文件,并创建其中所定义的bean。如果在全局上下文中存在相同名字的bean,则它们将被新定义的同名bean覆盖。
  2. WebApplicationContext被绑定在ServletContext中.如果需要获取它,你可以通过 RequestContextUtils工具类中的静态方法来拿到这个web应用的上下文WebApplicationContext

WebApplicationContext中特殊的bean类型

bean的类型 作用
HandlerMapping 处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视 HandlerMapping 类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。当然,也存在其他的实现。
HandlerAdapter 处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得 DispatcherServlet 无需关心具体的调用细节。比方说,要调用的是一个基于注解配置的控制器,那么调用前还需要从许多注解中解析出一些相应的信息。因此, handlerAdapter 的主要任务就是对 DispatcherServlet 屏蔽这些具体的细节。
HandlerExceptionResolver 处理器异常解析器。它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码。
ViewResolver 视图解析器。它负责将一个代表逻辑视图名的字符串(String)映射到实际的视图类型 View 上。
LocaleResolver &LocaleContextResolver 地区解析器 和 地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供了支持。
ThemeResolver 主题解析器。它负责解析你web应用中可用的主题,比如,提供一些个性化定制的布局等。
MultipartResolver 解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等。
FlashMapManager FlashMap管理器。它能够存储并取回两次请求之间的 FlashMap 对象。后者可用于在请求之间传递数据,通常是在请求重定向的情境下使用。

DispatcherServlet默认bean列表

  1. 地区解析器 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
  2. 主题解析器 org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
  3. 处理器映射器 org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping, org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
  4. 处理器适配器 org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
     `org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter`,
     `org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter`
    
  5. 处理器异常解析器 org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,
     `org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver`,
     `org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver`
    
  6. 视图映射器 org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
  7. 视图解析器 org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
  8. FlashMap管理器 org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

DispatcherServlet处理流程

  1. 首先,搜索应用的上下文对象WebApplicationContext并把它作为一个属性(attribute)绑定到该请求上,以便控制器和其他组件能够使用它。属性的键名默认为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
  2. 将地区(locale)解析器绑定到请求上,以便其他组件在处理请求(渲染视图、准备数>据等)时可以获取区域相关的信息。如果你的应用不需要解析区域相关的信息,忽略它即可
  3. 将主题(theme)解析器绑定到请求上,以便其他组件(比如视图等)能够了解要渲染哪 个主题文件。同样,如果你不需要使用主题相关的特性,忽略它即可
  4. 如果你配置了multipart文件处理器,那么框架将查找该文件是不是multipart(分为多个部分连续上传)的。若是,则将该请求包装成一个 MultipartHttpServletRequest对象,以便处理链中的其他组件对它做进一步的处理。关于Spring对multipart文件传输处理的支持,读者可以参考21.10Spring的multipart(文件上传)支持一小节
  5. 为该请求查找一个合适的处理器。如果可以找到对应的处理器,则与该处理器关联的整条执行链(前处理器、后处理器、控制器等)都会被执行,以完成相应模型的准备或视 图的渲染
  6. 如果处理器返回的是一个模型(model),那么框架将渲染相应的视图。若没有返回任何模型(可能是因为前后的处理器出于某些原因拦截了请求等,比如,安全问题),则框架不会渲染任何视图,此时认为对请求的处理可能已经由处理链完成了

如果在处理请求的过程中抛出了异常,那么上下文 WebApplicationContext 对象中所定义的异常处理器将会负责捕获这些异常。通过配置你自己的异常处理器,你可以定制自己处理异常的方式。

Controller

  • 1、@Valid校验注解

JavaBean中的代码

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

Controller中的代码 备注:这里一个@Valid的参数后必须紧挨着一个BindingResult 参数,否则spring会在校验不通过时直接抛出异常

@RequestMapping(method = RequestMethod.POST)
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
  • 2、 @PathVariable从路径中取值

@PathVariable 可以被应用于所有 简单类型 的参数上,比如int、long、Date等类型。Spring会自动地帮你把参数转化成合适的类型,如果转换失败,就抛出一个TypeMismatchException。如果你需要处理其他数据类型的转换,也可以注册自己的类。若需要更详细的信息可以参考“方法参数与类型转换”一节和“定制WebDataBinder初始化过程”一节

当 @PathVariable 注解被应用于 Map 类型的参数上时,框架会使用所有URI模板变量来填充这个map。

//从url中取值
@RequestMapping(path="/owners/{ownerId}/pets/{petId}", 
                method=RequestMethod.GET)
public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    Pet pet = owner.getPet(petId);
    model.addAttribute("pet", pet);
    return "displayPet";
}

//@PathVariable 标注在 Map上时
@RequestMapping(path="/owners/{ownerId}/pets/{petId}", 
                method=RequestMethod.GET)
public String findPet(@PathVariable Map<String, String>map,Model model) {
    Owner owner = ownerService.findOwner(map.get("ownerId"));
    Pet pet = owner.getPet(map.get("petId"));
    model.addAttribute("pet", pet);
    return "displayPet";
}

// 用正则表达式匹配Url
@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
public void handle(@PathVariable String version, 
                   @PathVariable String extension) {
// 代码部分省略...
}
  • 3、 @MatrixVariable 矩阵变量 通过<mvc:annotation-driven enable-matrix-variables="true"/>开启
// GET /pets/42;q=11;r=22
@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET)
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11


}

// GET /owners/42;q=11/pets/21;q=22
@RequestMapping(path = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public void findPet(
@MatrixVariable(name="q", pathVar="ownerId") int q1,
@MatrixVariable(name="q", pathVar="petId") int q2) {
// q1 == 11
// q2 == 22
}

/** 使用Map来接收矩阵变量 */
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@RequestMapping(path = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
public void findPet(
@MatrixVariable Map<String, String> matrixVars,
@MatrixVariable(pathVar="petId") Map<String, String> petMatrixVars) {
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 11, "s" : 23]
}
  • 4、@ModelAttribute注解

    注解在方法上的 @ModelAttribute 说明了方法的作用是用于添加一个或多个属性到model上。这样的方法能接受与 @RequestMapping 注解相同的参数类型,只不过不能直接被映射到具体的请求上。在同一个控制器中,注解了@ModelAttribute的方法实际上会在@RequestMapping 方法之前被调用

// Add one attribute
// The return value of the method is added to the model under the name "account"
// You can customize the name via @ModelAttribute("myAccount")
@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountManager.findAccount(number);
}
// Add multiple attributes
@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
model.addAttribute(accountManager.findAccount(number));
// add more ...
}

本文链接:https://www.qiangshuidiyu.xin/post/2017-11-08-02.html

-- EOF --

Comments