天天看點

RestTemplate 實踐和踩坑日記

話不多說

場景就是 我調用外部需要鑒權的接口, 需要按照對方的格式寫參數。嗚嗚嗚

官網 說這個東西 5.0後 處于維護階段。

大概下面這個意思

As of 5.0 the RestTemplate is in maintenance mode, with only minor requests for changes and bugs to be accepted going forward. Please, consider using the WebClient which offers a more modern API and supports sync, async, and streaming scenarios.

先直接貼配置

@Configuration
public class RestTemplateConfig {

    private static final Logger logger= LoggerFactory.getLogger(RestTemplateConfig.class);

    @Bean
    public RestTemplate restTemplate() {
        // 添加内容轉換器,使用預設的内容轉換器
        RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
        // 設定編碼格式為UTF-8
        List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
        HttpMessageConverter<?> converterTarget = null;
        for (HttpMessageConverter<?> item : converterList) {
            if (item.getClass() == StringHttpMessageConverter.class) {
                converterTarget = item;
                break;
            }
        }
        if (converterTarget != null) {
            converterList.remove(converterTarget);
        }
        HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        converterList.add(1,converter);
        // 為啥加這個。 了解了 mvc 的消息轉換器可以🈶️多個。
        // 坑1
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_HTML));
        restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);

        logger.info("-----restTemplate-----初始化完成");
        return restTemplate;
    }

    @Bean
    public ClientHttpRequestFactory httpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

    @Bean
    public HttpClient httpClient() {
        // 長連接配接保持30秒
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
        //設定整個連接配接池最大連接配接數 根據自己的場景決定
        connectionManager.setMaxTotal(100);
        //同路由的并發數,路由是對maxTotal的細分
        connectionManager.setDefaultMaxPerRoute(100);

        //requestConfig
        RequestConfig requestConfig = RequestConfig.custom()
                //伺服器傳回資料(response)的時間,超過該時間抛出read timeout
                .setSocketTimeout(3000)
                //連接配接上伺服器(握手成功)的時間,超出該時間抛出connect timeout
                .setConnectTimeout(2000)
                //從連接配接池中擷取連接配接的逾時時間,超過該時間未拿到可用連接配接,會抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                .setConnectionRequestTimeout(500)
                .build();
        //headers
        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
        headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
        headers.add(new BasicHeader("Accept-Language", "zh-CN"));
        headers.add(new BasicHeader("Connection", "Keep-Alive"));
        headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));

        return HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                .setDefaultHeaders(headers)
                // 保持長連接配接配置,需要在頭添加Keep-Alive
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                //重試次數,預設是3次,沒有開啟
                .setRetryHandler(new DefaultHttpRequestRetryHandler(2, true))
                .build();
    }
}
           

坑1 為啥 我傳回的字元串轉不了對象。

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class [xx.xx.xx.Employee;] and content type [text/html] ... 

           

他喵的 傳回封包媒體格式 竟然 text/html ,我轉了幾個小時 也沒有轉處理 氣死我了。 多謝下面的部落格

思路大概就是讓你支援 這個轉換器就好了。

參考

https://www.technicalkeeda.com/spring-tutorials/could-not-extract-response-no-suitable-httpmessageconverter-found-for-response-type

坑2 RestTemplate 傳遞 form 表單 的參數

得 自己設定頭 和參數格式

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("xxxx", "f哈哈哈");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
ResponseEntity<String> response = restTemplate.postForEntity( url, request , String.class );
           

貼下我的代碼

GtwShippingRequest shippingRequest = new GtwShippingRequest();
        shippingRequest.setBillNo("1");
        shippingRequest.setTrafName("1");
        shippingRequest.setVoyage("1");
        shippingRequest.setIeFlag("E");
        shippingRequest.setRegion("sh");
        Gson gson = new Gson();
        String content = gson.toJson(shippingRequest);
        String timestamp = String.valueOf(System.currentTimeMillis());
        String sign = getSign(bizCode92, bizId, content, timestamp, appKey);
        MultiValueMap<String, String> parameters= new LinkedMultiValueMap<String, String>();
        parameters.add("appId", appId);
        parameters.add("bizCode", bizCode92);
        parameters.add("bizId", bizId);
        parameters.add("content", content);
        parameters.add("timestamp", timestamp);
        parameters.add("sign", sign);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(parameters,headers);
        ParameterizedTypeReference<GtwResponse<GtwShippingInfo>> ptr = new ParameterizedTypeReference<GtwResponse<GtwShippingInfo>>(){};
        try {
            ResponseEntity<GtwResponse<GtwShippingInfo>> response = restTemplate.exchange(url, HttpMethod.POST, request, ptr);
            System.out.println(response.getBody());
        } catch ( Exception e) {
            e.printStackTrace();
        }