How to use RestTemplate in Spring boot, part I

How to use RestTemplate in Spring boot, part I

  • Overview
    • goal
  • Maoshan
  • pom
  • Common Service
    • pom
    • DTO
      • AccountDetailDTO
    • VO
      • AccountDetailVO
      • DeptVO
      • RoleVO
    • Result
      • HuaResult
      • HuaResultCode
      • IResultCode
  • Provider Service
    • pom
    • Controller
      • ProviderController
    • Business
      • Account Business
      • AccountBusinessImpl
    • config
      • application.yml
      • knife4jConfig

Overview

In projects, we often encounter situations where we need to obtain data from another system through http. For this requirement, most people may use Apache HttpClient to achieve it, and some people may use OkHttp or other components to achieve it. .

In Spring boot, Spring boot provides us with an http client component named RestTemplate. Based on it, we can also fulfill the above demands. Most people are familiar with the usage of RestTemplate, so I won’t go into details here. Today we will focus on how to deserialize the json string generated by the data provider based on generics into a complete Java Bean object.

Goal

Here is a fragment of the json of the data generated by the service provider when the Provider responds to the service:

{<!-- -->
  "isSuccess": true,
  "resultCode": "00000",
  "resultMessage": "The operation was successful!",
  "data": {<!-- -->
    "userId": "1639178930477944839",
    "userName": "welcome",
    "fullName": "welcome",
    "telephone": "13800000000",
    "dept": null,
    "roles": [
      {<!-- -->
        "id": "11",
        "code": "ADMIN",
        "name": "Administrator"
      },
      {<!-- -->
        "id": "12",
        "code": "BUYER",
        "name": "Buyer"
      },
      {<!-- -->
        "id": "13",
        "code": "SELLER",
        "name": "Business"
      }
    ]
  }
}

We hope that after the service consumer gets the data, it can deserialize the json into the corresponding Java Bean. Next, we will introduce the general solution to this kind of problem in detail from the two directions of the service provider and the service consumer with a practical case.

