Spring Boot核心技术之Rest映射以及源码的分析

该博客主要是Rest映射以及源码的分析,主要是思路的学习。SpringBoot版本:2.4.9

环境的搭建

主要分两部分:

Index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user" method="get">
<input value="REST-GET提交" type="submit" />
</form> <form action="/user" method="post">
<input value="REST-POST提交" type="submit" />
</form> <form action="/user" method="delete">
<input value="REST-DELETE 提交" type="submit"/>
</form> <form action="/user" method="put">
<input value="REST-PUT提交"type="submit" />
</form> </body>
</html>

controller

package com.xbhong.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*; @RestController
public class myContro {
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
} // @PostMapping("/user")
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
} @RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){
return "PUT-张三";
} @RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){
return "DELETE-张三";
}
}

测试功能是否可用:

观察效果:

可以看到最后两个请求都变成Get的请求了。由此我们可以引出来如下问题:

  1. 为什么不同的请求会出现相同的结果
  2. 怎么实现的才能完成我们的功能

后面的文章就是围绕上述的问题进行展开的。

解决问题:

像之前的SpringMVC中的表单请求通过HiddenHttpMethodFilter实现的,这样我们查一下在SpringBoot中是怎么样的。

默认双击Shift键,输入WebMvcAutoConfiguration这个类

找到默认配置的过滤器:

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}

通过OrderedHiddenHttpMethodFilter进入父类HiddenHttpMethodFilter:

在使用之前,我们需要将后两个的请求方式改写成post方式,并且需要在请求的时候传入一个_method方法(设置隐藏域);

<form action="/user" method="post">
<input name="_method" type="hidden" value="DELETE"/>
<input value="REST-DELETE 提交" type="submit"/>
</form> <form action="/user" method="post">
<input name="_method" type="hidden" value="PUT" />
<input value="REST-PUT提交"type="submit" />
</form>

为什么要这样设置呢?我们到HiddenHttpMethodFilter中看下。

流程:

  1. 第一步保存了传入的请求
  2. 当该请求时post,并且请求没有异常,才能进入下面方法,不是Post请求将直接通过过滤器链放行。
  3. 获取请求中的参数(this.methodParam)
  4. DEFAULT_METHOD_PARAM = _method获得(作为真正的请求方式)

然后再测试,发现还是没有实现。

我再回到WebMvcConfiguration中:

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}

首先该类存在于容器中。

@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)

当容器中不存在HiddenHttpMethodFilter这个类的时候,下面内容开启(条件装配);

@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)

表示:绑定的配置文件中:spring.mvc.hiddenmethod.filter名字为enable是默认不开启的(后续版本可能开启)。这样我们就找到了问题的所在。

所以我们需要在配置文件中配置(两种方法都可以)。

yaml:

spring:
mvc:
hiddenmethod:
filter:
enabled: true

properties:

spring.mvc.hiddenmethod.filter.enabled=true

重启项目:成功解决。

源码分析:

主要是分析doFilterInternal:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { HttpServletRequest requestToUse = request; if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
} filterChain.doFilter(requestToUse, response);
}
  • 表单提交会带上_method=PUT

  • 请求过来被HiddenHttpMethodFilter拦截

  • 请求是否正常,并且是POST

  • 获取到_method的值。

  • 兼容以下请求;PUT.DELETE.PATCH

    当方法走到上述代码11行时,进入ALLOWED_METHODS:

    private static final List<String> ALLOWED_METHODS =
    Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
    HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));

    如果请求里的参数在ALLOWED_METHODS存在,则执行下面代码。

  • 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。

    进入HttpMethodRequestWrapper对象中,向上找父类。本质还是HttpServletRequest

    由下面代码:

    private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
    
        private final String method;
    
        public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
    super(request);
    this.method = method;
    } @Override
    public String getMethod() {
    return this.method;
    }
    }

    可知,接收到前面的请求封装为HttpMethodRequestWrapper返回。

  • 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。

部分补充:

由于源码中规则:将获得请求中的参数无条件的以英文格式转完成大写,所以前端的value="PUT"value的值大小写无影响。

String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);

Rest使用客户端工具,

  • 如PostMan直接发送Put、delete等方式请求,无需Filter。

参考文献:

