Springboot 使用RestTemplate 以及RestTemplate中泛型返回问题

概述:

在Springboot中,调用restFul api时常用的方法主要有两种:

通过自带的RestTemplate  或者  自己写http客户端访问工具来实现服务调用

基本上RestTemplate已经可以满足需要了

RestTemplate其实是对http请求中一些模块化代码的封装,比如建立连接、构造请求头 请求体、解析响应信息、关闭连接等,是Springboot对HttpClient的封装,简化了http请求过程,减少冗余代码。

主要方法:

RestTemplate封装了常用http请求,比如GET、POST、PUT、DELETE等,可以方便的调用,主要请求方法如下:

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException

public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException

public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException

public void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientException

public void delete(String url, Object... uriVariables) throws RestClientException

public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException

public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException

这些方法使用起来是比较简单的,其中xxForObject返回的是接口返回值,xxForEntity返回的除了接口返回值  还包括http返回信息。

对于exchange和execute使用起来就比较灵活了,里面有个参数 HttpMethod,可以使用各种请求方式进行请求,比如用HttpMethod.GET方法进行GET请求。

HttpMethod是一个枚举:

RestTemplate exchange方法使用:

1、先新建一个springboot工程,端口取默认 8080,然后新建一个Controller,如下:

@RestController
public class RemoteRestController {
    @GetMapping("rest")
    public String usedForRemoteRest(){
        return "Hi there, from remote";
    }
}

如果调用成功,会返回一个字符串

2、再新建一个springboot工程,端口取8081,工程名比如取ex,方便辨认

server.port=8081

3、在新建的ex工程中,新建一个Controller,准备调用RestTemplate方法,去访问第一个工程中的接口:

@RestController
public class RestTestController {
    private static final String REMOTE_URL = "http://localhost:8080/";

    @GetMapping("rtest")
    public String restGetValue(HttpServletRequest req){
        RestTemplate restTemplate = new RestTemplate();
        String ret = restTemplate.getForObject(REMOTE_URL + "rest", String.class);
        System.out.println("====================ret: " + ret);

        ResponseEntity<String> retEntity = restTemplate.getForEntity(REMOTE_URL + "ret", String.class);
        return "";
    }
}

分别运行两个spring工程,在浏览器中输入http://localhost:8081/rtest ,可以看到返回:

在ex工程中下断点,可以看到getForObject和getForEntity返回值的区别:

可以看到getForEntity返回信息会包括http的信息

 

上面是简单的使用

在源码中我们可以看到,xxForObject, xxForEntity都是有返回值,而对于put, delete访问需要得到返回值,使用:

public void put(String url, @Nullable Object request, Object... uriVariables) throws RestClientException

public void delete(String url, Object... uriVariables) throws RestClientException

这两个方法就无能为力了

这时我们可以使用exchange方法来使用,具体如下:

在测试springboot工程中,写一个put方法的controller:

   @PutMapping("restput")
    public String putMethod(){
        return "PUT method invoke";
    }

可以封装一个exchange方法:

 private <T, A> T exchange(String url, HttpMethod method, Class<T> responseBodyType, A requestBody) {
        RestTemplate template = new RestTemplate();
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");
        MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
        // 请求体
        headers.setContentType(mediaType);
        // 发送请求
        HttpEntity<A> entity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<T> resultEntity = template.exchange(url, method, entity, responseBodyType);
        return resultEntity.getBody();
    }

responseBody: 代表返回值类型

requestBody: 代表请求体中的body参数

在ex工程中写一个测试请求接口:

    @GetMapping("rput")
    public String restPUTValue(HttpServletRequest req){
        String ret = exchange(REMOTE_URL + "restput", HttpMethod.PUT, String.class, null);
        return "RETURN: " + ret;
    }

在浏览器中输入:

http://localhost:8081/rput

会发现返回结果显示出来了:

 

exchange方法返回值中有泛型类型情况:

前面介绍的exchange方法是处理RestTemplate自带的put, delete方法中没有返回值的情况,但是包括get, post等方法,如果返回值中有泛型值,RestTemplate自带的getForEntity, getForObject等其实也是处理不了的,这时也可以使用exchange来代替,具体如下:

可以对上面封装的exchange方法进行改造,传入一个ParameterTypeReference对象:

  public static <T, A> T exchange(String url, HttpMethod method, ParameterizedTypeReference<T> responseBodyType, A requestBody) {
        RestTemplate restTemplate = new RestTemplate();
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");
        MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
        // 请求体
        headers.setContentType(mediaType);
        // 发送请求
        HttpEntity<A> entity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<T> resultEntity = restTemplate.exchange(url, method, entity, responseBodyType);
        return resultEntity.getBody();
    }

测试代码:

两个springboot工程分别新建一个对象RestBean,使用了泛型:

public class RestBean<T> {
    private String name;
    private int age;
    private T msg;

    public RestBean() {
    }

    public RestBean(String name, int age, T msg) {
        this.name = name;
        this.age = age;
        this.msg = msg;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public T getMsg() {
        return msg;
    }

    public void setMsg(T msg) {
        this.msg = msg;
    }
}

在测试工程中返回这个对象,泛型为String:

@GetMapping("restex")
    public RestBean<String> restMethodEx(){
        RestBean<String> bean = new RestBean<>();
        bean.setName("eric");
        bean.setAge(18);
        bean.setMsg("+++++++++++++++++Msg body");
        
        return bean;
    }

在ex工程中,写一个测试接口,用来远程调用测试工程的 "resetex" 接口:

 @GetMapping("rgetex")
    public String testEx(){
        ParameterizedTypeReference<RestBean<String>> responseBodyType = new ParameterizedTypeReference<RestBean<String>>() {};
        RestBean<String> ret = exchange(REMOTE_URL + "restex", HttpMethod.GET, responseBodyType, null);

        return "TEST SUCCESS: " + ret.getName();
    }

测试结果如下:

 

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页