How to use RestTemplate in Spring boot, part II
- Consumer Service
-
- pom
- Controller
- Business
-
- Consumer Business
- ConsumerBusinessImpl
- Result
-
- MaoResult
- MaoResultCode
- request
-
- Config
-
- application.yml
- JurongConfig
- knife4jConfig
- Summary
Considering the length of the article, here is an article divided into two parts, we will continue to introduce on the basis of 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 = "Consumer Management") public class ConsumerController {<!-- --> @Autowired private ConsumerBusiness consumerBusiness; @PostMapping("/consumer/account/detail") @Operation(summary = "Get consumer account details") 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
Consumer Business
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 is empty"); HuaResult<AccountDetailVO> huaResult = responseEntity.getBody(); Assert.notNull(huaResult, "result cannot be empty"); 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 = "Uniformly return entities") public class MaoResult<T> {<!-- --> /** * status code */ private String code; /** * information */ private String msg; /** * data */ 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", "Remote interface call failed"), PARSING_JSON_FAIL("PARSING_JSON_FAIL", "JSON parsing failed"), /** * Used to directly display the success of the prompt system, the content is determined by the input content */ SHOW_SUCCESS("A00002", ""), /** * unauthorized */ UNAUTHORIZED("A00004", "Unauthorized"), /** * The server is out of order */ EXCEPTION("A00005", "The server is out of order"), /** * There is no verification of method parameters, and the content is determined by the input content */ METHOD_ARGUMENT_NOT_VALID("A00014", "Method parameters are not verified"); 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 = "Account Details Request Parameters") @Data @Accessors(chain = true) public class AccountDetailRequest {<!-- --> @Schema(description = "UserID") 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+8 &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("Interface Documentation") .packagesToScan("com.qwfys.sample.maoshan") .build(); } @Bean public OpenAPI springShopOpenApi() {<!-- --> return new OpenAPI() .info( new Info() .title("Service Consumer Interface Documentation") .description("Service Consumer interface document") .version("0.0.1-SNAPSHOT") .license( new License() .name("Please abide by the MIT License authorization agreement") .url("https://github.com/ab-sample/maoshan") ) ); } }
Summary
1. After obtaining the json data with the help of RestTemplate, many times, we expect to deserialize the json data into Java Bean objects.
If the Java Bean does not contain generics, you can use the following methods to receive and deserialize data:
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)); } //... }
Pass the class corresponding to the Java Bean after json deserialization to the parameter responseType of the method.
If the Java Bean contains generics, the following methods can be used to complete data reception and deserialization:
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)); } //... }
At this time, we need to instantiate a ParameterizedTypeReference object. When instantiating, we need to instantiate the deserialized Java Bean as the generic parameter of ParameterizedTypeReference, such as:
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 is empty"); HuaResult<AccountDetailVO> huaResult = responseEntity.getBody(); Assert.notNull(huaResult, "result cannot be empty"); Assert.isTrue(huaResult.getIsSuccess(), "code:" + huaResult.getResultCode() + "message:" + huaResult.getResultMessage()); AccountDetailVO accountDetail = huaResult.getData(); return accountDetail; }
Here, HuaResult
is passed in as a generic parameter of ParameterizedTypeReference to complete the instantiation.
2. If you want to customize the RestTemplate instance, you can implement it based on the corresponding factory method when creating it, such as:
@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(); } }
If you just use it briefly, you can complete the instantiation as follows:
@Configuration public class JurongConfig {<!-- --> @Bean public RestTemplate restTemplate() {<!-- --> return new RestTemplate(); } }
I put the complete sample code in the maoshan code repository on github. If you want to see the complete code, you can download it from github.