How to use RestTemplate in Spring boot, part I

Overview

在项目中,我们经常会遇到需要从另外一个系统中以http方式获取数据的情况,这种需求,大部分人可能会采用Apache HttpClient来实现,也有一些人会采用OkHttp或者其他的组件来实现。

在Spring boot中,Spring boot为我们提供了一个名称为RestTemplate的http客户端组件,基于它,我们也是可以完成上述诉求的。关于RestTemplate的用法,大部分人都是熟悉的,这里不再赘述,今天我们着重介绍一下,面对数据提供方基于泛型生成的json字符串,我们如何将其反序列化为完整的Java Bean对象。

Goal

这里有服务提供方Provider响应服务时生成的数据的json的片段:

{
  "isSuccess": true,
  "resultCode": "00000",
  "resultMessage": "操作成功!",
  "data": {
    "userId": "1639178930477944839",
    "userName": "welcome",
    "fullName": "welcome",
    "telephone": "13800000000",
    "dept": null,
    "roles": [
      {
        "id": "11",
        "code": "ADMIN",
        "name": "管理员"
      },
      {
        "id": "12",
        "code": "BUYER",
        "name": "买家"
      },
      {
        "id": "13",
        "code": "SELLER",
        "name": "商家"
      }
    ]
  }
}

我们希望服务消费方取到数据以后,能将json反序列化为对应的Java Bean。下面我们就从服务提供方、服务消费方两个方向以一个实际的案例详细介绍这类问题的通用解决方法。

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 = "账号详情请求参数")
@Data
@Accessors(chain = true)
public class AccountDetailDTO {

    @Schema(description = "用户ID")
    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 = "账号详情")
@Data
@Accessors(chain = true)
public class AccountDetailVO {

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

    @Schema(description = "用户名称")
    private String userName;

    @Schema(description = "姓名")
    private String fullName;

    @Schema(description = "电话号码")
    private String telephone;

    @Schema(description = "所属部门")
    private DeptVO dept;

    @Schema(description = "角色列表")
    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 = "部门")
@Data
@Accessors(chain = true)
public class DeptVO {

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

    @Schema(description = "部门名称")
    private String name;

    @Schema(description = "部门路径")
    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 = "角色")
@Data
@Accessors(chain = true)
public class RoleVO {

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

    @Schema(description = "角色编码")
    private String code;

    @Schema(description = "角色名称")
    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 = "统一返回实体")
public class HuaResult<T> {
    @Schema(description = "是否成功")
    private Boolean isSuccess = false;

    @Schema(description = "响应码")
    private String resultCode;

    @Schema(description = "消息")
    private String resultMessage;

    @Schema(description = "数据")
    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;
    }

    // 错误时的构造器
    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默认级别的异常封装
     */
    METHOD_NOT_SUPPORT(false, "405", "请求方法类型不支持,请检查请求类型!"),
    MEDIA_TYPE_NOT_SUPPORT(false, "405", "HTTP媒体类型不支持异常!"),
    MEDIA_TYPE_NOT_ACCEPTABLE(false, "406", "客户端请求期望响应的媒体类型与服务器响应的媒体类型不一致!"),
    MISSING_PATH_VARIABLE(false, "500", "缺少可选的路径参数!"),
    MISSING_SERVLET_REQUEST_PARAMETER(false, "400", "缺少请求参数!"),
    REQUEST_BINDING(false, "400", "请求参数不合法,请联系管理员检查前端配置"),
    CONVERSION_NOT_SUPPORTED(false, "500", "参数绑定异常!"),
    TYPE_MIS_MATCH(false, "400", "类型不匹配异常!"),
    MESSAGE_NOT_READABLE(false, "400", "消息不可读异常!"),
    MESSAGE_NOT_WRITABLE(false, "500", "消息不可写异常!"),
    METHOD_ARGUMENT_NOT_VALID(false, "400", "请求参数不合法!"),
    MISSING_SERVLET_REQUEST_PART(false, "400", ""),
    BIND(false, "400", "请求参数不合法!"),
    NO_HANDLER_FOUND(false, "404", "没有找到合适的处理器,处理器可能不存在,请检查路径是否正确!"),
    ASYNC_REQUEST_TIMEOUT(false, "503", "异步请求超时"),


    /**
     * 不可预知系统异常
     */
    SERVER_ERROR(false, "99999", "抱歉,系统繁忙,请稍后重试!"),

    /**
     * 基本的返回
     */
    SUCCESS(true, "00000", "操作成功!"),
    FAILURE(false, "A0001", "操作失败!"),
    PARMERROR(false, "A0002", "请求参数不合法!"),
    NO_DATA(false, "A0003", "暂无数据"),
    NO_FILE(false, "A0004", "没有文件"),
    NO_PERMISSION_FILE(false, "A0005", "没有文件权限"),
    LOGIN_FAIL(false, "A0006", "用户不存在或被禁用"),
    DATA_EXCEPTION(false, "A0007", "数据异常"),

    /**
     * 系统可预知异常
     */
    UN_KNOW(false, "A0100", "未知错误"),
    NULL_POINT(false, "A0101", "空指针异常"),
    HTTP_MESSAGE_NOT_READABLE(false, "A0102", "http请求参数转换异常,参数格式错误"),
    HTTP_REQUEST_METHOD_NOT_SUPPORTED(false, "A0103", "http请求方式不支持"),


    /**
     * 参数相关
     */
    PARAM_ERROR(false, "A0200", "用户请求参数错误"),
    ENUM_NOT_EXIST(false, "A0201", "枚举名不存在"),
    ENUM_PARSE_EXIST(false, "A0202", "获取所有枚举过程中解析失败,请联系开发人员解决"),
    ADD_NOT_NEED_ID(false, "A0203", "新增的时候主键不需要传递"),

    UPDATE_ID_NOT_NULL(false, "A0204", "编辑的时候不需要传递主键"),
    MISSING_ANNO_PARAM(false, "A0205", "注解缺失必要的参数"),

    ;
    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 {
    /**
     * 是否成功
     *
     * @return
     */
    Boolean isSuccess();

    /**
     * 返回状态码
     *
     * @return
     */
    String resultCode();

    /**
     * 状态消息描述
     *
     * @return
     */
    String resultMessage();

    /**
     * 重写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.controler;

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 = "服务方管理")
public class ProviderController {

    @Autowired
    private AccountBusiness accountBusiness;

    @ResponseBody
    @PostMapping("/provider/account/detail")
    @Operation(summary = "获取服务方账号详情")
    public HuaResult<AccountDetailVO> findAccountDetail(@RequestHeader("Authorization") String token, @RequestBody AccountDetailDTO dto) {
        Assert.notNull(token, "token不能为空");
        Assert.notNull(dto.getUserId(), "userID不能为空");

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

Business

AccountBusiness

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("管理员")
        );

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

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

        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%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

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("接口文档")
                .packagesToScan("com.qwfys.sample.maoshan")
                .build();
    }

    @Bean
    public OpenAPI springShopOpenApi() {
        return new OpenAPI()
                .info(
                        new Info()
                                .title("Service Provider接口文档")
                                .description("Service Provider接口文档")
                                .version("0.0.1-SNAPSHOT")
                                .license(
                                        new License()
                                                .name("使用请遵守MIT License授权协议")
                                                .url("https://github.com/ab-sample/maoshan")
                                )
                );
    }
}

未完,考虑到篇幅问题,剩余部分放在How to use RestTemplate in Spring boot, part II中了,如果要阅读可以移步到第二部分阅读。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qwfys200

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值