Spring RestTemplate 使用一则

RestTemplate API

定义默认的 RestTemplate

/**
 * 定义restTemplate的配置
 * 
 * @author wenbronk
 * @Date 下午4:33:35
 */
@Configuration
public class RestTemplateConfig {
 
    @Bean
    @ConditionalOnMissingBean({ RestOperations.class, RestTemplate.class })
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        // return new RestTemplate(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")));
 
        return restTemplate;
    }
 
    @Bean
    @ConditionalOnMissingBean({ClientHttpRequestFactory.class})
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(15000);// ms
        factory.setConnectTimeout(15000);// ms
        return factory;
    }
}
 

Rest API 方法规范

HTTP 方法核心语义幂等性安全性场景
GET读取 / 查询资源获取单个用户:GET /users/123;获取所有订单:GET /orders
POST创建新资源创建订单:POST /orders;注册用户:POST /users
PUT全量更新资源(替换)更新用户全部信息:PUT /users/123
PATCH部分更新资源仅更新用户昵称:PATCH /users/123
DELETE删除资源删除订单:DELETE /orders/456

对象&数组以及请求头参数 (复杂的请求)

HttpEntity

HttpEntity<T>这个对象可以存放复杂的请求参数; 泛型是请求参数体; (GET没有请求体,也是可以的), 构造它需要 参数体, 请求头; 参数体可为null; HttpEntity<T> request = new HttpEntity<T>(param, headers);

默认情况下, 请求体 会转为json 请求

数组参数问题

    Long [] ids
    StreamServer streamServer = getCurrentStreamServer();
    String server_http_uri =  streamServer.getServerHttpUri();
    String url = server_http_uri+ MAPP_URI+"/query_by_ids?ids={ids}";
 
    HttpHeaders headers = new HttpHeaders(); 
    //headers.add("token", streamServer.getInsideVerify());
    HttpEntity request = new HttpEntity(ids, headers);
 
    return restTemplate.exchange(url, HttpMethod.GET, httpEntity, List.class,httpEntity.getBody());
    //return restTemplate.exchange(url, HttpMethod.GET, httpEntity, List.class,ids);

最后一个参数必须要, 而且必须通过httpEntity.getBody()获取,否则ids会丢掉后面下标, 什么鬼..?

在form-data 中

RestTemplate restTemplate = new RestTemplate();
String url = "http://ifreezer.zkmeiling.com/sample/source/add/insert.do";
HttpHeaders headers = new HttpHeaders();
headers.add("Cookie", "JSESSIONID=5B7130B20A1E78F2DB60E4D3B8CF8E1D");
 
 
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
@SuppressWarnings("rawtypes")
MultiValueMap map = new LinkedMultiValueMap();
map.add("sourceName","广东省畜禽种质地方猪采样-test220");
map.add("sourceTypeId",SOURCE_TYPE_ID);
for (int i = 0; i < sourceFieldValues.length; i++) {
    map.add("sourceFieldValues[]",  sourceFieldValues[i]);
}
 
 
HttpEntity requestBody = new HttpEntity(map, headers);
 
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, requestBody, String.class);
 
System.out.println(responseEntity.getBody() );
 

forEntity 因为泛型导致 LinkMap的问题

/**
封装一个方法 可接受泛型
**/
	public static <T, A> T exchange(String url, HttpMethod method, ParameterizedTypeReference<T> responseBodyType, A requestBody, Object... params) {
		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, params);
		return resultEntity.getBody();
	}
 
//使用
ParameterizedTypeReference<OriginalDataBean<Sl_collection_data>> typeRef = new ParameterizedTypeReference<OriginalDataBean<Sl_collection_data>>() {};
OriginalDataBean<Sl_collection_data> bean = exchange(url, HttpMethod.GET, typeRef, null, greaterId);

自定义消息转换器

getRestTemplate().getMessageConverters().add(e)

忽略证书 https

import java.net.HttpURLConnection;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
 
@Bean
public RestTemplate restTemplate() throws NoSuchAlgorithmException, KeyManagementException {
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[]{new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
 
        }
 
        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
 
        }
 
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }}, new java.security.SecureRandom());
    SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
    CloseableHttpClient httpClient = HttpClients.custom()
            .setSSLSocketFactory(csf)
            .build();
    HttpComponentsClientHttpRequestFactory requestFactory =
            new HttpComponentsClientHttpRequestFactory();
 
    requestFactory.setHttpClient(httpClient);
    RestTemplate restTemplate = new RestTemplate(requestFactory);
    //处理中文乱码
    restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    return restTemplate;
}