Spring Boot 3 RestClient 完整教程

Spring Boot 3 RestClient 完整教程

Spring Boot 3 RestClient 完整教程

目录

  1. RestClient 简介与环境准备
  2. RestClient 基础使用
  3. RestClient 高级特性
  4. 实战案例:RESTful API 客户端实现
  5. 最佳实践与性能优化

1. RestClient 简介与环境准备

1.1 RestClient 简介

RestClient 是 Spring Framework 6 引入的新的 HTTP 客户端。

作为 RestTemplate 的现代替代方案,提供了更简洁的 API、更好的响应式支持和函数式编程风格。

在 Spring Boot 3 中,RestClient 成为了推荐的 HTTP 客户端选择。

相比 RestTemplate,RestClient 具有以下优势:

  • 流畅的 API 设计,支持链式调用
  • 更好的类型安全和错误处理
  • 内置对 JSON 序列化/反序列化的支持
  • 支持拦截器和请求/响应处理
  • 与 Spring 生态系统无缝集成

1.2 环境准备

1.2.1 开发环境
  • JDK: 25
  • Maven: 3.9.11
  • Spring Boot: 3.5.7
1.2.2 创建项目与依赖配置

pom.xml

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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.5.7</version><relativePath/><!-- lookup parent from repository --></parent><groupId>com.lihaozhe</groupId><artifactId>restclient-tutorial</artifactId><version>0.0.1</version><name>restclient-tutorial</name><description>Spring Boot 3 RestClient Tutorial</description><!-- 属性配置 --><properties><java.version>25</java.version></properties><!-- 依赖配置 --><dependencies><!-- Spring Boot Web 依赖,包含 RestClient --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- JSON 处理 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-jsr310</artifactId></dependency><!-- 读取配置文件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- Lombok 简化代码 --><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><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessorPaths><path><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId></path><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></path></annotationProcessorPaths></configuration></plugin><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>
1.2.3 RestClient 配置

创建一个配置类,用于配置 RestClient 实例:

RestClientConfig.java

