当前位置: 首页 > news >正文

Spring 03 Web springMVC

Springboot 常用 Spring MVC 实现 web 服务。

Spring MVC 请求处理流程

《Spring 实战第四版》
图片来自《Spring 实战第四版》

浏览器请求首先被交给 DispatcherServlet 前端控制器。
DispatcherServlet 查询处理器映射以决定将请求发送给哪个控制器。控制器处理业务逻辑后,向 DispatcherServlet 返回处理结果(被称为模型)和逻辑视图名。DispatcherServlet 使用视图解析器为逻辑视图名匹配特定视图。最后视图渲染结果,交给响应对象返回浏览器。

MVC 启动

Springboot 启动 Spring MVC 时,动态加载\org\springframework\web\servlet\DispatcherServlet.properties文件定义的组件。

控制器

@Controller 注解定义控制器。它与 @Component 注解功能相同,因此Spring 会创建 MyController bean。
@RequestMapping 注解定义请求路径(value 属性)和控制器方法(hello())的映射关系。映射关系被存储到HandlerMapping(处理器映射)对象。DispatcherServlet 将请求发送给处理器映射,处理器映射返回的不是 Controller,而是 HandlerExecutionChain 对象。

@Controller
public class MyController {@RequestMapping(value = "/", method=GET)public String hello() {return "hello";}
}

HandlerExecutionChain 对象包含处理器 handler 和拦截器 interceptorList 。处理器是对控制器 controller 的封装。拦截器增强处理器功能。

public class HandlerExecutionChain {private final Object handler;private final List<HandlerInterceptor> interceptorList = new ArrayList<>();

HandlerAdapter 实现类执行 HandlerExecutionChain 对象的内容。即执行控制器并返回结果。
控制器返回的结果被称为模型。视图解析器根据逻辑视图名称定位视图,视图渲染模型给响应体。前后端分离场景下一般用 json 格式响应体,此时不需要视图解析器和视图。

@RequestMapping

@RequestMapping 注解有主要有两个参数,一个是路径 value,一个是请求方法 method。它的简化版本 @GetMapping 注解表示 get 请求类型,@PostMapping 注解表示 Post 请求类型。

获取控制器参数

@RequestParam 注解可以定义HTTP参数和方法参数的映射关系。

@RequestMapping(value = "/param", method=GET)
public String param(@RequestParam("user") String user,@RequestParam("age") int age) {return service(user, age);
}

@RequestBody 注解可以将 json 参数转换为对应 java 对象。

@RequestMapping(value = "/param", method=GET)
public String param(@RequestBody User user) {return service(user);
}

@PathVariable 注解可以获取路径参数。Restful 风格要求用路径,而不是用参数表示资源。

@RequestMapping(value = "/param/{id}", method=GET)
public String param(@PathVariable("id") String id) {return service(id);
}

@DataTimeFormat 注解和 @NumberFormat 注解可以定义格式化参数。

自定义获取控制器参数的规则

SpringMVC 通过 WebDataBinder 机制来获取参数。它解析 HTTP 请求上下文,转换参数并且提供验证功能。转换参数的接口有三个:Converter,Formatter 和 GenericConverter。第一个是转换类型,第二个是转换格式,第三个是转换数组。
SpringMVC 将三个接口的默认实现类注册到注册机,这就是大部分类型转换无需开发者开发的原因。
我们可以定义自己的转换器,只需实现接口,SpringMVC自动注册到注册机。

@Component
public class MyConvrter implements Converter<String, User> {@Overridepublic User convert(String str) {...}
}

参数验证

SpringMVC 支持参数验证。通过 @Valid 注解启动验证机制,通过 @NotNull, @Max, @Range, @Email 等注解验证字段。

用户也可以在 WebDataBinder 注册验证器自定义验证机制。

public class MyValidator implements Validator {// 指定验证类型@Overridepublic boolean supports(Class<?> clazz) {return clazz.equals(User.class);}// 执行验证方法@Overridepublic void validate(Object target, Errors erros) {...}
}

MyValidator 类没有 @Component 注解。在控制器类用 @InitBinder 注解注册验证类。

@RequestMapping("/user")
public class UserController {@InitBinderpublic void initBinder(WebDataBinder binder) {binder.setValidator(new MyValidator()); // 绑定验证器}@GetMapping("/validate")public Map<String, Object> validator(@Valid User user, Errors erros) {if (errors.hasErrors()) {// 没通过验证,返回错误结果}}
}

视图

SpringMVC 视图分为逻辑视图和非逻辑视图。逻辑视图需要视图解析器进一步定位视图,比如 JSP。非逻辑视图不需定位,直接渲染,比如 json。

拦截器

拦截器用于拦截处理器,增强处理器功能。preHandle 方法在处理器执行前执行,postHandle 方法在处理器执行后执行,afterCompletion 方法在处理器完成且视图渲染后后执行。

public class MyInterceptor extends HandlerInterceptor {@Overridepublic boolean preHandle(HttpServltRequest request, HttpServletResponse response, Object handler) {...}@Overridepublic boolean postHandle(HttpServltRequest request, HttpServletResponse response, Object handler) {...}@Overridepublic boolean afterCompletion(HttpServltRequest request, HttpServletResponse response, Object handler) {...}
}

开发拦截器后需要注册拦截器。

@Configuration
public class MyApplication implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {InterceptorRegistry ir = registry.addInterceptor(new MyInterceptor());ir.addPathPatterns("/user/*");}
}

多个拦截器按照责任链模式装配。对于 preHandle 方法,先注册先执行。对于 postHandle 和 afterCompletion 方法,先注册后执行。如果某个拦截器的 preHandle 为 false,后续的 preHandle 和 postHandle 都不会执行。

http://www.dtcms.com/a/312522.html

相关文章:

  • 如何查看SoC线程的栈起始地址及大小
  • leecode2962 统计最大元素出现至少K次的子数组
  • 第12届蓝桥杯Scratch图形化【省赛】初级组 2021年4月24日
  • 从Docker衔接到导入黑马商城以及前端登录显示用户或密码错误的相关总结(个人理解,仅供参考)
  • 从传热学基础到有限元弱形式推导:拆解热传导问题Matlab有限元离散核心
  • C++ 信号处理
  • 【AI编程工具IDE/CLI/插件专栏】-国外IDE与Cursor能力对比
  • 【从零开始速通C语言1】 - 汇编语言1
  • 西门子PLC基础指令4:输出指令、立即输出指令
  • 信用衍生工具
  • 《基于特征融合的小目标检测方法及其在医学影像领域的应用研究》论文解析
  • Coin Combinations I(Dynamic Programming)
  • ThinkPHP 与 Vue.js 结合的全栈开发模式
  • 多线程(三)-线程安全原因与解决
  • Day26-二叉树的最小深度
  • 【软考中级网络工程师】知识点之 RIP 协议
  • C++ 之 【模拟实现 优先级队列】
  • SQL 地理空间原理与实现
  • slice() 和 splice()
  • 信创及一次ORACLE到OB的信创迁移
  • 自由学习记录(76)
  • Python 的标准库 bisect 模块
  • 源码交易平台排行榜
  • 机器学习 决策树基本介绍
  • Mysql的MVCC是什么
  • HCIE-Datacom题库_07_设备【道题】
  • 《深入解析 Python 的 `*args` 和 `**kwargs`:从基础使用到高级应用》
  • 【数据结构】哈希表实现
  • 网关和BFF是如何演化的
  • uniapp 跨端开发