前言
项目中有个模板的功能是可以模仿postman进行http请求。 之前使用过httpClient,这次就来试试看更加模板化的RestTemplate吧~
关于RestTemplate的教程网上有很多,但大多都是秉着授人以渔的心态写的,也就是说在实战方面写得并不是很详细。这次我就借着模块开发的机会,来分享一下我是怎么编写http请求工具类的吧。
首先,要使用RestTemplate的exchange方法作为整个工具类的基础,借助它的可自定义配置,我们可以实现 使用任意格式的请求参数 和 返回任意格式的结果。这对于一个工具类来说是非常重要的。
需要注意的是,在RestTemplate中使用post方式请求 + 使用formdata格式传递body参数时,不能使用Map,需要要使用MultiValueMap。
实战环节
代码如下(示例):
/**
* RestTemplateUtils 【http请求工具类】
* 1. sendGet() sendPost() 是正常http请求
* <br>
* 2. sendGetByByte() sendPostByByte() 是用来下载字节流的
* <br>
* 3. 支持的请求方式:<br>
* <b>
* post请求 -json传参<br>
* post请求 -formData传参<br>
* get请求 -占位符传参<br>
* get请求 -url拼接<br>
* </b>
*
* @author xurenyi
* @since 2023/3/29 17:36
**/
public class RestTemplateUtils {
private static Logger logger = LoggerFactory.getLogger("RestTemplateUtils");
private volatile static RestTemplate restTemplate;
/**
* GET请求
*
* @param url
* @param returnDataType 返回数据的格式 JSONObject|JSONArray.class|String.class|Map.class|ArrayList.class,可为空
* @param requestHeaders 请求头,可为空
* @param requestParams 求参数,可为空
* @return 结果
*/
public static Object sendGet(String url,
@Nullable Class<?> returnDataType,
@Nullable Map<String, Object> requestHeaders,
@Nullable Map<String, Object> requestParams) {
return httpRequest(url, HttpMethod.GET, requestHeaders, requestParams, null, returnDataType, JSONObject.class);
}
/**
* POST请求
*
* @param url
* @param returnDataType 返回数据的格式 JSONObject|JSONArray.class|String.class|Map.class|ArrayList.class,可为空
* @param requestHeaders 请求头,可为空
* @param requestParams 请求参数,可为空
* @param requestBody 请求体,可为空
* @param sendDataType 请求体格式 json|jsonArray
* @return 结果
*/
public static Object sendPost(String url,
@Nullable Class<?> returnDataType,
@Nullable Map<String, Object> requestHeaders,
@Nullable Map<String, Object> requestParams,
@Nullable String requestBody,
Class<?> sendDataType) {
return httpRequest(url, HttpMethod.POST, requestHeaders, requestParams, requestBody, returnDataType, sendDataType);
}
/**
* POST请求 字节流
*
* @param url
* @param response http响应消息,可为空
* @param requestHeaders 请求头,可为空
* @param requestParams 请求参数,可为空
* @param requestBody 请求体,可为空
* @param sendDataType 请求体格式 json|jsonArray
**/
public static void sendPostByByte(String url, HttpServletResponse response,
@Nullable Map<String, Object> requestHeaders,
@Nullable Map<String, Object> requestParams,
@Nullable String requestBody,
Class<?> sendDataType) {
download(url, HttpMethod.POST, requestHeaders, requestParams, requestBody, response, false, sendDataType);
}
/**
* GET请求 字节流
*
* @param url
* @param response http响应消息,可为空
* @param requestHeaders 请求头,可为空
* @param requestParams 请求参数,可为空
**/
public static void sendGetByByte(String url, HttpServletResponse response,
@Nullable Map<String, Object> requestHeaders,
@Nullable Map<String, Object> requestParams) {
download(url, HttpMethod.GET, requestHeaders, requestParams, null, response, false, JSONObject.class);
}
/**
* 发送http请求
*
* @param url
* @param method
* @param requestHeaders
* @param requestParams
* @param requestBody
* @param returnDataType
* @return
*/
public static <T> Object httpRequest(String url, HttpMethod method,
@Nullable Map<String, Object> requestHeaders,
@Nullable Map<String, Object> requestParams,
@Nullable String requestBody,
@Nullable Class<?> returnDataType,
Class<?> sendDataType) {
Map<String, Object> params = new HashMap<>();
HttpHeaders headers = new HttpHeaders();
// 1. post请求 -json传参
// 2. post请求 -formData传参
// 3. get请求 -占位符传参
// 4. get请求 -url拼接
// 第一步 构建httpEntity
HttpEntity<?> entity = buildHttpEntity(sendDataType, method, requestHeaders, requestParams, requestBody, params, headers);
// 第二步 单例调用restTemplate
RestTemplate restTemplate = getSingleRestTemplate();
// 第三步 初始化一个返回值
Object r = null;
// 第四步 执行http请求,并根据情况给返回值赋值
try {
Class<?> resultClass = String.class;
if (returnDataType != null) {
resultClass = returnDataType;
r = handleHttpRequest(restTemplate, resultClass, url, method, params, entity);
} else {
handleHttpRequest(restTemplate, resultClass, url, method, params, entity);
}
} catch (RestClientException e) {
logger.error("远程调用接口异常{}", e);
}
return r;
}
/**
* 下载
*
* @param url
* @param method
* @param requestHeaders
* @param requestParams
* @param requestBody
* @param response
* @param isRespBodyOnly 是否是只需要响应体,默认true,true:只需要响应体 false:同时返回响应状态 响应头 响应体
*/
public static void download(String url, HttpMethod method,
@Nullable Map<String, Object> requestHeaders,
@Nullable Map<String, Object> requestParams,
@Nullable String requestBody,
HttpServletResponse response,
@Nullable Boolean isRespBodyOnly,
Class<?> sendDataType) {
if (Objects.isNull(isRespBodyOnly)) {
isRespBodyOnly = true;
}
HttpHeaders headers = new HttpHeaders();
Map<String, Object> params = new HashMap<>();
// 第一步 构建httpEntity
HttpEntity<?> entity = buildHttpEntity(sendDataType, method, requestHeaders, requestParams, requestBody, params, headers);
// 第二步 单例调用restTemplate
RestTemplate restTemplate = getSingleRestTemplate();
// 第三步 执行http请求,并返回字节流
handleHttpRequest(restTemplate, url, method, response, isRespBodyOnly, params, entity);
}
/**
* 构建httpEntity
*
* @param method
* @param requestHeaders
* @param requestParams
* @param requestBody
* @param params
* @param headers
* @return
*/
private static HttpEntity<?> buildHttpEntity(Class<?> sendDataType, HttpMethod method, Map<String, Object> requestHeaders, Map<String, Object> requestParams, String requestBody, Map<String, Object> params, HttpHeaders headers) {
//1.设置请求参数
if (requestParams != null && !requestParams.isEmpty()) {
Iterator<Map.Entry<String, Object>> paramsIterator = requestParams.entrySet().iterator();
Map.Entry<String, Object> nextParam = null;
while (paramsIterator.hasNext()) {
nextParam = paramsIterator.next();
params.put(nextParam.getKey(), nextParam.getValue());
}
}
//2.设置请求头
if (requestHeaders != null && !requestHeaders.isEmpty()) {
Iterator<Map.Entry<String, Object>> headersIterator = requestHeaders.entrySet().iterator();
Map.Entry<String, Object> nextHeader = null;
while (headersIterator.hasNext()) {
nextHeader = headersIterator.next();
headers.add(nextHeader.getKey(), String.valueOf(nextHeader.getValue()));
}
}
//3.设置请求体
//4.请求体 请求头封装到HttpEntity
String contentType = String.valueOf(requestHeaders.get(EtlHttpRequestConstant.CONTENT_TYPE));
if (requestBody != null && !requestBody.isEmpty()) {
if (sendDataType == null || sendDataType.equals(JSONObject.class)) {
Map<String, Object> requestBodyMap = JSONObject.parseObject(requestBody, Map.class);
Map bodyMap;
if (MediaType.APPLICATION_JSON_VALUE.equals(contentType) || HttpMethod.GET.equals(method)) {
bodyMap = setEntityBody(Map.class, requestBodyMap);
} else {
bodyMap = setEntityBody(LinkedMultiValueMap.class, requestBodyMap);
}
return new HttpEntity<>(bodyMap, headers);
} else if (sendDataType.equals(JSONArray.class)) {
List<Map> requestBodyMapList = JSON.parseArray(requestBody, Map.class);
List<Map> bodyMapList = new ArrayList<>();
if (MediaType.APPLICATION_JSON_VALUE.equals(contentType) || HttpMethod.GET.equals(method)) {
requestBodyMapList.forEach(i -> bodyMapList.add(setEntityBody(Map.class, i)));
} else {
requestBodyMapList.forEach(i -> bodyMapList.add(setEntityBody(LinkedMultiValueMap.class, i)));
}
return new HttpEntity<>(bodyMapList, headers);
} else if (sendDataType.equals(String.class)) {
return new HttpEntity<>(requestBody, headers);
}
}
// todo 如果是其他情况,则返回null
return new HttpEntity<>(null, headers);
}
/**
* 请求http请求
*
* @param restTemplate
* @param typeClass
* @param url
* @param method
* @param params
* @param entity
* @param <T>
* @return
*/
private static <T> T handleHttpRequest(RestTemplate restTemplate, Class<T> typeClass, String url, HttpMethod method, Map<String, Object> params, HttpEntity<?> entity) {
ResponseEntity<T> exchange = restTemplate.exchange(url, method, entity, typeClass, params);
return typeClass.cast(exchange.getBody());
}
/**
* 处理http请求(字节流)
*
* @param restTemplate
* @param url
* @param method
* @param response
* @param isRespBodyOnly
* @param params
* @param entity
*/
private static void handleHttpRequest(RestTemplate restTemplate, String url, HttpMethod method, HttpServletResponse response, Boolean isRespBodyOnly, Map<String, Object> params, HttpEntity<?> entity) {
BufferedOutputStream bos = null;
try {
ResponseEntity<byte[]> exchange = restTemplate.exchange(url, method, entity, byte[].class, params);
if (!isRespBodyOnly && response != null) {
setResponseDetails(response, exchange);
}
// FIXME: 2023/3/29 by.xurenyi 修改下载文件流的格式,此处有些小问题,暂定使用原接口的文件格式~~~
// response.reset();
// response.setContentType("pdf/plain");
// response.setContentType("application/octet-stream;charset=UTF-8");
// response.setHeader("Content-Type", "application/octet-stream;charset=UTF-8");
// response.setHeader("Content-Disposition", "attachment; filename=" + "test" + ".pdf");
//响应体
ServletOutputStream os = response.getOutputStream();
bos = new BufferedOutputStream(os);
byte[] buf = exchange.getBody();
bos.write(buf);
bos.flush();
} catch (IOException e) {
logger.error("RestTemplateUtils获取接口二进制流异常");
} catch (RestClientException e) {
logger.error("远程调用接口异常{}", e);
} finally {
try {
bos.close();
} catch (IOException e) {
logger.error("RestTemplateUtils流关闭异常");
}
}
}
/**
* 设置http响应详情
*
* @param response
* @param exchange
* @param <T>
*/
private static <T> void setResponseDetails(HttpServletResponse response, ResponseEntity<T> exchange) {
//响应状态码
response.setStatus(exchange.getStatusCodeValue());
//响应头,可能存在一个key对应多个value,本方法中会将同名header合并
HttpHeaders resHeaders = exchange.getHeaders();
Iterator<Entry<String, List<String>>> resHeadersIterator = resHeaders.entrySet().iterator();
while (resHeadersIterator.hasNext()) {
Entry<String, List<String>> headersNext = resHeadersIterator.next();
response.setHeader(headersNext.getKey(), headersNext.getValue().toString());
}
}
/**
* 设置entity
*
* @param beanClass
* @param requestBody
* @return
*/
private static Map setEntityBody(Class<? extends Map> beanClass, Map<String, Object> requestBody) {
Object entityBody;
Iterator<Entry<String, Object>> bodyIterator = requestBody.entrySet().iterator();
Entry<String, Object> bodyNext;
if (beanClass.equals(MultiValueMap.class) || beanClass.equals(LinkedMultiValueMap.class)) {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
while (bodyIterator.hasNext()) {
bodyNext = bodyIterator.next();
map.add(bodyNext.getKey(), bodyNext.getValue());
}
entityBody = map;
} else if (beanClass.equals(Map.class)) {
Map<String, Object> map = new HashMap<>();
while (bodyIterator.hasNext()) {
bodyNext = bodyIterator.next();
map.put(bodyNext.getKey(), bodyNext.getValue());
}
entityBody = map;
} else {
Map<String, Object> map = new HashMap<>();
while (bodyIterator.hasNext()) {
bodyNext = bodyIterator.next();
map.put(bodyNext.getKey(), bodyNext.getValue());
}
entityBody = map;
}
return beanClass.cast(entityBody);
}
/**
* RestTemplate 单例 懒汉 双检锁
**/
public static RestTemplate getSingleRestTemplate() {
if (restTemplate == null) {
synchronized (RestTemplateUtils.class) {
if (restTemplate == null) {
restTemplate = new RestTemplate();
}
}
}
return restTemplate;
}
}
版权归原作者 醒盼梦惜忆甚悠 所有, 如有侵权,请联系我们删除。