第二节:REST风格的案例及源码分析

一、REST 风格的请求

  发送 REST 风格的增删改查请求:

发起图书的增删改查请求;使用REST风格的URL地址
    /book/1     GET:查询1号图书
    /book/1     DELETE:删除1号图书
    /book/1     PUT:更新1号图书
    /book         POST:添加图书
    http://localhost:8080/index.jsp

  

  思考:浏览器的 form 表单只提供了 get 与 post 这两种提交方式,如何进行 put 和 delete 方式的提交呢?

  为了支持页面发起 PUT 和 DELETE 的请求,Spring 提供了对 REST 风格的支持:

  (1)SpringMVC 中有一个 Filter,可以把普通的请求转化为规定形式的请求,配置这个 Filter;

  (2)如何发起其他形式请求?

      按照以下要求:

      ① 创建一个 post 类型的表单;

      ② 表单项中携带一个 _method 的参数;

      ③ 这个 _method 的值就是 DELETE 或者 PUT

 

二、实验代码

  1、控制器代码

@Controller
public class RestTestController {

    @RequestMapping(value = "/book/{bid}", method = RequestMethod.GET)
    public String getBook(@PathVariable("bid")Integer bid) {
        System.out.println("查询到了" + bid + "图书");
        return "success";
    }

    @RequestMapping(value = "/book", method = RequestMethod.POST)
    public String saveBook() {
        System.out.println("添加了新的图书");
        return "success";
    }

    @RequestMapping(value = "/book/{bid}", method = RequestMethod.DELETE)
    public String deleteBook(@PathVariable("bid")Integer bid) {
        System.out.println("删除了" + bid + "图书");
        return "success";
    }

    @RequestMapping(value = "/book/{bid}", method = RequestMethod.PUT)
    public String updateBook(@PathVariable("bid")Integer bid) {
        System.out.println("更新了" + bid + "图书");
        return "success";
    }
}

 

 

  2、配置 HiddenHttpMethodFilter 过滤器(SpringMVC提供的过滤器)

    <!-- 支持REST风格的过滤器:可以将POST请求转换为PUT或DELETE请求 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

 

  3、页面请求链接

</body>

<a href="book/1">查询图书</a>

<form action="book" method="post">
    <input type="submit" value="添加图书">
</form>


<form action="book/1" method="post">
    <input name="_method" value="PUT">
    <input type="submit" value="更新1号图书">
</form>

<form action="book/1" method="post">
    <input name="_method" value="DELETE">
    <input type="submit" value="删除1号图书">
</form>

</body>

 

  4、测试

  5、可能会出现的问题

   (1)这个代码的运行环境需要 Tomcat7.0以及以下版本。

      原因: Tomcat按照JCP规范(JSP2.3版本)的规定,从Tomcat8.x版本开始,不再支持以HTTP PUT方式访问JSP页面,仅支持GET、POST和HEAD方式。

 

      而在控制器方法中编写的返回值是一个字符串,SpringMVC会认为这是一个jsp页面,所以报错了。

   (2)使用 Tomcat8.0或以上会报JSPs only permit GET POST or HEAD 的错误。

      第二节:REST风格的案例及源码分析

 

       解决方式一:在jsp页面设置为  isErrorPage

<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>

        解决方式二:

        如果在 controller 里的 testRESTPUT 的方法加上 @ResponseBody() 注解, 并且返回一个字符串,就不会操作了。                 @ResponseBody注解的作用是将控制器方法的返回值通过适当的转换器转换为指定的格式之后,写入到Response对象的body区,通常用来返回JSON数据或者是XML数据。

 

        注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过Response对象输出指定格式的数据。

 

三、HiddenHttpMethodFilter过滤器源码分析

  1、为什么请求隐含参数名称必须叫做 "_method"?

    第二节:REST风格的案例及源码分析

 

      因为在过滤器中默认是获取参数名为 "_method" 的参数值的。

 

  2、HiddenHttpMethodFilter 的处理过程

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        //获取表单上 _method 带来的值(delete、put)
        String paramValue = request.getParameter(this.methodParam);
        
        //获取表单方式为 POST 而且 _method 有值
        if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
            //把参数转为大写(DELETE、PUT)
            String method = paramValue.toUpperCase(Locale.ENGLISH);
            
            //包装了一下request对象,并且重写了request对象的 getMethod
            HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);
            
            //wrapper.getMethod (PUT 或 DELETE)
            filterChain.doFilter(wrapper, response);
        }
        else {
            //直接放行
            filterChain.doFilter(request, response);
        }
    }



    private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {

        private final String method;

        public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
            super(request);
            this.method = method;
        }
        
        //重写了 getMethod 方法
        @Override
        public String getMethod() {
            return this.method;
        }
    }

 

 

  3、图解

    第二节:REST风格的案例及源码分析

 

 

 

 

 

 

SpringMVC 中有一个 Filter,可以把普通的请求转化为规定形式的请求,配置这个Filter
上一篇:Java.反射


下一篇:Spring(SpringBoot)--FactoryBean--使用/原理/详解