使用RestTemplate客户端调用微服务发布的Restful接口

记录:393

场景:在Spring Cloud微服务架构中,使用nacos注册和配置微服务,使用RestTemplate客户端调用微服务发布的Restful接口。

版本:JDK 1.8,SpringBoot 2.6.3,springCloud 2021.0.1,Nacos 2.1.1。

3.1初始化准备

3.1.1创建Maven工程

使用IntelliJ IDEA创建Maven工程。

(1)微服务名称

名称:hub-example-303-resttemplate

(2)微服务groupId和artifactId

groupId: com.hub

artifactId: hub-example-303-resttemplate

(3)微服务核心模块版本

spring-boot 2.6.3
spring-cloud 2021.0.1
spring-cloud-alibaba 2021.0.1.0

3.1.2准备nacos

Nacos版本:Nacos 2.1.1。

(1)启动和登录nacos

启动命令:sh startup.sh -m standalone

地址:http://127.0.0.1:8848/nacos

用户名/口令:nacos/nacos

(2)创建命名空间

命名空间ID:aa3eebb6-daa2-4db8-9a29-03dd8a17db15

命名空间名:hub

3.2修改pom.xml

修改pom.xml,引入项目依赖Jar和管理Jar包。

3.2.1修改pom.xml文件

(1)RestTemplate依赖

org.springframework.web.client.RestTemplate,在spring-web-5.3.15.jar中。引入以下依赖就自动导入了。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

(2)RestTemplate依赖

使用RestTemplate调用微服务时,且微服务注册在Nacos时,需引入客户端负载均衡包。

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

3.2.2全量pom.xml文件

全量pom.xml文件请参考附录:3.10.1全量pom.xml文件

3.3创建bootstrap.yml文件和配置nacos

3.3.1创建bootstrap.yml

server:
  port: 18303
  servlet:
    context-path: /hub-303-rest
spring:
  application:
    name: hub-example-303-resttemplate
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:18848
        username: nacos
        password: nacos
        namespace: aa3eebb6-daa2-4db8-9a29-03dd8a17db15
        group: DEFAULT_GROUP
      config:
        server-addr: 127.0.0.1:18848
        username: nacos
        password: nacos
        namespace: aa3eebb6-daa2-4db8-9a29-03dd8a17db15
        group: DEFAULT_GROUP
        file-extension: yaml
        shared-configs:
          - dataId: hub-example01-config.yml
            group: DEFAULT_GROUP
            refresh: true

3.4创建启动类

3.4.1创建包

com.hub.example.domain:微服务使用到的DTO等实体类。

com.hub.example.controller:Controller类,发布Restful接口。

com.hub.example.config:配置类。

3.4.2启动类

包名:com.hub.example。

启动类:HubExampleFeignApplication。

(1)内容

@SpringBootApplication
@ComponentScan(basePackages = "com.hub.example.*")
@EnableDiscoveryClient
public class HubExampleRestApplication {
  public static void main(String[] args) {
    SpringApplication.run(HubExampleRestApplication.class, args);
  }
}

(2)解析

@SpringBootApplication,SpringBoot标记启动类的注解。

@ComponentScan,扫描指定的包,将组件加载到IOC容器中。

@EnableDiscoveryClient,开启服务发现功能。

3.5创建配置

3.5.1配置类

@Configuration
public class RestTemplateConfiguration {
  @Bean(name = "msRestTemplate")
  @Primary
  @LoadBalanced
  public RestTemplate msRestTemplate() {
    return new RestTemplate();
  }
}

3.5.2解析

使用RestTemplate调用注册到Nacos的微服务时,需加上@LoadBalanced注解,启动客户端负载均衡,否则会报错。

3.6编写Controller代码

3.6.1Controller代码

