• RestTemplate的使用


    一、简介

    RestTemplateSpring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率。相较于之前常用的 HttpClientRestTemplate 是一种更优雅的调用 RESTful 服务的方式。

    二、RestTemplate 用法

    2.1 准备工作

    创建一个用户实体类

    public class User {
    
        private String username;
        
        public User(){}
        public User(String username){
            this.username = username;
        }
        
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    }    
    

    创建 Controller:

    @RestController
    public class UserController {
    
        private static final Logger log = LoggerFactory.getLogger(UserController.class);
    
        @GetMapping("/user/{username}")
        public User getUser(@PathVariable String username) {
            log.info("username :{}", username);
            return new User(username);
        }
        
        @PostMapping("/user")
        public User modify(String username){
            log.info("username :{}", username);
            return new User("modify");
        }
    }
    

    2.2 声明 RestTemplate

    * Spring Boot <= 1.3 不需要定义,Spring Boot自动定义了一个
    * Spring Boot >= 1.4 Spring Boot不再自动定义一个RestTemplate,而是定义了一个RestTemplateBuilder 可以更好地控制 RestTemplate 创建的对象  
    
    @Configuration
    public class ApplicationConfig {
        @Bean
        public RestTemplate restTemplate(RestTemplateBuilder builder) {
            return builder.build();
        }
    }
    

    2.3 GET 请求

    方法列表:

    <T> T getForObject(String url, Class<T> responseType, Object... uriVariables);
    
    <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables);
    
    <T> T getForObject(URI url, Class<T> responseType);
    
    <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables);
    
    <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables);
    
    <T> ResponseEntity<T> getForEntity(URI var1, Class<T> responseType);
    

    实例一:

    getForObject 方法返回对象为响应体中数据转化成的对象

    @SpringBootTest
    class UserApiTests {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Test
        public void shouldGetRequestSuccess() {
            User expected = new User("MarkLogZhu");
            String url = "http://localhost:8900/user/{1}";
            User result = restTemplate.getForObject(url, User.class,"MarkLogZhu");
            assertTrue(expected.getUsername().equals(result.getUsername()));
        }
    
    }
    

    实例二:

    getForEntity 方法返回对象为 ResponseEntity 对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等

    @SpringBootTest
    class UserApiTests {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Test
        public void shouldGetForEntityRequestSuccess() {
            User expected = new User("MarkLogZhu");
            String url = "http://localhost:8900/user/{1}";
            ResponseEntity<User> result = restTemplate.getForEntity(url,User.class,"MarkLogZhu");
            assertTrue(result.getStatusCode().is2xxSuccessful());
            assertTrue(expected.getUsername().equals(result.getBody().getUsername()));
        }
    }     
    

    2.4 POST 请求

    方法列表:

    <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);
    
    <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);
    
    <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType);
    
    <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);
    
    <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);
    
    <T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType);
    

    实例一:

    getForObject 方法返回对象为响应体中数据转化成的对象

    @SpringBootTest
    class UserApiTests {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Test
        public void shouldPostForObjectRequestSuccess() {
            User expected = new User("modify");
            String url = "http://localhost:8900/user";
            Map<String, Object> map = new HashMap<>();
            map.put("username", "MarkLogZhu");
            User result = restTemplate.postForObject(url, map, User.class);
            assertTrue(expected.getUsername().equals(result.getUsername()));
        }
    
    }
    

    实例二:

    getForEntity 方法返回对象为 ResponseEntity 对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等

    @SpringBootTest
    class UserApiTests {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Test
        public void shouldPostForEntityRequestSuccess() {
            User expected = new User("modify");
            String url = "http://localhost:8900/user";
            Map<String, Object> map = new HashMap<>();
            map.put("username", "MarkLogZhu");
            ResponseEntity<User> result = restTemplate.postForEntity(url, map, User.class);
            assertTrue(result.getStatusCode().is2xxSuccessful());
            assertTrue(expected.getUsername().equals(result.getBody().getUsername()));
        }
    }    
    

    2.5 PUT请求方法

    方法列表:

    void put(String url, @Nullable Object request, Object... uriVariables);
    
    void put(String url, @Nullable Object request, Map<String, ?> uriVariables);
    
    void put(URI url, @Nullable Object request);
    

    2.6 DELETE请求方法

    方法列表:

    void delete(String url, Object... uriVariables);
    
    void delete(String url, Map<String, ?> uriVariables);
    
    void delete(URI url);
    

    三、RestTemplate 的组成

    RestTemplate 包含如下几个部分:

    * ClientHttpRequestFactory 客户端请求对象工厂
    * ClientHttpRequestInterceptor 请求拦截器  
    * HttpMessageConverter 对象转换器
    * ResponseErrorHandler 异常处理
    

    3.1 客户端请求对象工厂

    ClientHttpRequestFactory 默认使用的是 JDKHttpURLConnection

    @FunctionalInterface
    public interface ClientHttpRequestFactory {
        
    	ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;
    }
    
    public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
     	......
    	@Override
    	public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
    		HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
    		prepareConnection(connection, httpMethod.name());
    
    		if (this.bufferRequestBody) {
    			return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
    		}
    		else {
    			return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
    		}
    	}        
        ......    
    }    
    

    可以通过 setRequestFactory(ClientHttpRequestFactory requestFactory) 方法来更改请求实现。

    3.2 请求拦截器

    可以实现 ClientHttpRequestInterceptor 接口,自定义拦截器记录请求和响应头和主体:

    public class RequestResponseLoggingInterceptor implements ClientHttpRequestInterceptor {
    
        private final Logger log = LoggerFactory.getLogger(this.getClass());
    
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            logRequest(request, body);
            ClientHttpResponse response = execution.execute(request, body);
            logResponse(response);
            return response;
        }
    
    
        private void logRequest(HttpRequest request, byte[] body) throws UnsupportedEncodingException {
            if (log.isDebugEnabled()){
                log.debug("===========================request begin================================================");
                log.debug("URI         : {}", request.getURI());
                log.debug("Method      : {}", request.getMethod());
                log.debug("Headers     : {}", request.getHeaders());
                log.debug("Request body: {}", new String(body, "UTF-8"));
                log.debug("==========================request end================================================");
            }
        }
    
        private void logResponse(ClientHttpResponse response) throws IOException {
            if (log.isDebugEnabled()){
                log.debug("============================response begin==========================================");
                log.debug("Status code  : {}", response.getStatusCode());
                log.debug("Status text  : {}", response.getStatusText());
                log.debug("Headers      : {}", response.getHeaders());
                log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
                log.debug("=======================response end=================================================");
            }
        }
    }
    

    注册拦截器

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        RestTemplate restTemplate = builder.build();
        restTemplate.setInterceptors(Collections.singletonList(new RequestResponseLoggingInterceptor()));
        // 默认的 ClientHttpRequestFactory 的响应只能被读取一次,会导致响应返回数据为空,可以使用 BufferingClientHttpRequestFactory ,它支持多次读取
          restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
        return restTemplate;
    }
    

    3.3 对象转换器

    RestTemplate 的构造函数来看,它默认支持 ByteArrayHttpMessageConverterStringHttpMessageConverterResourceHttpMessageConverter 这三个转换器:

    public RestTemplate() {
    	this.messageConverters.add(new ByteArrayHttpMessageConverter());
    	this.messageConverters.add(new StringHttpMessageConverter());
    	this.messageConverters.add(new ResourceHttpMessageConverter(false));
    	try {
    		this.messageConverters.add(new SourceHttpMessageConverter<>());
    	}
    	catch (Error err) {
    		// Ignore when no TransformerFactory implementation is available
    	}
    	this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
    
    	if (romePresent) {
    		this.messageConverters.add(new AtomFeedHttpMessageConverter());
    		this.messageConverters.add(new RssChannelHttpMessageConverter());
    	}
    
    	if (jackson2XmlPresent) {
    		this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
    	}
    	else if (jaxb2Present) {
    		this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    	}
    
    	if (jackson2Present) {
    		this.messageConverters.add(new MappingJackson2HttpMessageConverter());
    	}
    	else if (gsonPresent) {
    		this.messageConverters.add(new GsonHttpMessageConverter());
    	}
    	else if (jsonbPresent) {
    		this.messageConverters.add(new JsonbHttpMessageConverter());
    	}
    
    	if (jackson2SmilePresent) {
    		this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
    	}
    	if (jackson2CborPresent) {
    		this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
    	}
    
    	this.uriTemplateHandler = initUriTemplateHandler();
    }
    

    也可以添加自定义的转换器,如微信接口返回是JSON格式的数据,但是响应头是Content-Type = text/plain,我们需要自定义一个转换器:

    public class WeChatMessageConverter extends MappingJackson2HttpMessageConverter {
    
        public WeChatMessageConverter() {
            List<MediaType> mediaTypes = new ArrayList<>();
            mediaTypes.add(MediaType.TEXT_PLAIN);
            setSupportedMediaTypes(mediaTypes);
        }
    
    }
    

    注册转换器:

    restTemplate.getMessageConverters().add(new WeChatMessageConverter());
    
  • 相关阅读:
    cmake 基本命令
    webpack4下import()模块按需加载,打包按需切割模块,减少包体积,加快首页请求速度
    内容安全策略(CSP)详解
    内网穿透访问Vue项目的时候出现Invalid Host header解决办法
    webpack3 项目升级 webpack4
    vue-multi-module【多模块集成的vue项目,多项目共用一份配置,可以互相依赖,也可以独立打包部署】
    JS的数据类型判断函数、数组对象结构处理、日期转换函数,浏览器类型判断函数合集
    使用模块化工具打包自己开发的JS库(webpack/rollup)对比总结
    基于AlipayJSBridge封装的H5网页支付宝打赏、网站打赏、个人免签支付,支付宝转账打赏支付组件
    whistle替代Fiddler调试远程服务器代码使用教程
  • 原文地址:https://www.cnblogs.com/markLogZhu/p/12930529.html
Copyright © 2020-2023  润新知