Maoshan

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/>
    </parent>

    <groupId>com.qwfys.sample</groupId>
    <artifactId>maoshan</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>maoshan</name>
    <description>maoshan</description>

    <modules>
        <module>maoshan-common</module>
        <module>maoshan-huayang</module>
        <module>maoshan-jurong</module>
    </modules>

    <properties>
        <java.version>17</java.version>
        <com.qwfys.sample.maoshan.version>0.0.1-SNAPSHOT</com.qwfys.sample.maoshan.version>
        <knife4j-openapi3-jakarta-spring-boot-starter.version>4.0.0
        </knife4j-openapi3-jakarta-spring-boot-starter.version>
        <hutool.version>5.8.12</hutool.version>
        <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-http</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.qwfys.sample</groupId>
                <artifactId>maoshan-common</artifactId>
                <version>${com.qwfys.sample.maoshan.version}</version>
            </dependency>
            <dependency>
                <groupId>com.qwfys.sample</groupId>
                <artifactId>maoshan-huayang</artifactId>
                <version>${com.qwfys.sample.maoshan.version}</version>
            </dependency>
            <dependency>
                <groupId>com.qwfys.sample</groupId>
                <artifactId>maoshan-jurong</artifactId>
                <version>${com.qwfys.sample.maoshan.version}</version>
            </dependency>

            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-core</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-extra</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-jwt</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-http</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-poi</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-cache</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-crypto</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-db</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
                <version>${knife4j-openapi3-jakarta-spring-boot-starter.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Common 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-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</project>

DTO

AccountDetailDTO

package com.qwfys.sample.maoshan.common.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;

/**
 * @author liuwenke
 * @since 0.0.1
 */
@Schema(description = "Account Details Request Parameters")
@Data
@Accessors(chain = true)
public class AccountDetailDTO {<!-- -->

    @Schema(description = "UserID")
    private Long userId;
}

VO

AccountDetailVO

package com.qwfys.sample.maoshan.common.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;

@Schema(description = "Account Details")
@Data
@Accessors(chain = true)
public class AccountDetailVO {<!-- -->

    @Schema(description = "UserID")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private Long userId;

    @Schema(description = "Username")
    private String userName;

    @Schema(description = "Name")
    private String fullName;

    @Schema(description = "Phone Number")
    private String telephone;

    @Schema(description = "Department")
    private DeptVO dept;

    @Schema(description = "role list")
    private List<RoleVO> roles;
}

DeptVO

package com.qwfys.sample.maoshan.common.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;

@Schema(description = "Department")
@Data
@Accessors(chain = true)
public class DeptVO {<!-- -->

    @JsonFormat(shape = JsonFormat.Shape.STRING)
    @Schema(description = "Department ID")
    private Long id;

    @Schema(description = "Department Name")
    private String name;

    @Schema(description = "Department path")
    private String path;
}

RoleVO

package com.qwfys.sample.maoshan.common.vo;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;

@Schema(description = "Role")
@Data
@Accessors(chain = true)
public class RoleVO {<!-- -->

    @JsonFormat(shape = JsonFormat.Shape.STRING)
    @Schema(description = "Role ID")
    private Long id;

    @Schema(description = "role encoding")
    private String code;

    @Schema(description = "role name")
    private String name;
}

Result

HuaResult

package com.qwfys.sample.maoshan.common.result;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok. AllArgsConstructor;
import lombok. Builder;
import lombok.Data;

/**
 * @author liuwenke
 * @since 0.0.1
 */
@Builder
@Data
@AllArgsConstructor
@Schema(description = "Uniformly return entities")
public class HuaResult<T> {<!-- -->
    @Schema(description = "Successful")
    private Boolean isSuccess = false;

    @Schema(description = "Response code")
    private String resultCode;

    @Schema(description = "message")
    private String resultMessage;

    @Schema(description = "data")
    private T data;

    public HuaResult() {<!-- -->
        this.resultCode = StrUtil.toString(HttpStatus.HTTP_OK);
        this.resultMessage = "";
        this.data = null;
    }

    public HuaResult(Boolean isSuccess, int resultCode, T data, String resultMessage) {<!-- -->
        this.isSuccess=isSuccess;
        this.resultCode = StrUtil.toString(resultCode);
        this.data = data;
        this.resultMessage = resultMessage;
    }

    // Constructor on error
    public HuaResult(int resultCode, T data, String resultMessage) {<!-- -->
        this.resultCode = StrUtil.toString(resultCode);
        this.data = data;
        this.resultMessage = resultMessage;
    }

    private HuaResult(IResultCode resultCode) {<!-- -->
        this(resultCode.isSuccess(), resultCode.resultCode(), resultCode.resultMessage(), null);
    }

    private HuaResult(IResultCode resultCode, String message) {<!-- -->
        this(resultCode.isSuccess(), resultCode.resultCode(), message, null);
    }

    private HuaResult(IResultCode resultCode, T data) {<!-- -->
        this(resultCode.isSuccess(), resultCode.resultCode(), resultCode.resultMessage(), data);
    }

    private HuaResult(IResultCode resultCode, String message, T data) {<!-- -->
        this(resultCode.isSuccess(), resultCode.resultCode(), message, data);
    }

    public static <T> HuaResult<T> data(T data) {<!-- -->
        return data(HuaResultCode.SUCCESS.resultMessage, data);
    }

    public static <T> HuaResult<T> data(String message, T data) {<!-- -->
        return data(HuaResultCode.SUCCESS.isSuccess(), HuaResultCode.SUCCESS.resultCode(), message, data);
    }

    public static <T> HuaResult<T> data(boolean isSuccess, String code, String message, T data) {<!-- -->
        return new HuaResult<>(isSuccess, code, null == data ? HuaResultCode.SUCCESS.resultCode : message, data);
    }

    public static <T> HuaResult<T> success() {<!-- -->
        return new HuaResult<>(HuaResultCode. SUCCESS);
    }

    public static <T> HuaResult<T> success(IResultCode resultCode) {<!-- -->
        return new HuaResult<>(resultCode);
    }

    public static <T> HuaResult<T> success(String message) {<!-- -->
        return new HuaResult<>(HuaResultCode. SUCCESS, message);
    }

    public static <T> HuaResult<T> success(IResultCode resultCode, String message) {<!-- -->
        return new HuaResult<>(resultCode, message);
    }

    public static <T> HuaResult<T> fail() {<!-- -->
        return new HuaResult<>(HuaResultCode.FAILURE);
    }

    public static <T> HuaResult<T> fail(IResultCode resultCode) {<!-- -->
        return new HuaResult<>(resultCode);
    }

    public static <T> HuaResult<T> fail(IResultCode resultCode, String message) {<!-- -->
        return new HuaResult<>(resultCode, message);
    }

    public static <T> HuaResult<T> fail(String message) {<!-- -->
        return new HuaResult<>(HuaResultCode.FAILURE, message);
    }

    public static <T> HuaResult<T> judge(boolean flag) {<!-- -->
        return flag ? success(HuaResultCode.SUCCESS.resultMessage()) : fail(HuaResultCode.FAILURE.resultMessage());
    }

    public static <T> HuaResult<T> judge(int flag) {<!-- -->
        return flag > 0 ? success(HuaResultCode.SUCCESS.resultMessage()) : fail(HuaResultCode.FAILURE.resultMessage());
    }
}

HuaResultCode

package com.qwfys.sample.maoshan.common.result;

import cn.hutool.core.util.StrUtil;
import lombok. AllArgsConstructor;
import lombok. NoArgsConstructor;

/**
 * @author liuwenke
 * @since 0.0.1
 */

@AllArgsConstructor
@NoArgsConstructor
public enum HuaResultCode implements IResultCode {<!-- -->
    /**
     * SpringMVC default level exception encapsulation
     */
    METHOD_NOT_SUPPORT(false, "405", "The request method type is not supported, please check the request type!"),
    MEDIA_TYPE_NOT_SUPPORT(false, "405", "HTTP media type does not support exception!"),
    MEDIA_TYPE_NOT_ACCEPTABLE(false, "406", "The media type expected by the client request is inconsistent with the media type responded by the server!"),
    MISSING_PATH_VARIABLE(false, "500", "Missing optional path parameter!"),
    MISSING_SERVLET_REQUEST_PARAMETER(false, "400", "Missing request parameters!"),
    REQUEST_BINDING(false, "400", "The request parameter is invalid, please contact the administrator to check the front-end configuration"),
    CONVERSION_NOT_SUPPORTED(false, "500", "Parameter binding exception!"),
    TYPE_MIS_MATCH(false, "400", "Type mismatch exception!"),
    MESSAGE_NOT_READABLE(false, "400", "The message is unreadable!"),
    MESSAGE_NOT_WRITABLE(false, "500", "The message cannot be written!"),
    METHOD_ARGUMENT_NOT_VALID(false, "400", "The request parameter is invalid!"),
    MISSING_SERVLET_REQUEST_PART(false, "400", ""),
    BIND(false, "400", "The request parameter is invalid!"),
    NO_HANDLER_FOUND(false, "404", "No suitable handler was found, the handler may not exist, please check whether the path is correct!"),
    ASYNC_REQUEST_TIMEOUT(false, "503", "Asynchronous request timeout"),


    /**
     * Unpredictable system exception
     */
    SERVER_ERROR(false, "99999", "Sorry, the system is busy, please try again later!"),

    /**
     * basic return
     */
    SUCCESS(true, "00000", "The operation is successful!"),
    FAILURE(false, "A0001", "Operation failed!"),
    PARMERROR(false, "A0002", "The request parameter is invalid!"),
    NO_DATA(false, "A0003", "No data yet"),
    NO_FILE(false, "A0004", "No file"),
    NO_PERMISSION_FILE(false, "A0005", "No file permission"),
    LOGIN_FAIL(false, "A0006", "User does not exist or is disabled"),
    DATA_EXCEPTION(false, "A0007", "Data exception"),

    /**
     * The system can predict anomalies
     */
    UN_KNOW(false, "A0100", "Unknown error"),
    NULL_POINT(false, "A0101", "Null pointer exception"),
    HTTP_MESSAGE_NOT_READABLE(false, "A0102", "http request parameter conversion exception, parameter format error"),
    HTTP_REQUEST_METHOD_NOT_SUPPORTED(false, "A0103", "http request method does not support"),


    /**
     * Parameter related
     */
    PARAM_ERROR(false, "A0200", "User request parameter error"),
    ENUM_NOT_EXIST(false, "A0201", "The enumeration name does not exist"),
    ENUM_PARSE_EXIST(false, "A0202", "The parsing failed during the process of obtaining all enumerations, please contact the developer to solve"),
    ADD_NOT_NEED_ID(false, "A0203", "The primary key does not need to be passed when adding new"),

    UPDATE_ID_NOT_NULL(false, "A0204", "No need to pass the primary key when editing"),
    MISSING_ANNO_PARAM(false, "A0205", "Annotation is missing necessary parameters"),

    ;
    public Boolean isSuccess;
    public String resultCode;
    public String resultMessage;

    @Override
    public Boolean isSuccess() {<!-- -->
        return this.isSuccess;
    }

    @Override
    public String resultCode() {<!-- -->
        return this.resultCode;
    }

    @Override
    public String resultMessage() {<!-- -->
        return this.resultMessage;
    }

    @Override
    public void formateMessage(String... messages) {<!-- -->
        this.resultMessage = StrUtil.format(this.resultMessage, messages);
    }
}

IResultCode

package com.qwfys.sample.maoshan.common.result;

/**
 * @author liuwenke
 * @since 0.0.1
 */
public interface IResultCode {<!-- -->
    /**
     * whether succeed
     *
     * @return
     */
    Boolean isSuccess();

    /**
     * return status code
     *
     * @return
     */
    String resultCode();

    /**
     * Status message description
     *
     * @return
     */
    String resultMessage();

    /**
     * rewrite message
     *
     * @param messages
     * @return
     */
    void formateMessage(String... messages);
}

Provider 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-huayang</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.qwfys.sample</groupId>
            <artifactId>maoshan-common</artifactId>
        </dependency>
    </dependencies>
</project>

Controller

ProviderController

package com.qwfys.sample.maoshan.huayang.controller;

import com.qwfys.sample.maoshan.common.dto.AccountDetailDTO;
import com.qwfys.sample.maoshan.common.result.HuaResult;
import com.qwfys.sample.maoshan.common.vo.AccountDetailVO;
import com.qwfys.sample.maoshan.huayang.business.spec.AccountBusiness;
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.util.Assert;
import org.springframework.web.bind.annotation.*;

/**
 * @author liuwenke
 * @since 0.0.1
 */
@Slf4j
@RestController
@Tag(name = "Server Management")
public class ProviderController {<!-- -->

    @Autowired
    private AccountBusiness accountBusiness;

    @ResponseBody
    @PostMapping("/provider/account/detail")
    @Operation(summary = "Get server account details")
    public HuaResult<AccountDetailVO> findAccountDetail(@RequestHeader("Authorization") String token, @RequestBody AccountDetailDTO dto) {<!-- -->
        Assert.notNull(token, "token cannot be empty");
        Assert.notNull(dto.getUserId(), "userID cannot be empty");

        AccountDetailVO detailVO = accountBusiness. findAccountDetail();
        HuaResult<AccountDetailVO> huaResult = HuaResult.data(detailVO);
        log.info("response: {}", huaResult);
        return huaResult;
    }
}

Business

Account Business

package com.qwfys.sample.maoshan.huayang.business.spec;

import com.qwfys.sample.maoshan.common.vo.AccountDetailVO;

/**
 * @author liuwenke
 * @since 0.0.1
 */
public interface AccountBusiness {<!-- -->
    AccountDetailVO findAccountDetail();
}

AccountBusinessImpl

package com.qwfys.sample.maoshan.huayang.business.impl;

import com.qwfys.sample.maoshan.common.vo.AccountDetailVO;
import com.qwfys.sample.maoshan.common.vo.RoleVO;
import com.qwfys.sample.maoshan.huayang.business.spec.AccountBusiness;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author liuwenke
 * @since 0.0.1
 */

@Service
public class AccountBusinessImpl implements AccountBusiness {<!-- -->
    @Override
    public AccountDetailVO findAccountDetail() {<!-- -->

        List<RoleVO> roles = new ArrayList<>();
        roles.add(
                new RoleVO()
                        .setId(11L)
                        .setCode("ADMIN")
                        .setName("Administrator")
        );

        roles.add(
                new RoleVO()
                        .setId(12L)
                        .setCode("BUYER")
                        .setName("Buyer")
        );

        roles.add(
                new RoleVO()
                        .setId(13L)
                        .setCode("SELLER")
                        .setName("Business")
        );

        AccountDetailVO detailVO = new AccountDetailVO()
                .setUserId(1639178930477944839L)
                .setUserName("welcome")
                .setFullName("welcome")
                .setTelephone("13800000000")
                .setRoles(roles);
        return detailVO;
    }
}

config

application.yml

mybatis-plus:
  global-config:
    banner: false

server:
  port: 19000

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:23306/huayang?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

knife4jConfig

package com.qwfys.sample.maoshan.huayang.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 Provider interface documentation")
                                .description("Service Provider 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")
                                )
                );
    }
}

It is not finished. Considering the length, the remaining part is placed in How to use RestTemplate in Spring boot, part II. If you want to read it, you can move to the second part to read it.