Spring Web MVC
M : Model
V : View
C : Controller -> DispatcherServlet
Front Controller = DispatcherServlet
Application Controller = @Controller
or xx implements Controller
- Context
- ServletContextListener -> ContextLoaderListener -> Root WebApplicationContext
- DispatcherServlet -> Servlet WebApplicationContext
- Services
- @Services
- Repositories
- @Repositories
映射处理
- Servlet匹配规则
- 精确匹配
/IndexServlet
- 模糊匹配
/*.jsp
- 当前目录下的所有目录
- /匹配
/
- 当前目录
- 精确匹配
- Servlet请求映射
- Servlet URL Pattern
- Filter URL Pattern
- Spring Web MVC
- DispatcherServlet
- HandlerMapping
@RestController
=@Controller
+@ResponseBody
org.springframework.web.bind.annotation.RestController
1 | package org.springframework.web.bind.annotation; |
DispatcherServlet < FrameworkServlet < HttpServletBean < HttpServlet
- 新建项目,依赖Web
- 新建packet->controller -> 新建Controller -> RestDemoController
1 | package com.bai.springwebmvc.controller; |
浏览器访问:localhost:8080,页面显示“Hello World”。
问题及回答
Q : 为什么Controller没有映射地址却能启动起来
A : 自动装配,详情参见下面源码:org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
。此处的ServletContext path =”” or “/“,此二者等价。
Request URL = ServletContext path + @RequestMapping(“”) 或者 @GetMapping()
当前例子中,Request URL = “”+“”=“” -> RestDemoController#index
1 | package org.springframework.boot.autoconfigure.web.servlet; |
Q : 为什么访问localhost:8080可以调用到RestDemoController#index?
A : Spring MVC的处理方式是HandlerMapping自动寻找Request URL,匹配的Handler,Handler是处理的方法,当前这是一种实例。Request -> Handler -> 执行结果 -> 返回(Rest) -> 普通的文本。
HandlerMapping -> RequestMappingHandlerMapping -> @RequestMapping + Handler Mapping
补充
Spring Web MVC 的配置 Bean :org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
Spring Boot允许通过application.properties去定义配置,配置外部化。
WebMvcProperties
配置前缀:spring.mvc
@PostMapping
Post请求 @RequestMapping(method = RequestMethod.POST) Create(C)
@GetMapping
Get请求 @RequestMapping(method = RequestMethod.GET) Read(R)
@PutMapping
Put请求 @RequestMapping(method = RequestMethod.PUT) Update(R)
@DeleteMapping
Delete请求 @RequestMapping(method = RequestMethod.DELETE) Delete(D)
无HeadMapping
拦截器:HandlerInterceptor ,可以理解handler到底是什么
如何装配
在启动类(xxxApplication,@SpringBootApplication) 继承WebMvcConfigurerAdapter(此类已经逐渐被淘汰),重写addInterceptors方法,通过registry.addInterceptor方法将自定义拦截器装配。
处理顺序
preHandle(true) -> HandlerMethod(因为采用了@GetMapping,其它场景可能会有不同)执行(Method#invoke) -> postHandle -> afterCompletion
异常处理
- Servlet标准
- Spring Web MVC
- Spring Boot
理解web.xml错误页面
传统的Servlet web.xml错误页面
Servlet -> web.xml(schema -> .xsd) -> 错误页面
- 处理状态码
- 处理异常类型
- 处理服务
- 优点
- 统一处理,业界标准
- 不足
- 灵活度不够,只能定义在web.xml文件或annotation里面
Spring Web MVC 异常处理
- @ExceptionHandler
- @RestControllerAdvice=@ControllerAdvice+@ResponseBody
- @ControllerAdvice专门拦截@Controller
- 不足
- 优点
- 易于理解,尤其是全局异常处理
Spring Boot错误处理页面
- 实现
ErrorPageRegistrar
接口
- 注册ErrorPage对象
- 实现ErrorPage对象中的Path路径Web服务
- 不足
- 页面处理的路径必须笃定
- 优点
- 状态码
- 比较通用,不需要理解SpringWebMVC异常体系
- 状态码
1 | package com.bai.springwebmvc; |
视图技术
- View
- ViewResolver
- ContentNegotiatingViewResolver
- 实战
- Thymeleaf
View
org.springframework.web.servlet.View#render
1 | void render(@Nullable Map<String, ?> model, |
- 处理页面渲染的逻辑
- Velocity
- JSP
- Thymeleaf
ViewResolver
页面+解析器(resolve)
org.springframework.web.servlet.ViewResolver#resolveViewName
1 | /** |
prefix 和 suffix 在org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.View的属性内
1 | public static class View { |
Spring Boot接续完整的页面路径
spring.view.prefix + hanlerMethod return + spring.view.suffix
自动装配类:org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration
进行自动装配,html不需要在web.xml里配置
配置项类:org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties
配置项前缀:spring.thymeleaf
模板寻找前缀:spring.thymeleaf.prefix
模板寻找后缀:spring.thymeleaf.suffix
1 | package org.springframework.boot.autoconfigure.thymeleaf; |
ContentNegotiatingViewResolver
org.springframework.web.servlet.view.ContentNegotiatingViewResolver
- 用于处理多个ViewResolver
- JSP
- Velocity
- Thymeleaf
- 当所有的ViewResover配置完成时,它们的order默认值时一样的,所以先来先服务(List)
- 当它们定义自己的order,通过order来倒序排列
- ViewResolver有优先级,排序在#getCandidateViews内
- 流程
- 得到CandidateViews(List)
- 得到最匹配的View
- render
代码示例
- 添加maven依赖
1 | <!--Thymeleaf--> |
- 修改默认配置
1 | <!--resources/application.properties--> |
- 添加页面
- resources下添加directory:
thymeleaf
- 在
thymeleaf
下添加file:index.htm
- resources下添加directory:
1 |
|
- 添加controller
1 | package com.bai.springwebmvc.controller; |
- 浏览器访问localhost:8080,页面显示
??home.welcome_zh_CN??
国际化(i18N)
- Locale/LocaleContext
- LocaleContextHolder
- Spring内的对象
- 缓存context
- LocaleResolver/LocaleContextResolver
org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
代码示例
- 修改application.properties
1 | spring.messages.basename=META-INF/locale/messages |
- 在上面的文件夹下添加文件
1 | #文件路径META-INF/locale/messages/messages.properties |
1 | #文件路径META-INF/locale/messages/messages_zh_cn.properties |
- 访问localhost:8080,页面会根据浏览器的设置返回对应语言的文字
问题及回答
Q:遇到新问题如何查文档
A:在能定位错误范围的前提下,尽量不Google,找规范文档。解决问题后,读相关资料,不要为了解决问题而解决,而是要尽量扩充知识面,积累知识。
Q:怎么处理异常比较优雅
A:采用ExceptionHandler,代码层面易于理解。
1 | package com.bai.springwebmvc.controller; |