13.Rest风格映射以及源码解析

rest风格,即请求路径相同,但是请求方式不同代表不同处理

1.get请求:获取对象
2.post请求:修改对象
3.delete请求:删除对象
4.put请求:增加对象

1.controler代码
    @RequestMapping(value = "/user" , method = RequestMethod.GET)
    public String getUser(){
        return "get-张三";
    }
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public String postUser(){
        return "post-张三";
    }
    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    public String putUser(){
        return "put-张三";
    }
    @RequestMapping(value = "/user",method = RequestMethod.DELETE)
    public String deleteUser(){
        return "delete-张三";
    }

2.页面代码:发现页面的form表单请求方式只有get/post
    <form action="/user" method="get">
        <input value="get-提交" type="submit">
    </form>
    <form action="/user" method="post">
        <input value="post-提交" type="submit">
    </form>
    <form action="/user" method="delete">
        <input value="delet-提交" type="submit">
    </form>
    <form action="/user" method="put">
        <input value="put-提交" type="submit">
    </form>

结论:
    当页面点击对应的get/post请求时可以调用到对应的方法,但是点击delete和put请求时返回的仍是get的处理方法

这是为什么呢?
分析源码:
    1.向容器中注册hiddenHttpMethodFilter,用来处理rest风格的请求问题
        @Bean
        @ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
        @ConditionalOnProperty(
            prefix = "spring.mvc.hiddenmethod.filter",
            name = {"enabled"},
            //发现默认是不注册,需要在配置文件中配置为true
            matchIfMissing = false
        )
        public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
            return new OrderedHiddenHttpMethodFilter();
        }
    
    2.OrderedHiddenHttpMethodFilter的父类HiddenHttpMethodFilter方法
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            HttpServletRequest requestToUse = request;
            if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
                //注意点1:this.methodParam的值是:_method,即获取表单中name="_method"的值,即请求方式(put/delete)
                //<form action="/user" method="post">
                //    <input name="_method" value="put" type="hidden">
                //    <input value="put-提交" type="submit">
                //</form>
                String paramValue = request.getParameter(this.methodParam);
                if (StringUtils.hasLength(paramValue)) {
                    //注意点2:会将获取到的请求方式(put/delete)全部置换成大写:所以在表单中的请求方式可以是任意大小写的格式,这里都会置换成大写
                    String method = paramValue.toUpperCase(Locale.ENGLISH);
                    //注意点3:ALLOWED_METHODS是一个list集合,里面包含了/put/delete/patch请求
                    ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
                    if (ALLOWED_METHODS.contains(method)) {
                        //注意点4:判断这里的请求是否是/put/delete/patch的一种,如果是,将request对象重新封装下,method的值改为/put/delete/patch,原始的请求都是以post形式提交过来
                        requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
                    }
                }
            }
            //放行:方位到具体的方法上
            filterChain.doFilter((ServletRequest)requestToUse, response);
        }
此时的代码结构更改为:
配置文件中:
    1.启用该方法过滤器,默认是false
        spring:
          mvc:
            hiddenmethod:
              filter:
                enabled: true
    
    2.页面代码改为:
        //改造点1:将delete和put形式的请求都改为post
        <form action="/user" method="post">
            //改造点2:设置一个隐藏的input标签,name值必须是:_method,值是请求方式
            <input name="_method" value="delete" type="hidden">
            <input value="delet-提交" type="submit">
        </form>
        <form action="/user" method="post">
            <input name="_method" value="put" type="hidden">
            <input value="put-提交" type="submit">
        </form>
        
总结:
    按照源码分析,在配置文件中加上启用隐藏方法过滤器,将hiddenHttpMethodFilter加载到容器中,当请求过来时,判断是否是post请求,是的话,判断是否是put/patch/delete的一种
    是的话,重新包装一个request以供使用
    
    
重要点:
    1.在表单中新增一个隐藏的input标签,name值必须是_method,value的是自己的特殊请求方式:/put/delete/patch
        <input name="_method" value="put" type="hidden">
    2.form表单的请求方式必须是post
        <form action="/user" method="post">
重要的重要的:上述操作只针对以页面的表单提交问题
上述的操作只针对于springboot页面表单的提交
如果通过第三方插件或其他途径调用如postman直接调用http://localhost:8080/user,选择请求方式为delete,不需要任何配置都会进入到delete的处理方法中
注解的妙用
1.
    @RequestMapping(value = "/user" , method = RequestMethod.GET)
    等同
    @GetMapping(value = "/user")

2.
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    等同于
    @PostMapping(value = "/user")

3.
    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    等同于
    @PutMapping(value = "/user")
    
4.
    @RequestMapping(value = "/user",method = RequestMethod.DELETE)
     等同于
    @DeleteMapping(value = "/user")

 

posted @ 2022-05-11 21:47  努力的达子  阅读(110)  评论(0编辑  收藏  举报