B站尚硅谷

结束:

如果你看到这里或者正好对你有所帮助,希望能点个关注或者推荐,感谢;

有错误的地方,欢迎在评论指出,作者看到会进行修改。

Spring Boot核心技术之Rest映射以及源码的分析的更多相关文章

  1. 快速开发架构Spring Boot 从入门到精通 附源码

    导读 篇幅较长,干货十足,阅读需花费点时间.珍惜原创,转载请注明出处,谢谢! Spring Boot基础 Spring Boot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计 ...

  2. Maven 搭建spring boot多模块项目(附源码),亲测可以,感谢原创

    原创地址:https://segmentfault.com/a/1190000005020589 我的DEMO码云地址,持续添加新功能: https://gitee.com/itbase/Spring ...

  3. Spring Boot 整合单机websocket(附github源码)

    websocket 概念 websocket 是一个通信协议,通过单个 TCP 连接提供全双工通信.websocket 连接成功后,服务端和客户可以进行双向通信.不同于 http 通信协议需要每次由客 ...

  4. Spring之SpringMVC前端控制器DispatcherServlet(源码)分析

    1.DispatcherServlet作用说明 DispatcherServlet提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得 ...

  5. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  6. 微服务架构 | *2.3 Spring Cloud 启动及加载配置文件源码分析(以 Nacos 为例)

    目录 前言 1. Spring Cloud 什么时候加载配置文件 2. 准备 Environment 配置环境 2.1 配置 Environment 环境 SpringApplication.prep ...

  7. Spring中AOP相关的API及源码解析

    Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring ...

  8. Spring Ioc源码分析系列--Ioc源码入口分析

    Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...

  9. DispatcherServlet源码注解分析

    DispatcherServlet的介绍与工作流程 DispatcherServlet是SpringMVC的前端分发控制器,用于处理客户端请求,然后交给对应的handler进行处理,返回对应的模型和视 ...

随机推荐

  1. C++中指针与引用详解

    在计算机存储数据时必须要知道三个基本要素:信息存储在何处?存储的值为多少?存储的值是什么类型?因此指针是表示信息在内存中存储地址的一类特殊变量,指针和其所指向的变量就像是一个硬币的两面.指针一直都是学 ...

  2. 20204107 孙嘉临 《PYTHON程序设计》实验四报告

    课程:<Python程序设计>班级: 2041姓名: 孙嘉临学号: 20204107实验教师:王志强实验日期:2020年6月29日必修/选修: 公选课 ##作为一个轻度游戏玩家,当然是要写 ...

  3. 制作 Cocoapods 库

    一.准备工作:注册 trunk 1.更新 cocoapods 至最新版本 2.申请注册 trunk pod trunk register email 'name' 3.进入邮箱,点击激活注册 4.验证 ...

  4. Unity Lamba错误集

    请先看对象层级视图 /// <summary> /// 选择关卡的内容对象 /// </summary> public Transform Transform_levelCon ...

  5. ps 快速替换背景颜色

    1.打开图片: 点击工具栏上的"选择"--色彩范围--按[delete]

  6. LeSS 的诞生(一):大规模团队该何去何从

    <敏捷宣言>发布后,"敏捷"被越来越多的小型开发团队认可.与此同时,另一个问题也逐渐暴露了出来:以 Scrum 为首的敏捷方法论对那些大规模的开发团队并不友好. 基于此 ...

  7. 「万字图文」史上最姨母级Java继承详解

    摘要:继承是面向对象软件技术中的一个概念.它使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用. 本文分享自华为云社区<「万字图文」史上最姨母级Java继承详解丨[奔跑吧!JAVA] ...

  8. springboot整合拦截器如何让其不拦截默认的访问路径

    1.注册自定义拦截器2.拦截器3.控制器4.其它说明:我想做控制拦截登陆,将所有的请求拦截下来判断如果当前的session里没有用户名则跳转到登陆页面.问题是目前可以拦截所有请求了,但第一次进入登陆页 ...

  9. vue(18)路由懒加载

    什么是路由懒加载 官方的解释: 当打包构建应用时,JavaScript 包会变得非常大,影响页面加载. 如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更 ...

  10. 详解Spring中Bean的作用域与生命周期

    摘要:在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我 ...