• Tomcat + Spring MVC + HttpClient:怎样使用PUT和PATCH方法传递数据


    在RESTful风格的API中。PUT/PATCH方法一般用于更新数据。在项目的代码中,使用的是HttpClient 4.5,是这样写的:

    protected JSONObject doHttpUriRequest(HttpUriRequest httpUriRequest) {
        JSONObject result = null;
    
        HttpClient httpClient = HttpClients.createDefault();
        try {
            HttpResponse httpResponse = httpClient.execute(httpUriRequest);
            StatusLine responseStatusLine = httpResponse.getStatusLine();
    
            int statusCode = responseStatusLine.getStatusCode();
            if (statusCode == 200) {
                HttpEntity responseEntity = httpResponse.getEntity();
    
                String jsonString = EntityUtils.toString(responseEntity, CHARACTER_SET);
                result = new JSONObject(jsonString);
    
                EntityUtils.consume(responseEntity);
            } else {
                // error handling
            }
        } catch (IOException e) {
            e.printStackTrace();
            return onLocalError(e);
        }
    
        return result;
    }
    
    protected JSONObject doHttpPatch(String uri, Map<String, String> params) {
        JSONObject result = null;
    
        HttpPatch httpPatch = new HttpPatch(uri);
        List<NameValuePair> nvps = constructNvps(params); // constructing name-value pair
    
        try {
            httpPatch.setEntity(new UrlEncodedFormEntity(nvps, CHARACTER_SET));
            result = doHttpUriRequest(httpPatch);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return onLocalError(e);
        }
    
        return result;
    }

    当中doHttpUriRequest()是一个处理发送请求的工具函数。doHttpPatch()是详细处理数据的函数。
    可见写法和一个普通的POST请求差点儿相同,仅仅是将HttpPost换成HttpPatch。
    但是在server端,比方在params中有一个參数叫key。值是value,在Controller里面,能识别到这是一个PATCH方法,但是key的值是null。就是Servlet不能从form里面获取參数。


    Google查了一下原因,大体是说PATCH这种方法非常新,就算到Tomcat 7.0.39也都不支持。

    那怎么破呢?有两个办法:

    1. 用URI来请求

    既然不能使用form来获取參数,那就写在URI的尾巴吧:

    protected JSONObject doHttpPatchWithURI(String uri, Map<String, String> params) {
        JSONObject result = null;
        URIBuilder uriBuilder = new URIBuilder();
        uriBuilder.setPath(uri);
        uriBuilder.setParameters(constructNvps(params));
    
        try {
            URI builtUri = uriBuilder.build();
            HttpPatch httpPatch = new HttpPatch(builtUri);
            result = doHttpUriRequest(httpPatch);
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return onLocalError(e);
        }
    
        return result;
    }

    使用了这样的做法,servlet能够获得參数了。


    这种方法有一个问题。就是即使key是null值,在URI的參数也会带上。在Servlet里面接收,key的值会变成”“(空字符串)。这样在RESTful风格API里面会有歧义:到底是不更新,还是更新成空字符串呢?

    2. 在web.xml中增加一个filter

    还有一种做法是保持使用上面POST风格的方法,在web.xml中增加一个filter:

    <filter>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <servlet-name>springWebMvcDispatcher</servlet-name>
    </filter-mapping>

    当中springWebMvcDispatcher是servlet的名字。
    Filter的工作是从request body的form data里面读取数据,然后包装成一个ServletRequest,使得ServletRequest.getParameter*()之类的方法能够读取到数据。

    參考文档:
    http://stackoverflow.com/questions/20370927/patch-method-in-tomcat-with-spring-mvc

  • 相关阅读:
    java复习计划
    超过16位的字符串装16进制
    《将博客搬至CSDN》
    android设置中文字体样式
    布局文件View和ViewGroup
    创建线程的两种方法,继承Thread,继承Runnable
    本地文件的copy复制
    字节流和字符流完成URL下载,并存入本地
    文本过滤器的用法,FileFilter()和FilenameFilter()
    JavaSE笔记
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/7261252.html
Copyright © 2020-2023  润新知