您现在的位置是:首页 >学无止境 >How to use RestTemplate in Spring boot, part II网站首页学无止境
How to use RestTemplate in Spring boot, part II
简介How to use RestTemplate in Spring boot, part II
How to use RestTemplate in Spring boot, part II
考虑到篇幅问题,这里将一篇文章切割成了两部分,我们将在How to use RestTemplate in Spring boot, part I的基础上继续介绍。
Consumer Service
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.qwfys.sample</groupId>
<artifactId>maoshan</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.qwfys.sample</groupId>
<artifactId>maoshan-jurong</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.qwfys.sample</groupId>
<artifactId>maoshan-common</artifactId>
</dependency>
</dependencies>
</project>
Controller
package com.qwfys.sample.maoshan.jurong.controller;
import com.qwfys.sample.maoshan.common.vo.AccountDetailVO;
import com.qwfys.sample.maoshan.jurong.business.spec.ConsumerBusiness;
import com.qwfys.sample.maoshan.jurong.comon.result.MaoResultCode;
import com.qwfys.sample.maoshan.jurong.comon.result.MaoResult;
import com.qwfys.sample.maoshan.jurong.request.AccountDetailRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@Tag(name = "消费方管理")
public class ConsumerController {
@Autowired
private ConsumerBusiness consumerBusiness;
@PostMapping("/consumer/account/detail")
@Operation(summary = "获取消费方账号详情")
public MaoResult<AccountDetailVO> viewAccountDetail(@RequestHeader("Authorization") String token, @RequestBody AccountDetailRequest param) {
MaoResult<AccountDetailVO> result = null;
try {
AccountDetailVO detailVO = consumerBusiness.viewAccountDetail(token, param);
result = MaoResult.success(detailVO);
} catch (Exception e) {
log.error(e.getMessage(), e);
result = MaoResult.fail(MaoResultCode.EXCEPTION);
}
log.info("response: {}", result);
return result;
}
}
Business
ConsumerBusiness
package com.qwfys.sample.maoshan.jurong.business.spec;
import com.qwfys.sample.maoshan.common.vo.AccountDetailVO;
import com.qwfys.sample.maoshan.jurong.request.AccountDetailRequest;
/**
* @author liuwenke
* @since 0.0.1
*/
public interface ConsumerBusiness {
AccountDetailVO viewAccountDetail(String token, AccountDetailRequest param);
}
ConsumerBusinessImpl
package com.qwfys.sample.maoshan.jurong.business.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qwfys.sample.maoshan.common.result.HuaResult;
import com.qwfys.sample.maoshan.common.vo.AccountDetailVO;
import com.qwfys.sample.maoshan.jurong.business.spec.ConsumerBusiness;
import com.qwfys.sample.maoshan.jurong.request.AccountDetailRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
/**
* @author liuwenke
* @since 0.0.1
*/
@Slf4j
@Service
public class ConsumerBusinessImpl implements ConsumerBusiness {
@Autowired
private RestTemplate restTemplate;
@Override
public AccountDetailVO viewAccountDetail(String token, AccountDetailRequest param) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", token);
headers.setContentType(MediaType.APPLICATION_PROBLEM_JSON);
ObjectMapper mapper = new ObjectMapper();
String body = null;
try {
body = mapper.writeValueAsString(param);
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
HttpEntity<?> httpEntity = new HttpEntity<>(body, headers);
String apiUrl = "http://127.0.0.1:19000/provider/account/detail";
HttpMethod httpMethod = HttpMethod.POST;
ResponseEntity<HuaResult<AccountDetailVO>> responseEntity = restTemplate.exchange(
apiUrl,
httpMethod,
httpEntity,
new ParameterizedTypeReference<HuaResult<AccountDetailVO>>() {
}
);
Assert.notNull(responseEntity, "responseEntity为空");
HuaResult<AccountDetailVO> huaResult = responseEntity.getBody();
Assert.notNull(huaResult, "result不能为空");
Assert.isTrue(huaResult.getIsSuccess(), "code:" + huaResult.getResultCode() + " message:" + huaResult.getResultMessage());
AccountDetailVO accountDetail = huaResult.getData();
return accountDetail;
}
}
Result
MaoResult
package com.qwfys.sample.maoshan.jurong.comon.result;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
@Slf4j
@Builder
@Data
@AllArgsConstructor
@Schema(description = "统一返回实体")
public class MaoResult<T> {
/**
* 状态码
*/
private String code;
/**
* 信息
*/
private String msg;
/**
* 数据
*/
private T data;
public MaoResult() {
}
public boolean isSuccess() {
return Objects.equals(MaoResultCode.OK.value(), this.code);
}
public boolean isFail() {
return !Objects.equals(MaoResultCode.OK.value(), this.code);
}
public static <T> MaoResult<T> success(T data) {
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setData(data);
maoResult.setCode(MaoResultCode.OK.value());
return maoResult;
}
public static <T> MaoResult<T> success() {
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setCode(MaoResultCode.OK.value());
maoResult.setMsg(MaoResultCode.OK.getMsg());
return maoResult;
}
public static <T> MaoResult<T> success(Integer code, T data) {
return success(String.valueOf(code), data);
}
public static <T> MaoResult<T> success(String code, T data) {
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setCode(code);
maoResult.setData(data);
return maoResult;
}
public static <T> MaoResult<T> showFailMsg(String msg) {
log.error(msg);
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setMsg(msg);
maoResult.setCode(MaoResultCode.SHOW_FAIL.value());
return maoResult;
}
public static <T> MaoResult<T> fail(MaoResultCode maoResultCode) {
log.error(maoResultCode.toString());
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setMsg(maoResultCode.getMsg());
maoResult.setCode(maoResultCode.value());
return maoResult;
}
public static <T> MaoResult<T> fail(MaoResultCode maoResultCode, T data) {
log.error(maoResultCode.toString());
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setMsg(maoResultCode.getMsg());
maoResult.setCode(maoResultCode.value());
maoResult.setData(data);
return maoResult;
}
public static <T> MaoResult<T> fail(String code, String msg, T data) {
log.error(msg);
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setMsg(msg);
maoResult.setCode(code);
maoResult.setData(data);
return maoResult;
}
public static <T> MaoResult<T> fail(String code, String msg) {
return fail(code, msg, null);
}
public static <T> MaoResult<T> fail(Integer code, T data) {
MaoResult<T> maoResult = new MaoResult<>();
maoResult.setCode(String.valueOf(code));
maoResult.setData(data);
return maoResult;
}
}
MaoResultCode
package com.qwfys.sample.maoshan.jurong.comon.result;
import lombok.ToString;
/**
* @author liuwenke
* @since 0.0.1
*/
@ToString
public enum MaoResultCode {
OK("00000", "ok"),
SHOW_FAIL("A00001", ""),
REMOTE_CALL_FAIL("REMOTE_CALL_FAIL", "远程接口调用失败"),
PARSING_JSON_FAIL("PARSING_JSON_FAIL", "JSON解析失败"),
/**
* 用于直接显示提示系统的成功,内容由输入内容决定
*/
SHOW_SUCCESS("A00002", ""),
/**
* 未授权
*/
UNAUTHORIZED("A00004", "Unauthorized"),
/**
* 服务器出了点小差
*/
EXCEPTION("A00005", "服务器出了点小差"),
/**
* 方法参数没有校验,内容由输入内容决定
*/
METHOD_ARGUMENT_NOT_VALID("A00014", "方法参数没有校验");
private final String code;
private final String msg;
public String value() {
return code;
}
public String getMsg() {
return msg;
}
MaoResultCode(String code, String msg) {
this.code = code;
this.msg = msg;
}
}
Request
package com.qwfys.sample.maoshan.jurong.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@Schema(description = "账号详情请求参数")
@Data
@Accessors(chain = true)
public class AccountDetailRequest {
@Schema(description = "用户ID")
private Long userId;
}
Config
application.yml
mybatis-plus:
global-config:
banner: false
server:
port: 19001
spring:
datasource:
url: jdbc:mysql://127.0.0.1:23306/jurong?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
username: root
password: Gah6kuP7ohfio4
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 0
maximum-pool-size: 20
idle-timeout: 10000
auto-commit: true
connection-test-query: SELECT 1
JurongConfig
package com.qwfys.sample.maoshan.jurong.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @author liuwenke
* @since 0.0.1
*/
@Configuration
public class JurongConfig {
private static final int CONNECT_TIMEOUT = 8000;
private static final int SOCKET_TIMEOUT = 8000;
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
//factory.setConnectTimeout(CONNECT_TIMEOUT);
//factory.setReadTimeout(SOCKET_TIMEOUT);
return new RestTemplate(factory);
//return new RestTemplate();
}
}
knife4jConfig
package com.qwfys.sample.maoshan.jurong.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author liuwenke
* @since 0.0.1
*/
@Configuration
public class knife4jConfig {
@Bean
public GroupedOpenApi baseRestApi() {
return GroupedOpenApi.builder()
.group("接口文档")
.packagesToScan("com.qwfys.sample.maoshan")
.build();
}
@Bean
public OpenAPI springShopOpenApi() {
return new OpenAPI()
.info(
new Info()
.title("Service Consumer接口文档")
.description("Service Consumer接口文档")
.version("0.0.1-SNAPSHOT")
.license(
new License()
.name("使用请遵守MIT License授权协议")
.url("https://github.com/ab-sample/maoshan")
)
);
}
}
Summary
1、借助RestTemplate取到json数据以后,很多时候,我们都期望将json数据反序列化为Java Bean对象。
如果Java Bean不包含泛型,可以借助如下方法完成数据的接收与反序列化:
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
@Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
}
}
将json反序列化后的Java Bean对应的class传给方法的参数responseType。
如果Java Bean包含泛型,可以借助如下方法完成数据的接收与反序列化:
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
@Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {
Type type = responseType.getType();
RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
}
}
这个时候,我们要实例化一个ParameterizedTypeReference的对象出来,实例化的时候,需要将json反序列化后的Java Bean做为ParameterizedTypeReference的泛型参数来实例化,如:
public AccountDetailVO viewAccountDetail(String token, AccountDetailRequest param) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", token);
headers.setContentType(MediaType.APPLICATION_PROBLEM_JSON);
ObjectMapper mapper = new ObjectMapper();
String body = null;
try {
body = mapper.writeValueAsString(param);
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
HttpEntity<?> httpEntity = new HttpEntity<>(body, headers);
String apiUrl = "http://127.0.0.1:19000/provider/account/detail";
HttpMethod httpMethod = HttpMethod.POST;
ResponseEntity<HuaResult<AccountDetailVO>> responseEntity = restTemplate.exchange(
apiUrl,
httpMethod,
httpEntity,
new ParameterizedTypeReference<HuaResult<AccountDetailVO>>() {
}
);
Assert.notNull(responseEntity, "responseEntity为空");
HuaResult<AccountDetailVO> huaResult = responseEntity.getBody();
Assert.notNull(huaResult, "result不能为空");
Assert.isTrue(huaResult.getIsSuccess(), "code:" + huaResult.getResultCode() + " message:" + huaResult.getResultMessage());
AccountDetailVO accountDetail = huaResult.getData();
return accountDetail;
}
这里将HuaResult<AccountDetailVO>
做为ParameterizedTypeReference的泛型参数传入,完成实例化。
2、如果要对RestTemplate实例做定制化,在创建的时候,可以基于相应的工厂方法实现,如:
@Configuration
public class JurongConfig {
private static final int CONNECT_TIMEOUT = 8000;
private static final int SOCKET_TIMEOUT = 8000;
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(CONNECT_TIMEOUT);
factory.setReadTimeout(SOCKET_TIMEOUT);
return new RestTemplate(factory);
//return new RestTemplate();
}
}
如果只是简单用一下,可以用如下方式完成实例化:
@Configuration
public class JurongConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
完整的样例代码我放到github上的maoshan代码仓库了,如果想看完整的代码可以到github下载。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。