【Spring Boot】RestTemplate使用总结

【问题背景】

最近一直在处理交接项目的遗留问题,在确定了商品同步方案之后,与商品服务对接,遇到了一个问题,请求Read time out。

在这里插入图片描述

【原调用方式】

和我交接项目的人,采用的是和旧系统一样的调用方式,写了个HttpClient工具类,之前和我对接接口就给我发了请求超时的错误信息,现在看来这个问题一直都没有处理。

【原方式处理方案】

其实这个问题很简单,既然是请求读取时间超时,那我们在发起请求的时候,将读取时间设置长一些,就解决了。项目中,使用的HttpClient版本是4.3,所以,我在他的请求工具类中增加了一段设置读取时间的代码:

//post方式请求
public String doPost(String url, Map<String, Object> map){
        HttpPost httpPost = new HttpPost(url);   
        //设置代理主机
        HttpHost proxy=new HttpHost("请求服务的ip地址", 36016);
        //设置请求的连接超时时间
        RequestConfig config=RequestConfig.custom().setProxy(proxy)
                .setConnectTimeout(30000)
               .setSocketTimeout(100000)
               .build();

        // 装载配置信息
        httpPost.setConfig(config);
        //装填参数
        List<NameValuePair> nvps = new ArrayList<>();
        if(map!=null){
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                Object value = entry.getValue();
                String valueStr = value==null?null:value.toString();
                nvps.add(new BasicNameValuePair(entry.getKey(),valueStr ));
            }
        }

        //设置header信息
        //指定报文头【Content-type】、【User-Agent】
        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
        httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

        try{
            //设置参数到请求对象中
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
            // 发起请求
            CloseableHttpResponse response = this.httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            log.info("返回http状态码:"+statusCode);
            // 判断状态码是否为200
            if ( statusCode == 200) {
                // 返回响应体的内容
                HttpEntity httpEntity = response.getEntity();

                if(httpEntity!=null && httpEntity.getContent()!=null){
                    return getResponseString(httpEntity);
                }
            }
            return null;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

连接超时的问题就解决了。但另一个问题是,这个项目调用的不仅仅是一个项目,我设置了商品调用的请求主机,但其他接口是调用另一个项目,这就不对了。要不然我就在工具类代码中在单独写一个post请求商品服务的方法,这样代码就重复了。想到既然用的是Spring Boot架构,我就将原生的HttpClient请求方式弃用了,直接使用Spring Boot中封装的更好的RestTemplate去处理。

【新调用方式配置】

采用RestTemplate方式调用其实也很简单,写一个全局配置,并且设置超时时间即可,代码如下:

@Configuration
public class RestTemplateConfig {

    @Bean
    @ConditionalOnMissingBean({ RestOperations.class, RestTemplate.class })
    //Spring Boot的自动配置机制依靠@ConditionalOnMissingBean注解判断是否执行初始化代码,
    // 即如果用户已经创建了bean,则相关的初始化代码不再执行。
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate(factory);
        // 使用 utf-8 编码集的 conver 替换默认的 conver(默认的 string conver 的编码集为"ISO-8859-1")
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
        while (iterator.hasNext()) {
            HttpMessageConverter<?> converter = iterator.next();
            if (converter instanceof StringHttpMessageConverter) {
                iterator.remove();
            }
        }
        messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));

        //解决微信返回text/plain的解析
        restTemplate.getMessageConverters().add(new WxMappingJackson2HttpMessageConverter());

        return restTemplate;
    }

    @Bean
    @ConditionalOnMissingBean({ClientHttpRequestFactory.class})
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        //设置超时时间
        factory.setReadTimeout(15000);// ms
        factory.setConnectTimeout(15000);// ms
        return factory;
    }
}

【新调用方式使用】

项目中如何发起调用请求,核心代码如下:

//设置请求头
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
//调用参数
         MultiValueMap<String, String> params= new LinkedMultiValueMap<>();
         params.add("companyId",companyId.toString());
         params.add("addGoodsList",new Gson().toJson(wmsGoodsDtos));
         params.add("editGoodsList",new Gson().toJson(editWmsGoodsDtos));
         params.add("deleteGoodsIdList",deleteList);
         params.add("platformId",platformId.toString());
         HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
//  执行HTTP请求
// 最后的参数需要用String.class  使用其他的会报错
         ResponseEntity<String> response = restTemplate.exchange("请求的接口地址", HttpMethod.POST, requestEntity, String.class);
         String result = response.getBody();

【总结】

现在大多是Spring Boot,Spring Cloud服务架构,既然有了新的架构,为什么还要把旧系统的一些老东西拿过来使用呢,换了一种方式,更好地解决了问题,也学习到了一些新东西,何乐而不为呢。

猜你喜欢

转载自blog.csdn.net/u013034223/article/details/84292751