@RestController
@RequestMapping("/hub/example/city")
@RefreshScope
@Slf4j
public class CityController {
  @Qualifier("msRestTemplate")
  @Autowired
  private RestTemplate msRestTemplate;
  @PostMapping("/queryCityByCityId")
  public ResultObj<CityDTO> queryCityByCityId(String cityId) {
    // 1.组装请求头
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.set("cityNo","0517");
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    // 2.组装请求实体
    HttpEntity<String> httpEntity = new HttpEntity<>(cityId,httpHeaders);
    String url="http://hub-example-301-nacos/hub-301-nacos/hub/example/city/queryCityByCityId";
    ResponseEntity<String> responseEntity = msRestTemplate.postForEntity(url,httpEntity,String.class,new Object[0]);
    // 3.解析应答实体
    String result = responseEntity.getBody();
    ResultObj resultObj= JSONUtil.toBean(result,ResultObj.class);
    CityDTO cityDTO =JSONUtil.toBean((JSONObject) resultObj.getData(),CityDTO.class);
    return ResultObj.data(200, cityDTO, "执行成功");
  }
  @PostMapping("/queryCityByCity")
  public ResultObj<CityDTO> queryCityByCity(@RequestBody CityReqDTO cityReqDTO) {
    // 1.组装请求头
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.set("cityNo","0517");
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    // 2.组装请求实体
    HttpEntity<CityReqDTO> httpEntity = new HttpEntity<>(cityReqDTO,httpHeaders);
    String url="http://hub-example-301-nacos/hub-301-nacos/hub/example/city/queryCityByCity";
    ResponseEntity<CityDTO> responseEntity = msRestTemplate.postForEntity(url,httpEntity,CityDTO.class,new Object[0]);
    // 3.解析应答实体
    CityDTO cityDTO = responseEntity.getBody();
    return ResultObj.data(200, cityDTO, "执行成功");
  }
}

3.6.2解析RestTemplate调用远程微服务

(1)调用方式

String url="http://hub-example-301-nacos/hub-301-nacos/hub/example/city/queryCityByCity";
ResponseEntity<CityDTO> responseEntity = msRestTemplate.postForEntity(url,httpEntity,CityDTO.class,new Object[0]);

(2)解析

在url中,hub-example-301-nacos,是目标微服务的名称,即微服务注册在Nacos中名称。

/hub-301-nacos,是目标微服务配置的server.servlet.context-path属性。

/hub/example/city/queryCityByCity,是目标微服务的Controller路径:@RequestMapping("/hub/example/city");和方法上的请求路径:@PostMapping("/queryCityByCity")。

3.6.3解析请求实体和响应实体

org.springframework.web.client.RestTemplate,操作http请求的客户端。

org.springframework.util.MultiValueMap,存储请求头的key、value键值对。

org.springframework.http.HttpHeaders,http请求头。

org.springframework.http.HttpEntity,http请求实体。

org.springframework.http.ResponseEntity,http响应实体。

在HttpHeaders中的核心属性:

final MultiValueMap<String, String> headers;

在HttpEntity中的核心属性:

private final HttpHeaders headers;
private final T body;

在HttpEntity中的核心属性:

ResponseEntity中的核心属性(其中headers和body从HttpEntity中继承):

private final Object status;
private final HttpHeaders headers;
private final T body;

3.6.4使用RestTemplate传递请求头信息

使用RestTemplate传递请求头信息。

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("cityNo","0517");
httpHeaders.setContentType(MediaType.APPLICATION_JSON);

3.7支撑对象

3.7.1CityDTO

@Data
public class CityDTO implements Serializable {
  private Long cityId;
  private String cityName;
  private Double landArea;
  private Long population;
  private Double gross;
  private String cityDescribe;
  private String dataYear;
  @JsonFormat(
      pattern = "yyyy-MM-dd HH:mm:ss"
  )
  private Date updateTime;
}

3.7.2ResultObj

@Data
public class ResultObj<T> implements Serializable {
  private int code;
  private boolean success;
  private String msg;
  private T data;
  private ResultObj(int code, T data, String msg) {
    this.code = code;
    this.data = data;
this.msg = msg;
this.success = code == 200;
  }
  public static <T> ResultObj<T> data(int code, T data, String msg) {
    return new ResultObj<>(code, data, msg);
  }
}

3.7.3CityReqDTO

@Data
public class CityReqDTO {
  private Long cityId;
  private String cityName;
}

3.8目标微服务信息

使用RestTemplate调用的远程微服务信息。

3.8.1目标微服名称

微服务名:hub-example-301-nacos

3.8.2目标微服Controller

