web场景1.自动配置1.整合web场景2.引入 autoconfigure 功能WebMvcConfigurer接口1.参数解析器是什么为什么要解析请求传进来的参数跟controller对应参数解析器 HandlerMethodArgumentResolver一句话SpringMVC 的工具负责把前端发来的请求数据url 参数、json 请求体转换成 Controller 方法上的 Java 参数对象。原理 前端发请求数据是字符串 /json 流。但是 Controller 方法写的是User user、Integer id这种 Java 类型。 Spring 不知道怎么把 http 请求里的数据塞到你方法的参数上参数解析器就是干这个映射转换的。RequestBody就是由对应的参数解析器读取 json 请求体转成 User 对象为什么要做 HTTP 传输只有字符串Java 是强类型。必须有解析器做转换、绑定否则你 Controller 拿不到参数。 你还可以自定义参数解析器比如自动把 token 转换成当前登录用户对象。2.跨域是什么意思跨域 浏览器的同源安全策略限制同源协议 域名 端口号三个全部一样才叫同源。只要有一个不一样就是跨域。例子 前端页面http://localhost:8080去请求后端接口http://localhost:8888端口不一样 → 跨域。 浏览器会拦截这个响应不让前端拿到返回数据请求其实已经发给后端了是浏览器拦住返回结果。为什么会有跨域浏览器安全机制防止恶意网站偷取别的网站 cookie、数据。 解决方式后端配置 CORS就是 WebMvcConfigurer 里面addCorsMappings告诉浏览器允许这个前端域名访问。⚠️ 重点跨域限制只存在浏览器端Postman、后端代码调用接口不存在跨域。Cookie服务器发给浏览器浏览器自动保存在本地的一小段文本信息。 之后每次访问这个网站浏览器会自动带上 Cookie 发给后端不需要前端手动写代码。举个生活化例子 你登录淘宝登录成功淘宝后端给你的浏览器下发一个 Cookie内容类似userId1001。 以后你每次打开淘宝页面浏览器自动把这个 Cookie 发给淘宝服务器。后端一看 Cookie就知道哦是这个用户不用重复登录。特点存在浏览器本地保存在电脑访问对应网站自动随请求带上有过期时间可以后端设置3.为什么webmvcconfigurer接口里面含有拦截器拦截器不是属于servlet的规范吗❌ 误区纠正拦截器HandlerInterceptor不属于 Servlet 规范Servlet 规范只有Filter 过滤器FilterServlet 原生Tomcat 定义和 Spring 无关。HandlerInterceptor 拦截器SpringMVC 自己造的组件不属于 Servlet只在 SpringMVC 框架内部生效。那WebMvcConfigurer#addInterceptors()是干嘛的 WebMvcConfigurer 是 SpringMVC 的扩展配置接口用来注册、配置你写好的拦截器交给 SpringMVC 管理。 不是说拦截器写在这个接口里面而是通过这个方法注册拦截器。一句话总结 拦截器是 SpringMVC 的不是 ServletWebMvcConfigurer 提供方法把拦截器注册进 SpringMVC。4.在springmvc里面有一个配置是打开视图控制器的要是不开视图控制器然后想要跳转HTML页面是不是要写很多controller视图控制器addViewControllers()就是你截图 WebMvcConfigurer 里的方法。 作用不用写 Controller 方法直接绑定 URL → 页面。举例子Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController(/login).setViewName(login.html); }访问/login直接跳 login 页面不用写 Controller 类。 如果不使用 addViewControllers 想跳转页面就必须写 Controller 方法GetMapping(/login) public String toLogin(){ return login.html; }如果页面很多就要写一堆这种空方法非常重复。5.异步支持是啥普通同步请求 浏览器发请求 → Tomcat 线程卡住一直占用这个线程直到业务处理完返回结果。 Tomcat 线程池数量有限如果慢请求很多线程会被占满新请求进不来服务卡死。异步请求 请求进来Tomcat 工作线程立刻释放还给线程池。业务逻辑丢到另外一个自定义异步线程去跑。等业务处理完成再返回给浏览器。configureAsyncSupport就是 WebMvcConfigurer 里面用来配置异步请求的线程池、超时时间。适用场景长耗时接口比如导出大文件、远程调用很慢的第三方接口。简单理解 同步服务员一直守着你这桌等菜上完才能接待下一桌。 异步服务员先离开去接待别的客人后厨做好菜再通知服务员送过来。静态资源映射方法Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug(Default resource handling disabled); return; } // 规则1webjars静态资源映射 addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(), classpath:/META-INF/resources/webjars/); // 规则2通用静态资源映射 addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) - { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (this.servletContext ! null) { ServletContextResource resource new ServletContextResource(this.servletContext, /); registration.addResourceLocations(resource); } }); }规则静态资源静态资源映射静态资源缓存3.欢迎页4.Favicon在静态资源目录下找favicon.ico5.缓存实验自定义静态资源规则静态资源目录 和 静态资源缓存策略访问直接写wj/什么 然后访问就行不用写全称去找容器中只要有一个WebMvcConfigurer就行法1法2SpringMVC 启动时寻找容器中所有 WebMvcConfigurer 类型的 Bean回调里面的配置方法完成 MVC 自定义配置。因为de那个类它是springmvc原生的所以不能与SpringBoot融合所以不能读yml只能通过enable那个子类继承重写遍历然后利用 webmvcProperties 将配置给到mvc组件你WebConfig implements WebMvcConfigurer重写addResourceHandlers写好添加资源映射的代码Spring 把 WebConfig 放进 IOC 容器De 通过 Autowired 收集到 ListWebMvcConfigurer拿到你的 WebConfigMVC 底层启动调用 De 的 addResourceHandlers (registry)De for 循环c.addResourceHandlers(registry)执行你写的代码 → 往 registry 注册规则MVC 拿 registry 里面全部规则正式生效3.路径匹配模式转换不能在路径中间加双**spring.mvc.pathmatch.matching-strategypath_pattern_parser使用默认的路径的匹配功能就行由PathPatternParser如果路径中间需要有双⭐那就换成ant风格内容协商第三方发请求想要的数据不一样假如接口多不能只用请求头/person那种请求所以说很麻烦用一套系统如何适配多种多端内容适配1.默认规则请求头默认开启2.效果演示引入转换为xml格式的依赖 导包 -JacksonXmlRootElement标注解在根标签例如Person自定义内容返回1.增加yaml返回支持1. 增加 yaml 返回支持导入依赖xmldependency groupIdcom.fasterxml.jackson.dataformat/groupId artifactIdjackson-dataformat-yaml/artifactId /dependency编写配置propertiesspring.mvc.contentnegotiation.media-types.yamltext/yaml增加HttpMessageConverter组件专门把对象写成yaml格式2.思考如何增加其他3.内容协商原理 HttpMessageConverter定制 HttpMessageConverter 来适配多端内容 协商编写webMvcconfigurer提供的 configureMessageConverte来实现多端内容协商1.ResponseBody2.webMvcconfigurer提供几种默认httpmessageconverters那为什么ObjectMapper能写出来yaml 我给你拆得清清楚楚一句话先点明 ObjectMapper 本身不是只能写 JSON它只是一个「序列化调度外壳」真正决定输出是 JSON 还是 YAML 的是传给它的 Factory。 1. 两个 Factory JsonFactoryJackson 默认的。负责生成 JSON 的字节 YAMLFactory来自 jackson-dataformat-yaml负责生成 YAML 的字节 java 运行 // JSON版本默认 ObjectMapper jsonMapper new ObjectMapper(new JsonFactory()); // YAML版本 ObjectMapper yamlMapper new ObjectMapper(new YAMLFactory()); ObjectMapper 的代码不用改writeValueAsString() 这个方法一模一样。 ObjectMapper 只负责遍历你的 Java 对象、读取字段、调用 Factory 去输出字符。 Factory 才知道语法规则什么时候加大括号{}、什么时候加冒号、换行yaml。 你可以这么理解 ObjectMapper 一个通用打印机 JsonFactory JSON 墨盒打出来是 JSON 格式 YAMLFactory YAML 墨盒打出来是 YAML 格式 打印机本身不变换墨盒输出格式就变了。 2. 重点ObjectMapper 不懂 yaml 语法 ObjectMapper 完全不知道 yaml 长啥样 是 YAMLFactory YAMLGenerator 里面写好了 yaml 的格式规则 用 : 分隔 key value 缩进表示层级 开头可选 --- 这些逻辑全在 YAMLFactory 里面。 ObjectMapper 只负责把「对象里面有哪些字段、值是多少」交给这个 Factory。 3. 和 HTTP、Content-Type 分开承接刚才说的 ⚠️ 这个序列化和 HTTP 没有半点关系 你用 YAMLFactory 得到 yaml 字符串只是一段文本 yaml name: 小明 age: 18 ObjectMapper YAMLFactory 只负责生产这段文字。 至于 HTTP 响应头写不写 Content-Type: application/yaml是 HttpMessageConverter 的事情和它俩无关。 4. 延伸还能换别的 Factory jackson 还有别的扩展 CBORFactory二进制格式 CBOR SmileFactory另一种二进制 它们全都可以丢给 ObjectMapper一套 API 通用。 这就是 Jackson 的设计API 统一格式由底层 Factory 插拔切换 极简一句话总结 ObjectMapper 是通用框架不绑定 JSON 传入不同的 Factory就切换成不同格式 YAMLFactory 里面内置 yaml 语法规则所以它就能输出 yaml。 要不要我给你对比一下同一个 User 对象JsonFactory 和 YAMLFactory 输出结果 代码里ObjectMapper怎么跟工厂联合的 先看源码构造方法 java 运行 // ObjectMapper 有一个构造接收 JsonFactory父类YAMLFactory 是它的子类 public ObjectMapper(JsonFactory factory) { this(factory, null, null); } 类继承关系 YAMLFactory extends JsonFactory 所以可以直接传给 ObjectMapper。 1. 联合的代码最简单写法 java 运行 // 1. 先造工厂YAML工厂 JsonFactory factory new YAMLFactory(); // 2. 把工厂传给ObjectMapper绑定在一起 ObjectMapper mapper new ObjectMapper(factory); User user new User(); user.setName(张三); // 3. 调用writeValueAsString String yaml mapper.writeValueAsString(user); System.out.println(yaml); 2. 内部到底怎么联动核心流程 当你调用 mapper.writeValueAsString(user) 的时候内部步骤 ObjectMapper 拿到你的 Java 对象开始反射拿到类、字段、值 ObjectMapper 去找自己持有的那个 JsonFactory就是你传进来的 YAMLFactory 调用 factory.createGenerator() 创建一个 Generator生成器 JsonFactory → JsonGenerator生成 json 符号{ } , : YAMLFactory → YAMLGenerator生成 yaml 符号换行、缩进、: ObjectMapper 把字段名、字段值一句一句丢给 Generator 比如告诉生成器key 是 namevalue 是张三 Generator 按照自己格式的语法拼出文本 最后返回拼好的字符串 ✅ 关键点 ObjectMapper 只负责【解析对象、遍历属性】 Generator 负责【按格式输出字符】 Factory 负责【生产对应的 Generator】 画图理解调用链 plaintext mapper.writeValueAsString(对象) ↓ ObjectMapper反射拿字段 ↓ this._factory.createGenerator() ↓ YAMLFactory 造出 YAMLGenerator ↓ ObjectMapper 循环调用 generator.writeFieldName / writeString ↓ YAMLGenerator 输出 yaml缩进、冒号、换行 3. 对比默认 JSON 版本 java 运行 // 默认无参构造底层自动 new JsonFactory() ObjectMapper jsonMapper new ObjectMapper(); // 等价于 ObjectMapper jsonMapper new ObjectMapper(new JsonFactory()); 4. 你还可以提前给工厂配置再传给 Mapper java 运行 // 先配置工厂 YAMLFactory yamlFactory new YAMLFactory() .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); // 再绑定 ObjectMapper mapper new ObjectMapper(yamlFactory); 工厂的配置会被它产出的 Generator 继承。 5. 一句话总结联合关系 ObjectMapper 持有一个 JsonFactory 的成员变量创建 mapper 的时候把工厂传进去两者就绑定了。序列化的时候 mapper 调用这个工厂来产出对应的 Generator由 Generator 输出对应格式文本。 补充区分别混 Factory生产 Generator Generator真正输出符号json /yaml 语法 ObjectMapper调度反射读取 Java 对象的数据喂给 Generator 要不要我把这一套套进之前说的 HttpMessageConverter写一个返回 YAML 的消息转换器完整代码 YAMLFactory怎么传的 1、最简单直接传核心写法 YAMLFactory 是 JsonFactory 的子类而 ObjectMapper 的构造方法接收 JsonFactory所以直接把 new YAMLFactory() 塞进去就行 java 运行 // 第一步创建YAML工厂 YAMLFactory yamlFactory new YAMLFactory(); // 第二步传给ObjectMapper的构造方法绑定 ObjectMapper mapper new ObjectMapper(yamlFactory); 等价简写一行 java 运行 ObjectMapper mapper new ObjectMapper(new YAMLFactory()); 底层源码 java 运行 public ObjectMapper(JsonFactory factory) { this(factory, null, null); } 因为 YAMLFactory extends JsonFactory符合参数类型编译通过。 2、带配置再传递常用关掉 yaml 开头的 --- 先配置工厂再传给 mapper java 运行 // 先new工厂设置特性 YAMLFactory yamlFactory new YAMLFactory() // 关闭yaml默认的 --- 文档标记 .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); // 把配置好的工厂传进去 ObjectMapper mapper new ObjectMapper(yamlFactory); 3、❌ 错误写法不能后面 set这个坑很多人踩 ObjectMapper 没有 setFactory 方法 工厂只能在构造的时候传一旦 mapper 创建完成工厂就固定了不能中途替换。 java 运行 // 不行没有这个方法 mapper.setFactory(new YAMLFactory()); 想要换格式只能重新 new 一个 ObjectMapper传入新工厂。 4、传进去之后内部怎么存的 ObjectMapper 内部有一个成员变量 java 运行 protected final JsonFactory _jsonFactory; 你传进去的 YAMLFactory就赋值给这个 _jsonFactory。 后面调用 writeValueAsString 的时候mapper 就拿这个 _jsonFactory 去创建 YAMLGenerator。 5、对比默认 JSON 的情况 java 运行 // 无参构造底层自动 new JsonFactory() ObjectMapper jsonMapper new ObjectMapper(); // 等价 ObjectMapper jsonMapper new ObjectMapper(new JsonFactory()); 一句话总结 YAMLFactory 在 new ObjectMapper 的时候作为构造参数传进去工厂一旦传入绑定就不能修改。.3.http写法webconfig重写配置文件4.WebMvcConfiguartionSupport提供了很多默认设置判断系统中是否有相应的类如果有就加入相应的HttpMessageConverter
阅读完成 · 觉得有帮助?