1、RestTemplate是什么
传统情况下在java代码里访问restful服务,一般使用Apache的HttpClient。不过此种方法使用起来太过繁琐。spring提供了一种简单便捷的模板类来进行操作,这就是RestTemplate。
2、封装使用
package com.recallg.demo.utils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URLEncoder;
import java.util.*;
import java.util.zip.GZIPInputStream;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
/**
* Curl Api请求类库
*/
@Slf4j
public class Curl {
// 请求结果
private String result = "";
/**
* RestTemplate 请求构造内部类
*/
public static class Builder {
// 请求URL
private String url;
// basic auth用户名
private String userName;
// basic auth密码
private String passWord;
// 请求方式 默认为GET
private HttpMethod methodType = GET;
// 请求参数
private HashMap<String, String> paramMap;
// 请求header头
private HashMap<String, String> headerMap;
// RestTemplate 实例
private RestTemplate client;
// header头实例
private HttpHeaders headers;
// 请求结果
private String result;
public Builder(String url) {
this.url = url;
}
/**
* basic auth 认证类型请求
* @param url
* @param userName
* @param passWord
*/
public Builder(String url, String userName, String passWord) {
this.url = url;
this.userName = userName;
this.passWord = passWord;
}
/**
* 添加参数
* @param key 参数key
* @param value 参数内容
* @return Builder
*/
public Builder addParam(String key, String value) {
if (paramMap == null) {
paramMap = new LinkedHashMap<>(16);
}
paramMap.put(key, value);
return this;
}
/**
* 添加header参数
* @param key 参数key
* @param value 参数内容
* @return Builder
*/
public Builder addHeader(String key, String value) {
if (headerMap == null) {
headerMap = new LinkedHashMap<>(16);
}
headerMap.put(key, value);
return this;
}
/**
* GET 请求
* @return Curl
*/
public Curl get() {
this.methodType = GET;
this.getResponse(MediaType.APPLICATION_FORM_URLENCODED);
return new Curl(this);
}
/**
* post 请求
* @return Curl
*/
public Curl post() {
this.methodType = POST;
this.getResponse(MediaType.APPLICATION_FORM_URLENCODED);
return new Curl(this);
}
/**
* raw 方式提交json 请求
* @return Curl
*/
public Curl postRaw() {
HashMap<String, Object> paramRawMap = new HashMap<>();
return this.raw(paramRawMap);
}
/**
* raw 方式提交json 请求
* @param paramRawMap Map数据
* @return Curl
*/
public Curl postRaw(HashMap<String, Object> paramRawMap) {
return this.raw(paramRawMap);
}
private Curl raw(HashMap<String, Object> paramRawMap) {
client = new RestTemplate();
client.setErrorHandler(new RestErrorHandler());
headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
this.setHeadersMapData();
this.responseRawExchange(JSON.toJSONString(paramRawMap));
return new Curl(this);
}
public SimpleClientHttpRequestFactory getFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
//单位为ms
factory.setReadTimeout(10 * 1000);
//单位为ms
factory.setConnectTimeout(30 * 1000);
// 代理的url网址或ip, port端口
InetSocketAddress address = new InetSocketAddress("36.110.168.141", 9039);
Proxy proxy = new Proxy(Proxy.Type.HTTP, address);
factory.setProxy(proxy);
return factory;
}
/**
* 初始化请求体
* @param type 请求类型
*/
private void getResponse(MediaType type) {
client = new RestTemplate();
client.setErrorHandler(new RestErrorHandler());
headers = new HttpHeaders();
headers.setContentType(type);
this.setHeadersMapData();
MultiValueMap<String, String> params = this.setHttpMethodParamsMap();
this.responseExchange(params);
}
/**
* 设置header头数据
*/
private void setHeadersMapData() {
if (headerMap != null){
headerMap.forEach((k, v) -> {
this.headers.set(k, v);
});
}
// 设置basic auth请求方式认证信息
if (this.userName != null && this.passWord != null) {
String secretKey = this.userName + ":" + this.passWord;
String authValue = "Basic " + Base64.getEncoder()
.encodeToString(secretKey.getBytes());
this.headers.set("Authorization", authValue);
}
}
/**
* 组装请求体参数
* @return MultiValueMap<String, String>
*/
private MultiValueMap<String, String> setHttpMethodParamsMap() {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
if (this.methodType.equals(GET)) {
if (this.paramMap != null) {
String _UrlParams = getUrlParamsByMap(this.paramMap);
this.url = this.url + "?" + _UrlParams;
}
if (this.paramMap != null) {
this.paramMap.forEach((k, v) -> {
params.put(k, Collections.singletonList(v));
});
}
} else if (this.methodType.equals(POST)) {
if (this.paramMap != null) {
this.paramMap.forEach((k, v) -> {
params.put(k, Collections.singletonList(v));
});
}
}
return params;
}
/**
* 执行Curl请求操作
* @param params 请求体参数
*/
private void responseExchange(MultiValueMap<String, String> params) {
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, this.headers);
// 执行HTTP请求,将返回的结构使用spring ResponseEntity处理http响应
ResponseEntity<byte[]> responseEntity = this.client.exchange(this.url, this.methodType, requestEntity, byte[].class);
String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);
int httpCode = responseEntity.getStatusCodeValue();
String httpCodeValue = responseEntity.getStatusCode().toString();
log.info("状态码:{}", httpCodeValue);
try {
if ("gzip".equals(contentEncoding)) {
// gzip解压服务器的响应体
byte[] data = unGZip(new ByteArrayInputStream(responseEntity.getBody()));
// log.info(new String(data, StandardCharsets.UTF_8));
this.result = new String(data);
} else {
// 其他编码暂时不做处理(如果需要处理其他编码请自行扩展)
this.result = new String(responseEntity.getBody());
}
} catch (NullPointerException e) {
log.error("请求错误: {}", e.getMessage());
this.result = httpCodeValue;
}
}
/**
* 执行Curl Raw JSON请求操作
* @param params 请求体参数
*/
private void responseRawExchange(String params) {
HttpEntity<String> requestEntity = new HttpEntity<>(params, this.headers);
// 执行HTTP请求,将返回的结构使用spring ResponseEntity处理http响应
ResponseEntity<byte[]> responseEntity = this.client.postForEntity(this.url, requestEntity, byte[].class);
String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);
if ("gzip".equals(contentEncoding)) {
// gzip解压服务器的响应体
byte[] data = unGZip(new ByteArrayInputStream(responseEntity.getBody()));
this.result = new String(data);
} else {
// 其他编码暂时不做处理(如果需要处理其他编码请自行扩展)
this.result = new String(responseEntity.getBody());
}
}
/**
* Gzip解压缩
* @param inputStream 数据流
* @return byte[]
*/
private byte[] unGZip(InputStream inputStream) {
byte[] result = null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {
byte[] buf = new byte[4096];
int len = -1;
while ((len = gzipInputStream.read(buf, 0, buf.length)) != -1) {
byteArrayOutputStream.write(buf, 0, len);
}
result = byteArrayOutputStream.toByteArray();
} finally {
byteArrayOutputStream.close();
}
} catch (IOException e) {
log.error("unGZip error :", e);
}
return result;
}
/**
* 组装GET参数
* @param params 参数
* @return String
*/
private String getUrlParamsByMap(Map<String, String> params) {
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
String prestr = "";
try {
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
value = URLEncoder.encode(value, "UTF-8");
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
} catch (UnsupportedEncodingException e) {
log.error("GET params error: {}", e);
}
return prestr;
}
}
/**
* RestTemplate 异常处理
*/
public static class RestErrorHandler implements ResponseErrorHandler {
/**
* 判断返回结果response是否是异常结果
* 主要是去检查response 的HTTP Status
* 仿造DefaultResponseErrorHandler实现即可
*/
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
int rawStatusCode = response.getRawStatusCode();
HttpStatus statusCode = HttpStatus.resolve(rawStatusCode);
return (statusCode != null ? statusCode.isError(): hasError(rawStatusCode));
}
protected boolean hasError(int unknownStatusCode) {
HttpStatus.Series series = HttpStatus.Series.resolve(unknownStatusCode);
return (series == HttpStatus.Series.CLIENT_ERROR || series == HttpStatus.Series.SERVER_ERROR);
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// 里面可以实现你自己遇到了Error进行合理的处理
//TODO 将接口请求的异常信息持久化
}
}
public Curl(Builder builder) {
this.result = builder.result;
}
public String build() {
return this.result;
}
}
3、使用方法
1、GET方式
String result = new Curl.Builder("http://api.test.com/list")
.addParam("test", "A")
.addParam("ssss", "B")
.addHeader("Content-Type", "application/json; charset=utf-8")
.get().build();
log.info("测试GET:{}", result);
2、POST方式
String result = new Curl.Builder("http://api.test.com/add")
.addParam("test", "A")
.addParam("ssss", "B")
.addHeader("Content-Type", "application/json; charset=utf-8")
.post().build();
log.info("测试POST:{}", result);
3、POST JSON方式(RAW)
ArrayList arr = new ArrayList<>();
arr.add("test params");
HashMap<String, Object> params = new HashMap<>();
params.put("tags", arr);
String result = new Curl.Builder("http://api.test.com/test")
.addHeader("Content-Type", "application/json; charset=utf-8")
.postRaw(params).build();
log.info("测试POST JSON:{}", result);
4、POST/GET 方式basic auth验证
String url = "http://api.test.com/test";
result = new Curl.Builder(url, "username", "password")
.addHeader("Content-Type", "application/json; charset=utf-8")
.post().build();
log.info("测试POST/GET basic auth:{}", result);