@RestController
@RequestMapping("/hub/example/city")
@RefreshScope
@Slf4j
public class CityController {
  @Autowired
  private HttpServletRequest request;
  @PostMapping("/queryCityByCityId")
  public ResultObj<CityDTO> queryCityByCityId(String cityId) {
      log.info("cityNo = " + request.getHeader("cityNo"));
      CityDTO cityDTO = new CityDTO();
      cityDTO.setCityId(cityId != null ? Long.parseLong(cityId) : 1L);
      cityDTO.setCityName(cityName);
      cityDTO.setUpdateTime(new Date());
      return ResultObj.data(200, cityDTO, "执行成功");
  }
  @PostMapping("/queryCityByCity")
  public CityDTO queryCityByCity(@RequestBody CityReqDTO cityReqDTO) {
    CityDTO cityDTO = new CityDTO();
    cityDTO.setCityId(cityReqDTO.getCityId());
    cityDTO.setCityName(cityReqDTO.getCityName());
    cityDTO.setCityDescribe(cityReqDTO.getCityName() + "是一个互联网城市.");
    cityDTO.setUpdateTime(new Date());
    return cityDTO;
  }
}

3.9使用Postman工具测试

使用Postman工具测试。

测试地址:http://127.0.0.1:18302/hub-302-feign/hub/example/city/queryCityByCity

测试入参:

{
    "cityId":"20230326",
    "cityName":"杭州"
}

返回结果:

{
  "code": 200,
  "success": true,
  "msg": "执行成功",
  "data": {
    "cityId": 20230326,
    "cityName": "杭州",
    "landArea": null,
    "population": null,
    "gross": null,
    "cityDescribe": "杭州是一个互联网城市.",
    "dataYear": null,
    "updateTime": "2023-03-26 21:16:55"
  }
}

3.10附录

3.10.1全量pom.xml文件

<?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>
  <groupId>com.hub</groupId>
  <artifactId>hub-example-303-resttemplate</artifactId>
  <version>1.0-SNAPSHOT</version>
  <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.6.3</version>
  </parent>
  <description>应用RestTemplate调用微服务</description>
  <packaging>jar</packaging>
  <properties>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <spring.boot.maven.plugin.version>2.6.3</spring.boot.maven.plugin.version>
      <spring.boot.version>2.6.3</spring.boot.version>
      <spring.cloud.version>2021.0.1</spring.cloud.version>
      <spring.cloud.alibaba.version>2021.0.1.0</spring.cloud.alibaba.version>
      <nacos.client.version>2.1.1</nacos.client.version>
      <lombok.version>1.18.24</lombok.version>
      <guava.version>30.1-jre</guava.version>
      <hutool.version>5.8.12</hutool.version>
  </properties>
  <dependencyManagement>
      <dependencies>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-parent</artifactId>
              <version>${spring.boot.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-dependencies</artifactId>
              <version>${spring.cloud.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
          <dependency>
              <groupId>com.alibaba.cloud</groupId>
              <artifactId>spring-cloud-alibaba-dependencies</artifactId>
              <version>${spring.cloud.alibaba.version}</version>
              <type>pom</type>
              <scope>import</scope>
          </dependency>
      </dependencies>
  </dependencyManagement>
  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-bootstrap</artifactId>
      </dependency>
      <!--nacos注册中心-->
      <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
          <exclusions>
              <exclusion>
                  <groupId>org.springframework.cloud</groupId>
                  <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-loadbalancer</artifactId>
      </dependency>
      <!--nacos配置中心-->
      <dependency>
          <groupId>com.alibaba.cloud</groupId>
          <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
          <exclusions>
              <exclusion>
                  <groupId>com.alibaba.nacos</groupId>
                  <artifactId>nacos-client</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      <dependency>
          <groupId>com.alibaba.nacos</groupId>
          <artifactId>nacos-client</artifactId>
          <version>${nacos.client.version}</version>
      </dependency>
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>${lombok.version}</version>
      </dependency>
      <dependency>
          <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>${guava.version}</version>
      </dependency>
      <dependency>
          <groupId>cn.hutool</groupId>
          <artifactId>hutool-all</artifactId>
          <version>${hutool.version}</version>
      </dependency>
  </dependencies>
  <build>
      <finalName>${project.artifactId}</finalName>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
              <version>${spring.boot.maven.plugin.version}</version>
              <configuration>
                  <fork>true</fork>
                  <addResources>true</addResources>
              </configuration>
              <executions>
                  <execution>
                      <goals>
                          <goal>repackage</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      </plugins>
  </build>
</project>

以上,感谢。

2023年3月26日

猜你喜欢

转载自blog.csdn.net/zhangbeizhen18/article/details/129785472