首页 > 代码库 > 三、Spring MVC之Restful风格的实现

三、Spring MVC之Restful风格的实现

    先抛论点:我觉得Restful风格仅仅是一种风格,并不是什么高深的技术架构,而是一种编程的规范。在我们进行应用程序开发的过程中,我们可以发现,80%以上的操作都是增删查改式的操作,restful就是定义了CRUD的开发规范。下面把restful风格的url和传统风格的url进行一个对比。

业务操作
传统风格URL
传统请求方式
restful风格URL
restful请求方式
新增
/add
GET/POST
/order
POST
修改
/update?id=1
GET/POST/order/1
PUT
查询
/get?id=1GET/POST/order/1GET
删除
/delete?id=1GET/POST/order/1DELETE


    自从我们学习jsp、servlet以来,所用的请求方式一般就是post或者get,浏览器目前也只是支持post和get请求方式,那要怎么实现put和delete请求呢?不要着急,spring mvc提供了一个filter用来实现put和delete请求。下面我们来看一下这个filter的代码,简单说一下对注视的理解,水平有限,不一定准确:浏览器目前只支持post和get请求,这个过滤器呢可以实现把post请求转为put请求或者delete请求,它是怎么实现的呢?利用一个普通的post请求,再加上一个隐藏域,隐藏域的名称为_method,当它发现是一个post请求的时候,而且还有_method属性的话,它就会把该请求转换为响应的http请求。该过滤器定义在web.xml的位置也需要注意,因为这个filter需要检查post的参数,因此需要定义在文件上传得filter后面,典型的有:org.springframework.web.multipart.support.MultipartFilter。

package org.springframework.web.filter;

import java.io.IOException;
import java.util.Locale;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;

/**
 * {@link javax.servlet.Filter} that converts posted method 
 * parameters into HTTP methods, retrievable via 
 * {@link HttpServletRequest#getMethod()}. Since browsers currently only
 * support GET and POST, a common technique - used by the Prototype
 * library, for instance - is to use a normal POST with an additional 
 * hidden form field ({@code _method}) to pass the "real" HTTP method along.
 * This filter reads that parameter and changes
 * the {@link HttpServletRequestWrapper#getMethod()} return value accordingly.
 *
 * <p>The name of the request parameter defaults to {@code _method}, but can be
 * adapted via the {@link #setMethodParam(String) methodParam} property.
 *
 * <p><b>NOTE: This filter needs to run after multipart processing in case of 
 * a multipart POST request, due to its inherent need for checking a POST 
 * body parameter.</b>
 * So typically, put a Spring 
 * {@link org.springframework.web.multipart.support.MultipartFilter}
 * <i>before</i> this HiddenHttpMethodFilter in your {@code web.xml} filter chain.
 *
 * @author Arjen Poutsma
 * @author Juergen Hoeller
 * @since 3.0
 */
public class HiddenHttpMethodFilter extends OncePerRequestFilter {

    /** Default method parameter: {@code _method} */
    public static final String DEFAULT_METHOD_PARAM = "_method";

    private String methodParam = DEFAULT_METHOD_PARAM;


    /**
     * Set the parameter name to look for HTTP methods.
     * @see #DEFAULT_METHOD_PARAM
     */
    public void setMethodParam(String methodParam) {
        Assert.hasText(methodParam, "‘methodParam‘ must not be empty");
        this.methodParam = methodParam;
    }

    @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)) {
                requestToUse = new HttpMethodRequestWrapper(request, paramValue);
            }
        }

        filterChain.doFilter(requestToUse, response);
    }


    /**
     * Simple {@link HttpServletRequest} wrapper that returns the supplied method for
     * {@link HttpServletRequest#getMethod()}.
     */
    private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {

        private final String method;

        public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
            super(request);
            this.method = method.toUpperCase(Locale.ENGLISH);
        }

        @Override
        public String getMethod() {
            return this.method;
        }
    }

}


    有了上面的filter,结合前面的RequestMapping的method属性,就可以实现put或者delete请求了,下面来看两个具体的例子

1、以put请求为例

第一步需要在web.xml中配置过滤器

<!-- HiddenHttpMethodFilter可以把post请求转为delete或者put请求,
需要借助于_method属性,  -->
<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>

第二步:form表单的定义,它实际上就是一个post,定义了一个隐藏域

<form action="/restful/testPut/1" method="post">
    <!-- POST请求转为PUT请求的关键 -->
    <input type="hidden" name="_method" value="http://www.mamicode.com/PUT"/>
    <p>put请求</p>
    <input type="submit" value="http://www.mamicode.com/submit" />
</form>

第三步:后台方法的定义,定义method为put,使用注解@PathVariable获取url中的参数

@RequestMapping(value = "/testPut/{id}", method = RequestMethod.PUT)
public String testPut(@PathVariable("id") int id) {
    System.out.println("test put function" + id);
    return "greeting";
}

这就是实现了一个restful风格的put请求。


项目源代码:RestfulControll.java

https://git.oschina.net/acesdream/spring-mvc


本文出自 “艾斯的梦想” 博客,请务必保留此出处http://acesdream.blog.51cto.com/10029622/1905068

三、Spring MVC之Restful风格的实现