packagecom.lihaozhe.restclienttutorial.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.http.client.JdkClientHttpRequestFactory;importorg.springframework.web.client.RestClient;@ConfigurationpublicclassRestClientConfig{// 配置默认的 RestClient 实例@BeanpublicRestClientrestClient(){// 创建 RestClient 构建器returnRestClient.builder()// 设置默认基础 URL.baseUrl("https://jsonplaceholder.typicode.com")// 设置请求工厂,这里使用 JDK 自带的 HttpClient.requestFactory(newJdkClientHttpRequestFactory())// 构建 RestClient 实例.build();}}
1.2.4 启动类

RestclientTutorialApplication.java

packagecom.lihaozhe.restclienttutorial;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassRestclientTutorialApplication{publicstaticvoidmain(String[] args){SpringApplication.run(RestclientTutorialApplication.class, args);}}

2. RestClient 基础使用

2.1 数据模型定义

首先定义一个示例数据模型,用于后续的 API 调用:

User.java

packagecom.lihaozhe.restclienttutorial.model;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;// 使用 Lombok 注解简化代码@Data@NoArgsConstructor@AllArgsConstructorpublicclassUser{privateLong id;privateString name;privateString username;privateString email;privateAddress address;privateString phone;privateString website;privateCompany company;}@Data@NoArgsConstructor@AllArgsConstructorclassAddress{privateString street;privateString suite;privateString city;privateString zipcode;privateGeo geo;}@Data@NoArgsConstructor@AllArgsConstructorclassGeo{privateString lat;privateString lng;}@Data@NoArgsConstructor@AllArgsConstructorclassCompany{privateString name;privateString catchPhrase;privateString bs;}

Post.java

packagecom.lihaozhe.restclienttutorial.model;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;@Data@NoArgsConstructor@AllArgsConstructorpublicclassPost{privateLong id;privateLong userId;privateString title;privateString body;}

2.2 基本 HTTP 方法使用

创建一个服务类,演示 RestClient 的基本用法:

ApiService.java

packagecom.lihaozhe.restclienttutorial.service;importcom.lihaozhe.restclienttutorial.model.Post;importcom.lihaozhe.restclienttutorial.model.User;importlombok.RequiredArgsConstructor;importorg.springframework.http.HttpStatus;importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestClient;importjava.util.List;@Service// 构造函数注入所需依赖@RequiredArgsConstructorpublicclassApiService{// 注入 RestClient 实例privatefinalRestClient restClient;/** * 使用 GET 方法获取单个用户 */publicUsergetUserById(Long id){// 发送 GET 请求并返回 User 对象return restClient.get()// 指定请求路径.uri("/users/{id}", id)// 发送请求并将响应体转换为 User 类型.retrieve()// 处理 HTTP 状态码 404 的情况.onStatus(HttpStatus.NOT_FOUND,(request, response)->{thrownewRuntimeException("User not found with id: "+ id);})// 将响应体转换为 User 对象.body(User.class);}/** * 使用 GET 方法获取所有用户 */publicList<User>getAllUsers(){// 发送 GET 请求并返回用户列表return restClient.get().uri("/users").retrieve()// 由于返回的是数组,使用参数化类型.body(User[].class);}/** * 使用 POST 方法创建新帖子 */publicPostcreatePost(Post post){// 发送 POST 请求创建新资源return restClient.post().uri("/posts")// 设置请求体.body(post).retrieve()// 处理 201 Created 状态码.onStatus(HttpStatus.CREATED,(request, response)->{System.out.println("Post created successfully");}).body(Post.class);}/** * 使用 PUT 方法更新帖子 */publicPostupdatePost(Long id,Post post){// 发送 PUT 请求更新资源return restClient.put().uri("/posts/{id}", id).body(post).retrieve().body(Post.class);}/** * 使用 DELETE 方法删除帖子 */publicvoiddeletePost(Long id){// 发送 DELETE 请求删除资源 restClient.delete().uri("/posts/{id}", id).retrieve()// 检查响应状态码是否为 200 OK.toBodilessEntity();}}

2.3 测试 RestClient 基础功能

创建测试类验证上述功能:

ApiServiceTest.java

packagecom.lihaozhe.restclienttutorial.service;importcom.lihaozhe.restclienttutorial.model.Post;importcom.lihaozhe.restclienttutorial.model.User;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjava.util.List;importstaticorg.junit.jupiter.api.Assertions.*;@SpringBootTestclassApiServiceTest{@AutowiredprivateApiService apiService;@TestvoidshouldGetUserById(){// 测试获取单个用户User user = apiService.getUserById(1L);assertNotNull(user);assertEquals(1L, user.getId());assertEquals("Leanne Graham", user.getName());}@TestvoidshouldGetAllUsers(){// 测试获取所有用户List<User> users = apiService.getAllUsers();assertNotNull(users);assertFalse(users.isEmpty());assertTrue(users.size()>0);}@TestvoidshouldCreatePost(){// 测试创建帖子Post post =newPost(null,1L,"Test Title","Test Body");Post createdPost = apiService.createPost(post);assertNotNull(createdPost);assertNotNull(createdPost.getId());assertEquals(post.getTitle(), createdPost.getTitle());assertEquals(post.getBody(), createdPost.getBody());}@TestvoidshouldUpdatePost(){// 测试更新帖子Long postId =1L;Post post =newPost(postId,1L,"Updated Title","Updated Body");Post updatedPost = apiService.updatePost(postId, post);assertNotNull(updatedPost);assertEquals(postId, updatedPost.getId());assertEquals(post.getTitle(), updatedPost.getTitle());}@TestvoidshouldDeletePost(){// 测试删除帖子assertDoesNotThrow(()-> apiService.deletePost(1L));}}

3. RestClient 高级特性

3.1 请求参数与 headers 设置

ApiService.java (扩展)

/** * 演示请求参数和 headers 设置 */publicList<Post>getPostsByUserId(Long userId){// 设置请求参数和 headersreturn restClient.get()// 使用 uri 方法设置查询参数.uri(uriBuilder -> uriBuilder .path("/posts").queryParam("userId", userId).build())// 设置请求头.header("Accept","application/json").header("Authorization","Bearer token123").retrieve().body(Post[].class);}

3.2 拦截器使用

创建一个自定义拦截器,用于日志记录:

LoggingInterceptor.java

packagecom.lihaozhe.restclienttutorial.interceptor;importorg.springframework.http.HttpRequest;importorg.springframework.http.client.ClientHttpRequestExecution;importorg.springframework.http.client.ClientHttpRequestInterceptor;importorg.springframework.http.client.ClientHttpResponse;importorg.springframework.util.StreamUtils;importjava.io.IOException;importjava.nio.charset.StandardCharsets;publicclassLoggingInterceptorimplementsClientHttpRequestInterceptor{@OverridepublicClientHttpResponseintercept(HttpRequest request,byte[] body,ClientHttpRequestExecution execution )throwsIOException{// 记录请求信息logRequest(request, body);// 执行请求ClientHttpResponse response = execution.execute(request, body);// 记录响应信息logResponse(response);return response;}privatevoidlogRequest(HttpRequest request,byte[] body){System.out.println("=== Request ===");System.out.println("Method: "+ request.getMethod());System.out.println("URI: "+ request.getURI());System.out.println("Headers: "+ request.getHeaders());System.out.println("Body: "+newString(body,StandardCharsets.UTF_8));System.out.println("===============");}privatevoidlogResponse(ClientHttpResponse response)throwsIOException{System.out.println("=== Response ===");System.out.println("Status code: "+ response.getStatusCode());System.out.println("Headers: "+ response.getHeaders());System.out.println("Body: "+StreamUtils.copyToString(response.getBody(),StandardCharsets.UTF_8));System.out.println("===============");}}

更新 RestClient 配置,添加拦截器:

RestClientConfig.java (扩展)

// 配置带有拦截器的 RestClient@BeanpublicRestClientrestClientWithInterceptor(){returnRestClient.builder().baseUrl("https://jsonplaceholder.typicode.com").requestFactory(newJdkClientHttpRequestFactory())// 添加自定义拦截器.interceptors(newLoggingInterceptor()).build();}

3.3 错误处理

ApiService.java (扩展)

/** * 演示高级错误处理 */publicUsergetUserWithErrorHandling(Long id){try{return restClient.get().uri("/users/{id}", id).retrieve()// 处理 4xx 客户端错误.onStatus(HttpStatus::is4xxClientError,(request, response)->{String errorBody =StreamUtils.copyToString(response.getBody(),StandardCharsets.UTF_8);thrownewRuntimeException("Client error: "+ response.getStatusCode()+", Body: "+ errorBody);})// 处理 5xx 服务器错误.onStatus(HttpStatus::is5xxServerError,(request, response)->{thrownewRuntimeException("Server error: "+ response.getStatusCode());}).body(User.class);}catch(RestClientException e){// 捕获并处理 RestClient 异常System.err.println("Error fetching user: "+ e.getMessage());// 可以根据需要返回默认值或重新抛出returnnewUser();}}

3.4 超时设置

更新 RestClient 配置,添加超时设置:

RestClientConfig.java (扩展)

// 配置带有超时设置的 RestClient@BeanpublicRestClientrestClientWithTimeout(){// 创建 HTTP 客户端工厂并设置超时JdkClientHttpRequestFactory requestFactory =newJdkClientHttpRequestFactory();// 设置连接超时 requestFactory.setConnectTimeout(Duration.ofSeconds(5));// 设置读取超时 requestFactory.setReadTimeout(Duration.ofSeconds(10));returnRestClient.builder().baseUrl("https://jsonplaceholder.typicode.com").requestFactory(requestFactory).build();}

4. 实战案例:RESTful API 客户端实现

4.1 案例说明

我们将实现一个完整的 RESTful API 客户端,用于管理"任务"资源,包括以下功能:

  • 获取所有任务
  • 获取单个任务
  • 创建任务
  • 更新任务
  • 删除任务
  • 根据状态筛选任务

4.2 数据模型

Task.java

packagecom.lihaozhe.restclienttutorial.model;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importjava.time.LocalDateTime;@Data@NoArgsConstructor@AllArgsConstructorpublicclassTask{privateLong id;privateString title;privateString description;privateboolean completed;privateLocalDateTime createdAt;privateLocalDateTime updatedAt;}

4.3 服务接口

TaskService.java

packagecom.lihaozhe.restclienttutorial.service;importcom.lihaozhe.restclienttutorial.model.Task;importjava.util.List;publicinterfaceTaskService{List<Task>getAllTasks();TaskgetTaskById(Long id);TaskcreateTask(Task task);TaskupdateTask(Long id,Task task);voiddeleteTask(Long id);List<Task>getTasksByStatus(boolean completed);}

4.4 服务实现

TaskServiceImpl.java

packagecom.lihaozhe.restclienttutorial.service;importcom.lihaozhe.restclienttutorial.model.Task;importlombok.RequiredArgsConstructor;importorg.springframework.http.HttpStatus;importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestClient;importjava.util.List;@Service@RequiredArgsConstructorpublicclassTaskServiceImplimplementsTaskService{privatefinalRestClient restClient;// 任务 API 的基础路径privatestaticfinalString TASKS_BASE_URL ="/tasks";@OverridepublicList<Task>getAllTasks(){return restClient.get().uri(TASKS_BASE_URL).retrieve().body(Task[].class);}@OverridepublicTaskgetTaskById(Long id){return restClient.get().uri(TASKS_BASE_URL +"/{id}", id).retrieve().onStatus(HttpStatus.NOT_FOUND,(request, response)->{thrownewRuntimeException("Task not found with id: "+ id);}).body(Task.class);}@OverridepublicTaskcreateTask(Task task){// 设置创建时间 task.setCreatedAt(LocalDateTime.now()); task.setUpdatedAt(LocalDateTime.now());return restClient.post().uri(TASKS_BASE_URL).body(task).retrieve().onStatus(HttpStatus.CREATED,(request, response)->{System.out.println("Task created successfully");}).body(Task.class);}@OverridepublicTaskupdateTask(Long id,Task task){// 设置更新时间 task.setUpdatedAt(LocalDateTime.now());return restClient.put().uri(TASKS_BASE_URL +"/{id}", id).body(task).retrieve().body(Task.class);}@OverridepublicvoiddeleteTask(Long id){ restClient.delete().uri(TASKS_BASE_URL +"/{id}", id).retrieve().toBodilessEntity();}@OverridepublicList<Task>getTasksByStatus(boolean completed){return restClient.get().uri(uriBuilder -> uriBuilder .path(TASKS_BASE_URL).queryParam("completed", completed).build()).retrieve().body(Task[].class);}}

4.5 控制器层

TaskController.java

packagecom.lihaozhe.restclienttutorial.controller;importcom.lihaozhe.restclienttutorial.model.Task;importcom.lihaozhe.restclienttutorial.service.TaskService;importlombok.RequiredArgsConstructor;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.*;importjava.util.List;@RestController@RequestMapping("/api/tasks")@RequiredArgsConstructorpublicclassTaskController{privatefinalTaskService taskService;@GetMappingpublicList<Task>getAllTasks(){return taskService.getAllTasks();}@GetMapping("/{id}")publicResponseEntity<Task>getTaskById(@PathVariableLong id){try{Task task = taskService.getTaskById(id);returnResponseEntity.ok(task);}catch(RuntimeException e){returnResponseEntity.notFound().build();}}@PostMappingpublicResponseEntity<Task>createTask(@RequestBodyTask task){Task createdTask = taskService.createTask(task);returnnewResponseEntity<>(createdTask,HttpStatus.CREATED);}@PutMapping("/{id}")publicResponseEntity<Task>updateTask(@PathVariableLong id,@RequestBodyTask task ){Task updatedTask = taskService.updateTask(id, task);returnResponseEntity.ok(updatedTask);}@DeleteMapping("/{id}")publicResponseEntity<Void>deleteTask(@PathVariableLong id){ taskService.deleteTask(id);returnResponseEntity.noContent().build();}@GetMapping("/filter")publicList<Task>getTasksByStatus(@RequestParamboolean completed){return taskService.getTasksByStatus(completed);}}

4.6 测试用例

TaskServiceImplTest.java

packagecom.lihaozhe.restclienttutorial.service;importcom.lihaozhe.restclienttutorial.model.Task;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.web.client.RestClient;importjava.time.LocalDateTime;importjava.util.List;importstaticorg.junit.jupiter.api.Assertions.*;@SpringBootTestclassTaskServiceImplTest{@AutowiredprivateTaskService taskService;// 注入带有拦截器的 RestClient 用于测试@Autowired@Qualifier("restClientWithInterceptor")privateRestClient restClient;@TestvoidshouldPerformCrudOperations(){// 创建任务Task task =newTask(null,"Test Task","Test Description",false,null,null);Task createdTask = taskService.createTask(task);assertNotNull(createdTask);assertNotNull(createdTask.getId());assertEquals(task.getTitle(), createdTask.getTitle());assertNotNull(createdTask.getCreatedAt());// 获取任务Long taskId = createdTask.getId();Task fetchedTask = taskService.getTaskById(taskId);assertNotNull(fetchedTask);assertEquals(taskId, fetchedTask.getId());// 更新任务 fetchedTask.setCompleted(true); fetchedTask.setTitle("Updated Task Title");Task updatedTask = taskService.updateTask(taskId, fetchedTask);assertNotNull(updatedTask);assertTrue(updatedTask.isCompleted());assertEquals("Updated Task Title", updatedTask.getTitle());assertTrue(updatedTask.getUpdatedAt().isAfter(createdTask.getCreatedAt()));// 按状态筛选任务List<Task> completedTasks = taskService.getTasksByStatus(true);assertFalse(completedTasks.isEmpty());// 删除任务assertDoesNotThrow(()-> taskService.deleteTask(taskId));// 验证任务已删除assertThrows(RuntimeException.class,()-> taskService.getTaskById(taskId));}}

5. 最佳实践与性能优化

5.1 最佳实践

  1. 单一职责原则:每个 RestClient 实例专注于特定的 API 或服务
  2. 异常处理:始终处理可能的异常,提供有意义的错误信息
  3. 连接池管理:合理配置连接池大小和超时时间
  4. 避免重复创建:RestClient 实例应该是单例的,避免频繁创建和销毁
  5. 日志记录:使用拦截器记录关键请求和响应信息,便于调试
  6. 配置外部化:将基础 URL、超时时间等配置放在配置文件中
  7. 使用 Builders:利用 RestClient 的构建器模式创建客户端实例

5.2 性能优化

  1. 连接池配置
@BeanpublicRestClientrestClientWithPool(){// 配置 HTTP 客户端连接池HttpClient httpClient =HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).connectionPool(newConnectionPool(10,30,TimeUnit.SECONDS)).build();JdkClientHttpRequestFactory requestFactory =newJdkClientHttpRequestFactory(httpClient);returnRestClient.builder().baseUrl("https://api.lihaozhe.com").requestFactory(requestFactory).build();}
  1. 响应压缩:启用请求和响应压缩
@BeanpublicRestClientrestClientWithCompression(){HttpClient httpClient =HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build();JdkClientHttpRequestFactory requestFactory =newJdkClientHttpRequestFactory(httpClient);returnRestClient.builder().baseUrl("https://api.lihaozhe.com").requestFactory(requestFactory).defaultHeader("Accept-Encoding","gzip, deflate").build();}
  1. 异步请求:对于非阻塞场景,使用异步请求
@BeanpublicAsyncRestClientasyncRestClient(){returnAsyncRestClient.builder().baseUrl("https://api.lihaozhe.com").build();}// 使用示例publicCompletableFuture<User>getUserAsync(Long id){return asyncRestClient.get().uri("/users/{id}", id).retrieve().bodyToMono(User.class).toFuture();}
  1. 缓存策略:对于频繁访问且不常变化的资源,实现缓存机制
privatefinalCache<String,User> userCache =CacheBuilder.newBuilder().expireAfterWrite(10,TimeUnit.MINUTES).maximumSize(100).build();publicUsergetCachedUser(Long id){try{return userCache.get(id.toString(),()->{// 缓存未命中时,从 API 获取return restClient.get().uri("/users/{id}", id).retrieve().body(User.class);});}catch(ExecutionException e){thrownewRuntimeException("Error fetching user", e.getCause());}}

5.3 配置外部化

application.properties

# API 基础 URL api.base-url=https://jsonplaceholder.typicode.com # 连接超时(毫秒) api.connection-timeout=5000 # 读取超时(毫秒) api.read-timeout=10000 # 连接池大小 api.connection-pool-size=10 

配置类

@Configuration@ConfigurationProperties(prefix ="api")@DatapublicclassApiProperties{privateString baseUrl;privateint connectionTimeout;privateint readTimeout;privateint connectionPoolSize;}@ConfigurationpublicclassConfiguredRestClientConfig{@BeanpublicRestClientconfiguredRestClient(ApiProperties apiProperties){HttpClient httpClient =HttpClient.newBuilder().connectTimeout(Duration.ofMillis(apiProperties.getConnectionTimeout())).connectionPool(newConnectionPool( apiProperties.getConnectionPoolSize(),30,TimeUnit.SECONDS )).build();JdkClientHttpRequestFactory requestFactory =newJdkClientHttpRequestFactory(httpClient); requestFactory.setReadTimeout(Duration.ofMillis(apiProperties.getReadTimeout()));returnRestClient.builder().baseUrl(apiProperties.getBaseUrl()).requestFactory(requestFactory).interceptors(newLoggingInterceptor()).build();}}

总结

本教程详细介绍了 Spring Boot 3 中 RestClient 的使用方法,从基础到高级,涵盖了各种常见场景和最佳实践。RestClient 作为 RestTemplate 的现代替代方案,提供了更简洁、更灵活的 API,是开发 RESTful 客户端的理想选择。

通过本教程,你应该能够:

  • 理解 RestClient 的核心概念和优势
  • 配置和使用 RestClient 发送各种 HTTP 请求
  • 处理请求参数、headers 和响应数据
  • 使用拦截器、错误处理等高级特性
  • 实现完整的 RESTful API 客户端
  • 应用最佳实践和性能优化技巧

RestClient 结合了 Spring 的强大功能和现代 Java 的特性,为开发者提供了高效、可靠的 HTTP 客户端解决方案。在实际项目中,应根据具体需求选择合适的配置和功能,以获得最佳的性能和可维护性。

Read more

大疆无人机常见故障提示及应对指南

大疆无人机常见故障提示及应对指南

大疆无人机在使用过程中,故障提示主要通过 DJI Fly/DJI GO 4 App 弹窗、机身指示灯状态及遥控器提示音三种方式呈现。以下按「连接通信类」「传感系统类」「动力系统类」「图传相机类」「电池电源类」五大核心场景,整理常见故障提示、核心原因及分步解决办法,帮助快速定位并处理问题。 北京云升智维科技有限责任公司是一家专业从事电子设备维修第三方服务企业,我们拥有深厚的电路原理知识和丰富的维修经验,能够为各种设备和电路板提供专业的检测和维修服务。我们的服务范围广泛,包括但不限于电路板、工控主板、工业机械、医疗设备、精密仪器、大地测量仪器及驱动器等。我们拥有一支技术过硬,经验丰富的维修团队,精通各类设备维修,结合多年实战维修经验,快速准确诊断故障,提高维修效率,为客户节省35%及以上维修成本及时间成本,我们致力于为客户提供高质量、可靠的服务,确保设备的稳定运行。我们坚持诚实守信、笃行致远的原则,以确保客户满意。 一、连接通信类故障提示 核心表现:App 提示连接异常,遥控器与无人机无法联动,

By Ne0inhk
【保姆级教程】从零入手:Python + Neo4j 构建你的第一个知识图谱

【保姆级教程】从零入手:Python + Neo4j 构建你的第一个知识图谱

摘要: 大数据时代,数据之间的关系往往比数据本身更有价值。传统的 SQL 数据库在处理复杂关系(如社交网络、推荐系统、风控分析)时显得力不从心,而 知识图谱 和 图数据库 Neo4j 正是为此而生。本文将带你从 0 基础出发,理解知识图谱核心概念,安装 Neo4j 环境,并手把手教你用 Python 代码构建一个生动的人物关系图谱。拒绝枯燥理论,全是实战干货! 一、 什么是知识图谱与 Neo4j? 在动手写代码之前,我们先用大白话把两个核心概念捋清楚。 1. 什么是知识图谱 (Knowledge Graph)? 不要被高大上的名字吓到。知识图谱本质上就是把世界上的事物(节点)和它们之间的联系(关系)画成一张巨大的网。 * Excel 思维: 罗列数据。例如:张三,25岁;李四,

By Ne0inhk
FAIR plus 机器人全产业链接会,链动全球智能新机遇

FAIR plus 机器人全产业链接会,链动全球智能新机遇

本文声明:本篇内容为个人真实体验分享,非商业广告,无强制消费引导。所有推荐仅代表个人感受,仅供参考,按需选择。 过往十年,中国机器人产业蓬勃发展。中国出品的核心部件得到了产业规模化的验证,机器人产品的整体制造能力也开始向全球输出。与此同时,机器人产业正在更加紧密地与人工智能融合,机器人从专用智能走向通用智能。 在此背景下,深圳市机器人协会打造了“FAIR plus机器人全产业链接会”,FAIR plus是一个专注于机器人全产业链技术和开发资源的平台,也是全球首个机器人开发技术展,以供应链和创新技术为切入点,推动全球具身智能机器人产业的发展。通过学术会议、技术标准、社区培育、供需对接等方式,创造人工智能+机器人各产业链环节的开发、产品、工程、方案等技术人员,以及有意引入机器人的场景方相关工艺、设备、信息技术人员线下见面的机会,达成合作,以有效促进机器人向智能化方向发展,连同提升产业整体能力的建设和配置。 2025年4月,首届“FAIR plus机器人全产业链接会”(FAIR plus 2025)以“智启未来链动全球”为主题,汇聚全球顶尖专家、企业领袖,

By Ne0inhk
【CS创世SD NAND征文】为无人机打造可靠数据仓:工业级存储芯片CSNP32GCR01-AOW在飞控系统中的应用实践

【CS创世SD NAND征文】为无人机打造可靠数据仓:工业级存储芯片CSNP32GCR01-AOW在飞控系统中的应用实践

一、引言:无人机时代的数据存储挑战 在无人机(UAV)技术飞速发展的今天,其应用范畴早已突破消费级航拍的界限,深度渗透至测绘勘察、基础设施巡检、精准农业、安防监控乃至国防军事等工业级领域。每一次精准的自动巡航、每一帧高清图像的实时图传、每一条飞行轨迹的忠实记录,都离不开飞控系统这颗"大脑"的精密运算。然而,大脑的决策依赖于记忆与学习,而承担这一"记忆"任务的存储单元,其可靠性直接决定了飞行任务的成败与数据的价值。一次意外的数据丢失或存储故障,不仅可能导致珍贵的测绘数据付诸东流,造成重大的经济损失,甚至可能引发严重的飞行安全事故。因此,为无人机飞控系统选择一款高性能、高可靠的存储芯片,已成为行业设计中不可或缺的关键一环。 本文将围绕基于全志MR100主控平台与CS创世SD NAND(具体型号:CSNP32GCR01-AOW)构建的新一代无人机飞控存储方案,深入探讨工业级存储芯片如何为高端无人机赋予稳定、可靠的"数据生命线",助力无人机技术在各个领域发挥更大的价值。 二、应用产品介绍:无人机飞控系统——空中机器人的智能核心

By Ne0inhk