0-编辑历史
2023-10-17 16:20
宜改需求 太初有道,道生时空,故时空乃程序设计之根本
这篇文章的主要内容:在一个 Spring Boot 客户端应用程序中,使用 RestTemplate 发送 HTTP 请求,有一个 RESTful Web Service 作为服务端返回响应,并可能在响应体中返回数据。客户端使用 RestTemplate 的相关 API 来获取响应结果,并进行解析和处理。
实现这个客户端应用程序的前提是我们需要有一个服务端应用程序,在这个项目中,为了简化起见,我将客户端与服务端合二为一。
2023-10-18 15:09
宜不接需求 心若向阳,何惧悲伤
1-参考资料
chatgpt: website
project: juejin.cn/post/728896…
spring documentation: docs.spring.io/spring-fram…
httpbin.org : httpbin.org/#/
2-构建服务端应用程序
服务端应用程序使用如下技术构建:Spring Boot \ Spring Web \ H2 \ Mybatis-Plus \ springdoc \ lombok
项目结构目录如下图所示
2023-10-17 17:00,如下试是对代码的展示,可以快速跳过此部分代码直接浏览第三部分
2-0-build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.15'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '1.8'
}
repositories {
mavenCentral()
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
// https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter
implementation group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.5.3.1'
// https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.7.0'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
2-1-实体类
package com.example.lkcoffee.persistence.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* @version 1.0
* @since 2023/10/10 17:22
*/
@Schema(description = "coffee model")
@Data
@TableName(value = "coffee")
@JsonIgnoreProperties(ignoreUnknown=true)
public class Coffee {
@TableId(value = "ID", type = IdType.AUTO)
private Integer id;
@TableField(value = "name")
private String name;
@TableField(value = "brand")
private String brand;
@TableField(value = "price")
private BigDecimal price;
@TableField(value = "introduction")
private String introduction;
@TableField(value = "rating")
private BigDecimal rating;
}
2-2-Mapper && Xml
package com.example.lkcoffee.persistence.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.lkcoffee.persistence.entity.Coffee;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
* @version 1.0
* @since 2023/10/11 10:04
*/
@Mapper
public interface CoffeeMapper extends BaseMapper<Coffee> {
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.lkcoffee.persistence.mapper">
</mapper>
2-3-Interface && ServiceImpl
package com.example.lkcoffee.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.lkcoffee.persistence.entity.Coffee;
import com.example.lkcoffee.search.CoffeeSearchCriteria;
/**
* @version 1.0
* @since 2023/10/11 10:08
*/
public interface CoffeeService extends IService<Coffee> {
IPage<Coffee> getCoffeePage(CoffeeSearchCriteria coffeeSearchCriteria);
}
package com.example.lkcoffee.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.lkcoffee.persistence.entity.Coffee;
import com.example.lkcoffee.persistence.mapper.CoffeeMapper;
import com.example.lkcoffee.search.CoffeeSearchCriteria;
import com.example.lkcoffee.service.CoffeeService;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* @version 1.0
* @since 2023/10/11 10:07
*/
@Service
public class CoffeeServiceImpl extends ServiceImpl<CoffeeMapper, Coffee> implements CoffeeService {
@Override
public IPage<Coffee> getCoffeePage(CoffeeSearchCriteria coffeeSearchCriteria) {
Page<Coffee> coffeePage = new Page<>(
coffeeSearchCriteria.getCurrentPage(), coffeeSearchCriteria.getPageSize());
// 取消单页分页条数限制
coffeePage.setMaxLimit(-1L);
QueryWrapper<Coffee> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda()
.ge(Coffee::getRating , coffeeSearchCriteria.getRating());
return this.page(coffeePage, queryWrapper);
}
}
2-4-Controller
package com.example.lkcoffee.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.lkcoffee.persistence.entity.Coffee;
import com.example.lkcoffee.search.CoffeeSearchCriteria;
import com.example.lkcoffee.service.CoffeeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* The type Coffee controller.
*
* @version 1.0
* @since 2023 /10/11 10:09
*/
@Tag(name = "lkCoffee API")
@RestController
@RequestMapping("/coffee")
public class CoffeeController {
@Autowired
private CoffeeService coffeeService;
/**
* Gets coffee page.
*
* @param rating the rating
* @param pageNumber the page number
* @param pageSize the page size
* @return the user page
*/
@Operation(summary = "按评分获取咖啡分页列表")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "成功获取咖啡分页列表"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
@GetMapping("/page")
public ResponseEntity<IPage<Coffee>> getCoffeePage(
@Parameter(description = "咖啡评分") @RequestParam float rating,
@Parameter(description = "页码,默认为1") @RequestParam(defaultValue = "1") Long pageNumber,
@Parameter(description = "每页记录数,默认为10") @RequestParam(defaultValue = "10") Long pageSize
) {
CoffeeSearchCriteria coffeeSearchCriteria = new CoffeeSearchCriteria();
coffeeSearchCriteria.setRating(rating);
coffeeSearchCriteria.setCurrentPage(pageNumber);
coffeeSearchCriteria.setPageSize(pageSize);
IPage<Coffee> coffeeIPage = coffeeService.getCoffeePage(coffeeSearchCriteria);
return ResponseEntity.ok(coffeeIPage);
}
/**
* Gets coffee list.
*
* @return the coffee list
*/
@Operation(summary = "获取咖啡列表")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "成功获取咖啡列表"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
@GetMapping("/list")
public ResponseEntity<List<Coffee>> getCoffeeList() {
List<Coffee> coffeeList = coffeeService.list();
return ResponseEntity.ok(coffeeList);
}
/**
* Gets coffee by id.
*
* @param id the id
* @return the coffee by id
*/
@Operation(summary = "根据 ID 获取咖啡")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "成功获取咖啡"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
@GetMapping("/{id}")
public ResponseEntity<Coffee> getCoffeeById(
@Parameter(description = "咖啡 ID") @PathVariable Integer id) {
Coffee coffee = coffeeService.getById(id);
return ResponseEntity.ok(coffee);
}
/**
* Save coffee response entity.
*
* @param coffee the coffee
* @return the response entity
*/
@Operation(summary = "保存咖啡")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "成功保存咖啡"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
@PostMapping("/save")
public ResponseEntity<Void> saveCoffee(@RequestBody Coffee coffee) {
coffeeService.save(coffee);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
/**
* Update coffee by id response entity.
*
* @param coffee the coffee
* @return the response entity
*/
@Operation(summary = "更新咖啡")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "成功更新咖啡"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
@PutMapping("/update")
public ResponseEntity<Void> updateCoffeeById(@RequestBody Coffee coffee) {
coffeeService.updateById(coffee);
return ResponseEntity.noContent().build();
}
/**
* Delete coffee by id response entity.
*
* @param id the id
* @return the response entity
*/
@Operation(summary = "根据 ID 删除咖啡")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "成功删除咖啡"),
@ApiResponse(responseCode = "500", description = "服务器内部错误")
})
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteCoffeeById(
@Parameter(description = "咖啡 ID") @PathVariable Integer id
) {
coffeeService.removeById(id);
return ResponseEntity.noContent().build();
}
}
2-5-Swagger
package com.example.lkcoffee.config;
import io.swagger.v3.oas.models.ExternalDocumentation;
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.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* The type Swagger config.
*
* @version 1.0
* @since 2023 /10/13 13:14
*/
@Configuration
public class SwaggerConfig {
/**
* Lk coffee open api.
*
* @return the open api
*/
@Bean
public OpenAPI lkCoffeeOpenAPI() {
return new OpenAPI()
.info(new Info().title("lkCoffee API")
.description("lkCoffee application")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("lkCoffee Wiki Documentation")
.url("http://springdoc.org"));
}
}
2-6-配置文件-application.yml
spring:
application:
name: lkcoffee
datasource:
url: jdbc:h2:mem:lkcoffee
driverClassName: org.h2.Driver
username: root
password: toor
generate-unique-name: false
name: lkcoffee
jpa:
show-sql: true
hibernate:
ddl-auto: update
use-new-id-generator-mappings: false
h2:
console:
path: /h2-console
enabled: true
settings:
trace: false
web-allow-others: false
sql:
init:
schema-locations: classpath:/schema-h2.sql
data-locations: classpath:/data-h2.sql
server:
port: 8888
springdoc:
api-docs:
enabled: true
path: /v3/api-docs
version: openapi_3_0
swagger-ui:
path: /swagger-ui/index.html
tagsSorter: alpha
use-root-path: true
cache:
disabled: true
2-7-H2数据预配置
schema-h2.sql
DROP TABLE IF EXISTS coffee;
CREATE TABLE coffee
(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
brand VARCHAR(50) NOT NULL,
price DECIMAL(6, 2) NOT NULL,
introduction VARCHAR(500),
rating DECIMAL(3, 1) NOT NULL DEFAULT 0
);
data-h2.sql
DROP TABLE IF EXISTS coffee;
CREATE TABLE coffee
(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
brand VARCHAR(50) NOT NULL,
price DECIMAL(6, 2) NOT NULL,
introduction VARCHAR(500),
rating DECIMAL(3, 1) NOT NULL DEFAULT 0
);
2-8-启动应用程序
package com.example.lkcoffee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author yang.jianming3
*/
@SpringBootApplication
public class LkcoffeeApplication {
private static final Logger logger = LoggerFactory.getLogger(LkcoffeeApplication.class);
/**
* Swagger地址:http://localhost:8080/swagger-ui/index.html#/
* 参考资料:https://dzone.com/articles/openapi-3-documentation-with-spring-boot
* @param args args
*/
public static void main(String[] args) throws UnknownHostException {
ApplicationContext applicationContext = SpringApplication.run(LkcoffeeApplication.class, args);
Environment environment = applicationContext.getEnvironment();
logger.info("\n---------------------------------------------lkcoffee-----------------------------------------------------------------------\n" +
"应用 '{}' 运行成功! \n" +
"Swagger-UI-Interface 访问连接: http://{}:{}{}{} \n" +
"API-Docs 访问连接: http://{}:{}{}{} \n" +
"--------------------------------------------------------------------------------------------------------------------",
environment.getProperty("spring.application.name"),
InetAddress.getLocalHost().getHostAddress(),
environment.getProperty("server.port", "8080"),
environment.getProperty("server.servlet.context-path", ""),
environment.getProperty("springdoc.swagger-ui.path", "/swagger-ui/index.html"),
InetAddress.getLocalHost().getHostAddress(),
environment.getProperty("server.port", "8080"),
environment.getProperty("server.servlet.context-path", ""),
environment.getProperty("springdoc.api-docs.path", "/v3/api-docs")
);
}
}
3-发送HTTP请求并处理响应
在 Spring Boot 客户端应用程序中,发送HTTP请求并处理响应有如下方法
1-使用 Java 原生的 HttpURLConnection:Java 提供了 HttpURLConnection 类来进行基本的 HTTP 请求和响应操作。可以使用该类创建一个连接,并发送 GET、POST等请求到目标资源,并读取响应数据。
2-使用 Apache HttpClient:Apache HttpClient 是一个功能强大的 HTTP 客户端库,提供了更多的灵活性和控制力。可以使用它来发送 HTTP 请求并处理响应。
3-使用 Spring 的 RestTemplate:RestTemplate 是 Spring 提供的一个用于发送 HTTP 请求并处理响应的类。它封装了许多常见的 HTTP 操作,使得发送请求和处理响应更加简单。可以使用 RestTemplate 发送 GET、POST 等请求,并使用相应的方法获取响应数据。
4-使用 Spring WebFlux WebClient:Spring WebFlux 是 Spring 提供的响应式编程框架,其中包含一个 WebClient 类。WebClient 提供了一种非阻塞的方式发送 HTTP 请求,并处理响应。它适用于需要高吞吐量和低延迟的应用程序场景。
无论选择哪种方法,都可以根据具体的需求和场景来决定。如果正在开发一个新的 Spring Boot 应用程序,推荐使用 Spring 的 RestTemplate 或 Spring WebFlux WebClient,因为它们与 Spring 生态系统无缝集成,并提供了更多的功能和扩展性。
4-RestTemplate
4-1-RestTemplate 介绍
RestTemplate 是 Spring 提供的一个用于发送 HTTP 请求并处理响应的类。它封装了许多常见的 HTTP 操作,使得发送请求和处理响应更加简单。可以使用 RestTemplate 发送 GET、POST 等请求,并使用相应的方法获取响应数据。
RestTemplate Class 位于 org.springframework.web.client package, 实现了如下接口: RestOperations
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {}
Synchronous client to perform HTTP requests, exposing a simple, template method API over underlying HTTP client libraries such as the JDK HttpURLConnection, Apache HttpComponents, and others.
RestTemplate offers templates for common scenarios by HTTP method, in addition to the generalized exchange and execute methods that support less frequent cases.
4-3-RestTemplate 构造
在 Constructor Summary 一节,有三种构造方法
4-3-1-使用默认设置构造
默认构造函数会根据默认设置创建一个 RestTemplate 对象。如果只需要进行简单的 GET/POST 请求,并且对请求的细节不太关注,那么这种构造方式就足够了。
Constructor : RestTemplate()
Description: Create a new instance of the RestTemplate using default settings.
代码示例如下
package com.example.lkcoffee.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author yang.jianming3
* @version 1.0
* @since 2023/10/16 10:20
*/
@Slf4j
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
4-3-2-使用自定义的 ClientHttpRequestFactory 构造
如果需要自定义 HTTP 请求的细节,例如超时时间、连接池管理等,那么可以实现自定义的 ClientHttpRequestFactory,并把它传给 RestTemplate 的构造函数来创建 RestTemplate 对象。这种方式非常灵活,可以实现更高级的 HTTP 请求定制。
Constructor : RestTemplate(ClientHttpRequestFactory requestFactory)
Description: Create a new instance of the RestTemplate based on the given **ClientHttpRequestFactory**.
代码示例如下
package com.example.lkcoffee.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author yang.jianming3
* @version 1.0
* @since 2023/10/16 10:20
*/
@Slf4j
@Configuration
public class RestTemplateConfig {
/**
* Create Rest template Bean Use ClientHttpRequestFactory
*
* @param clientHttpRequestFactory the clientHttpRequestFactory
* @return the rest template
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
return restTemplate;
}
/**
*
* Client http request factory.
*
* @return the client http request factory
*/
@Bean
public ClientHttpRequestFactory bufferingClientHttpRequestFactory() {
SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
//Set the underlying URLConnection's read timeout (in milliseconds)
simpleClientHttpRequestFactory.setReadTimeout(20000);
// Set the underlying URLConnection's connect timeout (in milliseconds).
simpleClientHttpRequestFactory.setConnectTimeout(20000);
return new BufferingClientHttpRequestFactory(simpleClientHttpRequestFactory);
}
}
在上面的示例中,涉及到如下知识点
ClientHttpRequestFactory:它是一个接口,定义了用于创建 ClientHttpRequest 对象的方法。Spring 提供了多个实现,用于适应不同的场景和需求。具体取决于你的项目配置和需求,可以选择合适的 ClientHttpRequestFactory 实现。
SimpleClientHttpRequestFactory:它是 ClientHttpRequestFactory 的一个简单实现,使用标准的 JDK HttpURLConnection 类库来创建 ClientHttpRequest 对象。它适用于大多数简单的 HTTP 请求场景,不需要复杂的自定义配置。
BufferingClientHttpRequestFactory:它是 ClientHttpRequestFactory 的一个装饰器(Decorator)实现,可以在底层 HTTP 请求的基础上添加请求和响应的缓冲功能。它内部使用了一个 ClientHttpRequestFactory 对象来创建 ClientHttpRequest,然后对 ClientHttpRequest 进行包装以实现缓冲的功能。这对于需要读取请求或响应内容多次的情况非常有用。
4-3-3-使用自定义的 HttpMessageConverter 构造
如果需要处理自定义的 HTTP 响应格式,例如 XML、CSV、JSON 等,可以实现自定义的 HttpMessageConverter,并在 RestTemplate 的构造函数中传入。这种方式可以自由控制响应数据的转换过程,支持更多的数据格式
Constructor : RestTemplate(List<HttpMessageConverter<?>> messageConverters)
Description: Create a new instance of the RestTemplate using the given list of HttpMessageConverter to use.
这个我没有研究
5-使用RestTemplate.exchange() 方法发送 HTTP 请求
2023-10-17 18:16,其他方法我还没有研究,目前只研究了使用 RestTemplate.exchange() 方法发送 HTTP 请求
在 RestTemplate 源码中, exchange() 方法有多个重载实现,例如如下方法
url 表示要发送请求的 URL,method 表示请求方法(GET、POST 等),requestEntity 表示请求体,responseType 表示期望的响应类型等
@Override
public <T> ResponseEntity<T> exchange(
URI url,
HttpMethod method,
@Nullable HttpEntity<?> requestEntity,
Class<T> responseType
) throws RestClientException {
// ……
}
下面直接给出代码实例
package com.example.lkcoffee.controller;
import com.example.lkcoffee.persistence.entity.Coffee;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
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.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.*;
/**
* @author yang.jianming3
* @version 1.0
* @since 2023/10/16 10:19
*/
@Tag(name = "rest-template API")
@Slf4j
@RestController
@RequestMapping("/rest-template")
public class RestTemplateController {
@Autowired
private RestTemplate restTemplate;
@Operation(summary = "The request's query parameters.")
@GetMapping("/get-coffee-list")
public ResponseEntity<?> getCoffeeList() {
// 1. 设置请求头
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<?> requestEntity = new HttpEntity<>(httpHeaders);
// 2. 设置查询参数组成的 URI
URI url = UriComponentsBuilder.fromHttpUrl("http://localhost:8888/coffee/list")
.build()
.toUri();
// 3. 发送请求并获取响应
HttpMethod httpMethod = HttpMethod.GET;
//4. 设置期望的响应类型
Class<ArrayList> responseType = ArrayList.class;
ResponseEntity<ArrayList> response = restTemplate.exchange(url, httpMethod, requestEntity, responseType);
// 获取响应体内容
ArrayList responseBody = response.getBody();
return ResponseEntity.ok(responseBody);
}
@Operation(summary = "根据 ID 获取咖啡")
@GetMapping("/get-coffee")
public ResponseEntity<?> getCoffee(@RequestParam Integer id) {
// 1. 设置请求头
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<?> requestEntity = new HttpEntity<>(httpHeaders);
// 2. 设置有 路径 组成的 URI
URI url = UriComponentsBuilder.fromHttpUrl("http://localhost:8888/coffee/{id}")
.buildAndExpand(id)
.toUri();
log.info("url : {}", url);
// 3. 发送请求并获取响应
HttpMethod httpMethod = HttpMethod.GET;
//4. 设置期望的响应类型
Class<Coffee> responseType = Coffee.class;
ResponseEntity<Coffee> response = restTemplate.exchange(url, httpMethod, requestEntity, responseType);
ObjectMapper objectMapper = new ObjectMapper();
String responseString = null;
try {
responseString = objectMapper.writeValueAsString(response);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
log.info("response : {}", responseString);
Coffee responseBody = new Coffee();
if (Objects.equals(HttpStatus.OK, response.getStatusCode())) {
// 获取响应体内容
responseBody = response.getBody();
return ResponseEntity.ok(responseBody);
} else if (Objects.equals(HttpStatus.NOT_FOUND, response.getStatusCode())) {
return ResponseEntity.notFound().build();
} else {
return ResponseEntity.ok(responseBody);
}
}
}
设置HTTP请求头部属性待补充
6-RestTemplate其他方法
待补充
7-总结
下面还可以介绍使用 UriComponents 、UriComponentsBuilder 构造 URL
还可以介绍一下 HttpHeaders \ HttpEntity \ RequestEntity \ ResponseEntity 等与HTTP请求相关的类