首页 > 技术文章 > RestTemplate的exchange()方法,解决put和delete请求拿不到返回值的问题

wwct 2020-02-19 22:28 原文

嗷嗷待哺的controller(被调用provider的controller方法)

    //测试get少量参数
    @RequestMapping(value = "detailsGetD",method = RequestMethod.GET)
    public String test05(Integer id,String name){
        System.out.println("GET-"+id+"-"+name);
        return "error";
    }
    //测试post
    @RequestMapping(value = "detailsPostD",method = RequestMethod.POST)
    public String test06(Integer id,String name){
        System.out.println("POST-"+id+"-"+name);
        return "error";
    }
    //测试put
    @RequestMapping(value = "detailsPutD",method = RequestMethod.PUT)
    public String test07(Integer id,String name){
        System.out.println("PUT-"+id+"-"+name);
        return "error";
    }
    //测试delete
    @RequestMapping(value = "detailsDeleteD",method = RequestMethod.DELETE)
    public String test08(Integer id,String name){
        System.out.println("DELETE-"+id+"-"+name);
        return "error";
    }

  consumer的调用传参(url拼接少量参数)

        //get传递单参
        ResponseEntity<String> resp = restTemplate.exchange("http://localhost:8080/detailsGetD?id={id}&name={name}", HttpMethod.GET, null, String.class,1,"zsw");
        //post传递单参
        ResponseEntity<String> resp = restTemplate.exchange("http://localhost:8080/detailsPostD?id={id}&name={name}", HttpMethod.POST, null, String.class,1,"zsw");
        //put传递单参
        Map<String,Object> map=new HashMap<>();
        map.put("id",1);
        map.put("name","zsw");
        ResponseEntity<String> resp = restTemplate.exchange("http://localhost:8080/detailsPutD?id={id}&name={name}", HttpMethod.PUT, null, String.class,map);
        //delete传递单参
        Map<String,Object> map=new HashMap<>();
        map.put("id",1);
        map.put("name","zsw");
        ResponseEntity<String> resp = restTemplate.exchange("http://localhost:8080/detailsDeleteD?id={id}&name={name}", HttpMethod.DELETE, null, String.class,map);

        //返回内容
        String result = resp.getBody();
        System.out.println(result);

  使用map和直接写参数都可以。

 

 再介绍一下传json对象。

  首先登场的是provider方controller。

    //测试get
    @RequestMapping(value = "detailsGet",method = RequestMethod.GET)
    public String test01(@RequestBody Detail detail){
        System.out.println("GET-"+detail);
        return "error";
    }
    //测试post
    @RequestMapping(value = "detailsPost",method = RequestMethod.POST)
    public String test02(@RequestBody Detail detail){
        System.out.println("POST-"+detail);
        return "error";
    }
    //测试put
    @RequestMapping(value = "detailsPut",method = RequestMethod.PUT)
    public String test03(@RequestBody Detail detail){
        System.out.println("PUT-"+detail);
        return "error";
    }
    //测试delete
    @RequestMapping(value = "detailsDelete",method = RequestMethod.DELETE)
    public String test04(@RequestBody Detail detail){
        System.out.println("DELETE-"+detail);
        return "error";
    }

  我们再来看consumer的选手,传参json对象。

        String json = "{\"author\":\"zsw\",\"createdate\":1582010438846,\"id\":1,\"summary\":\"牡丹\",\"title\":\"菏泽\"}";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(json,headers);
        ResponseEntity<String> resp = restTemplate.exchange("http://localhost:8080/detailsPost", HttpMethod.POST, entity, String.class);
        HttpStatus statusCode = resp.getStatusCode(); // 获取响应码
        int statusCodeValue = resp.getStatusCodeValue(); // 获取响应码值
        HttpHeaders headers1 = resp.getHeaders(); // 获取响应头
        System.out.println("statusCode:" + statusCode);
        System.out.println("statusCodeValue:" + statusCodeValue);
        System.out.println("headers:" + headers1);

        //或者直接传对象,底层自己处理
        Detail detail=new Detail();
        detail.setId(1L);
        detail.setSummary("牡丹");
        detail.setTitle("菏泽");
        detail.setAuthor("zsw");
        detail.setCreatedate(new Timestamp(new Date().getTime()));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Detail> entity = new HttpEntity<>(detail,headers);
        ResponseEntity<String> resp = restTemplate.exchange("http://localhost:8080/detailsDelete", HttpMethod.DELETE, entity, String.class);

        //拿到返回值
        String result = resp.getBody();
        System.out.println(result);
        return result;

  post、put、delete请求都可以用这种方法。但是测试get时就不行了直接报错:org.springframework.web.client.HttpClientErrorException: 400 null(错误请求,服务器不理解请求的语法),get请求不支持这种方式的传参,get请求只能将请求参数拼接URI后边,而不能单独传递request body参数,除非你改用POST。如果用resuful风格,必须要get传参对象,也不是没有办法的。根据(https://blog.belonk.com/c/http_resttemplate_get_with_body.html)这篇文章,小弟把情况摸清楚了,上手!

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.zhou.entity.Detail;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Repository;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Repository
public class DetailMapper {

    public String test(){
        RestTemplate restTemplate1 = new RestTemplate();
        restTemplate1.setRequestFactory(new HttpComponentsClientHttpRequestWithBodyFactory());

        String json = "{\"author\":\"zsw\",\"createdate\":1582010438846,\"id\":1,\"summary\":\"牡丹\",\"title\":\"菏泽\"}";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(json,headers);
        ResponseEntity<String> resp = restTemplate1.exchange("http://localhost:8080/detailsGet", HttpMethod.GET, entity, String.class);

        String result = resp.getBody();
        System.out.println(result);
        return result;
    }
    private static final class HttpComponentsClientHttpRequestWithBodyFactory extends HttpComponentsClientHttpRequestFactory {
        @Override
        protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
            if (httpMethod == HttpMethod.GET) {
                return new HttpGetRequestWithEntity(uri);
            }
            return super.createHttpUriRequest(httpMethod, uri);
        }
    }
    private static final class HttpGetRequestWithEntity extends HttpEntityEnclosingRequestBase {
        public HttpGetRequestWithEntity(final URI uri) {
            super.setURI(uri);
        }

        @Override
        public String getMethod() {
            return HttpMethod.GET.name();
        }
    }
}

  大致就是这个样子。对于没接触过httpclient的我,有些类不能导包,属实有的懵。百度百度百度。。。  找到httpclient的maven的依赖,下载导包,成功!启动项目:无法访问org.apache.http.annotation.ThreadSafe,找不到org.apache.http.annotation.ThreadSafe的类文件 ???,我记忆中没有用过这个类,全局搜索一下也找不到(ctrl+shift+f  -  查询自己写的代码)。继续百度,说httpclient4.5.2版本和httpcore4.4.4版本更配哦,maven自动下载的httpcore4.4.13,今天这个maven咋回事(好感-1),参考(https://www.jianshu.com/p/f35eac56c334)文章,最终的pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zhou</groupId>
    <artifactId>news-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>news-consumer</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 分页 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.13</version>
        </dependency>

        <!-- Apache Commons IO -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.2</version>
        </dependency>
        <!-- Apache Commons IO -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.4</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

  重新启动,访问,拿到参数。

 附上github地址:https://github.com/wwck-zsw/RestTemplate

参考链接:

    https://segmentfault.com/a/1190000021123356

    https://www.cnblogs.com/jnba/p/10522608.html(灵感来源)

 

推荐阅读