Spring Boot 的 WebClient 实践教程

news2025/2/12 0:33:39

什么是 WebClient?

在 Spring Boot 中,WebClient 是 Spring WebFlux 提供的一个非阻塞、响应式的 HTTP 客户端,用于与 RESTful 服务或其他 HTTP 服务交互。相比于传统的 RestTemplate,WebClient 更加现代化,具有异步和非阻塞的特点,适合高性能、高并发的应用场景。

WebClient 的特点

非阻塞 I/O:适用于响应式编程模型,能高效处理大量并发请求。

功能强大:支持同步和异步调用,处理复杂的 HTTP 请求和响应,包括流式数据。

灵活的配置:可自定义超时、请求拦截器、认证方式等。

响应式编程支持:返回 Mono 或 Flux,与 Spring WebFlux 的响应式编程模型无缝集成。

引入依赖

在使用 WebClient 之前,需要确保 Spring Boot 项目已包含相关依赖。

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

配置及使用 WebClient

现在有以下服务

  • service1服务:http://localhost:8081/
  • service2服务:http://localhost:8082/
  • common服务:http://localhost:8079/

创建 WebClientConfig 配置类,为 service1 和 service2 配置独立的 WebClient。

package com.example.common.config;

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.TcpClient;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;

/**
 * 配置 WebClient,支持基础功能(独立 WebClient 实例)和高级特性(超时、拦截器、内存限制)。
 */
@Configuration
public class WebClientConfig {

    /**
     * 配置 WebClient,用于调用 service1(http://localhost:8081)
     *
     * @param builder WebClient.Builder 实例
     * @return 针对 service1 的 WebClient 实例
     */
    @Bean(name = "service1WebClient")
    public WebClient service1WebClient(WebClient.Builder builder) {
        return builder
                .baseUrl("http://localhost:8081") // 配置 service1 的基本 URL
                .defaultHeader("Content-Type", "application/json") // 设置默认请求头
                .exchangeStrategies(
                        ExchangeStrategies.builder()
                                .codecs(configurer -> configurer
                                        .defaultCodecs()
                                        .maxInMemorySize(16 * 1024 * 1024)) // 设置最大内存限制为 16MB
                                .build())
                .filter(logRequest()) // 添加请求日志拦截器
                .filter(logResponse()) // 添加响应日志拦截器
                .build();
    }

    /**
     * 配置 WebClient,用于调用 service2(http://localhost:8082)
     *
     * @param builder WebClient.Builder 实例
     * @return 针对 service2 的 WebClient 实例
     */
    @Bean(name = "service2WebClient")
    public WebClient service2WebClient(WebClient.Builder builder) {
        return builder
                .baseUrl("http://localhost:8082") // 配置 service2 的基本 URL
                .defaultHeader("Content-Type", "application/json") // 设置默认请求头
                .filter(logRequest()) // 添加请求日志拦截器
                .filter(logResponse()) // 添加响应日志拦截器
                .build();
    }

    /**
     * 提供全局的 WebClient.Builder 配置,支持超时和高级功能。
     *
     * @return 配置好的 WebClient.Builder
     */
    @Bean
    public WebClient.Builder webClientBuilder() {
        // 配置 TCP 客户端,设置连接超时、读超时和写超时
        TcpClient tcpClient = TcpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // 连接超时 5秒
                .doOnConnected(connection ->
                        connection.addHandlerLast(new ReadTimeoutHandler(5)) // 读超时 5秒
                                  .addHandlerLast(new WriteTimeoutHandler(5))); // 写超时 5秒

        // 使用配置的 TcpClient 创建 HttpClient
        HttpClient httpClient = HttpClient.from(tcpClient);

        // 创建 WebClient.Builder 并配置 HttpClient 和拦截器
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient)) // 配置 HttpClient
                .filter(logRequest()) // 请求日志拦截器
                .filter(logResponse()); // 响应日志拦截器
    }

    /**
     * 请求日志拦截器:记录请求的详细信息(方法和 URL)
     *
     * @return ExchangeFilterFunction 拦截器
     */
    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(request -> {
            System.out.println("Request: " + request.method() + " " + request.url());
            return Mono.just(request);
        });
    }

    /**
     * 响应日志拦截器:记录响应的状态码
     *
     * @return ExchangeFilterFunction 拦截器
     */
    private ExchangeFilterFunction logResponse() {
        return ExchangeFilterFunction.ofResponseProcessor(response -> {
            System.out.println("Response status: " + response.statusCode());
            return Mono.just(response);
        });
    }
}

service1相应的接口

package cloud.service1.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * Service1 的控制器类,用于处理与API相关的请求.
 * 该类被Spring框架管理,作为处理HTTP请求的一部分.
 */
@RestController
@RequestMapping("/api/service1")
public class Service1Controller {

    /**
     * 获取Service1的数据信息.
     * 
     * @return 包含服务信息的映射,包括服务名称和问候消息.
     */
    @GetMapping("/data")
    public Map<String, String> getData() {
        // 返回一个不可变的映射,包含服务名称和问候消息
        return Map.of("service", "service1", "message", "Hello from Service1");
    }
}

service2相应的接口

package cloud.service2.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * Service2的控制器类,用于处理与Service2相关的HTTP请求.
 * 该类被Spring框架管理,作为处理RESTful请求的控制器.
 */
@RestController
@RequestMapping("/api/service2")
public class Service2Controller {

    /**
     * 处理GET请求到/api/service2/info,返回Service2的信息.
     * 
     * @return 包含服务信息的Map,包括服务名称和欢迎消息.
     */
    @GetMapping("/info")
    public Map<String, String> getInfo() {
        return Map.of("service", "service2", "message", "Hello from Service2");
    }
}

服务调用实现

package com.example.common.service;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

/**
 * CommonService 类提供了对其他服务进行调用的方法
 * 它通过 WebClient 实例与 service1 和 service2 进行通信
 */
@Service
public class CommonService {

    // 用于与 service1 通信的 WebClient 实例
    private final WebClient service1WebClient;
    // 用于与 service2 通信的 WebClient 实例
    private final WebClient service2WebClient;

    /**
     * 构造函数注入两个 WebClient 实例
     *
     * @param service1WebClient 用于 service1 的 WebClient
     * @param service2WebClient 用于 service2 的 WebClient
     */
    public CommonService(
            @Qualifier("service1WebClient") WebClient service1WebClient,
            @Qualifier("service2WebClient") WebClient service2WebClient) {
        this.service1WebClient = service1WebClient;
        this.service2WebClient = service2WebClient;
    }

    /**
     * 调用 service1 的接口
     *
     * @return 来自 service1 的数据
     */
    public Mono<String> callService1() {
        // 通过 service1WebClient 调用 service1 的 API,并处理可能的错误
        return service1WebClient.get()
                .uri("/api/service1/data")
                .retrieve()
                .bodyToMono(String.class)
                .onErrorResume(e -> {
                    // 错误处理:打印错误信息并返回错误提示
                    System.err.println("Error calling service1: " + e.getMessage());
                    return Mono.just("Error calling service1");
                });
    }

    /**
     * 调用 service2 的接口
     *
     * @return 来自 service2 的数据
     */
    public Mono<String> callService2() {
        // 通过 service2WebClient 调用 service2 的 API,并处理可能的错误
        return service2WebClient.get()
                .uri("/api/service2/info")
                .retrieve()
                .bodyToMono(String.class)
                .onErrorResume(e -> {
                    // 错误处理:打印错误信息并返回错误提示
                    System.err.println("Error calling service2: " + e.getMessage());
                    return Mono.just("Error calling service2");
                });
    }
}
package com.example.common.controller;

import com.example.common.service.CommonService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

/**
 * 通用控制器类,处理与通用服务相关的API请求
 */
@RestController
@RequestMapping("/api/common")
public class CommonController {

    // 注入通用服务接口,用于调用具体的服务方法
    private final CommonService commonService;

    /**
     * 构造函数注入CommonService实例
     *
     * @param commonService 通用服务接口实例
     */
    public CommonController(CommonService commonService) {
        this.commonService = commonService;
    }

    /**
     * 调用 service1 的接口
     *
     * @return service1 的响应数据
     */
    @GetMapping("/service1")
    public Mono<String> getService1Data() {
        return commonService.callService1();
    }

    /**
     * 调用 service2 的接口
     *
     * @return service2 的响应数据
     */
    @GetMapping("/service2")
    public Mono<String> getService2Info() {
        return commonService.callService2();
    }
}

测试接口

优化实践

将上述代码进一步优化和整合以确保代码可维护性和高效性。

package com.example.common.config;

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.TcpClient;

/**
 * 配置 WebClient 的各类设置和日志记录
 */
@Configuration
public class WebClientConfig {

    /**
     * 全局 WebClient.Builder 配置
     *
     * @return 配置好的 WebClient.Builder
     */
    @Bean
    public WebClient.Builder webClientBuilder() {
        // 配置 TCP 客户端的连接、读取、写入超时时间
        TcpClient tcpClient = TcpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) // 连接超时
                .doOnConnected(conn -> conn
                        .addHandlerLast(new ReadTimeoutHandler(5)) // 读超时
                        .addHandlerLast(new WriteTimeoutHandler(5))); // 写超时

        // 将 TCP 客户端配置应用到 HTTP 客户端
        HttpClient httpClient = HttpClient.from(tcpClient);

        // 配置 WebClient 构建器,包括 HTTP 连接器、交换策略、请求和响应日志
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .exchangeStrategies(ExchangeStrategies.builder()
                        .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024)) // 内存限制
                        .build())
                .filter(logRequest())  // 请求日志
                .filter(logResponse()); // 响应日志
    }

    /**
     * 针对 service1 的 WebClient 配置
     *
     * @param builder 全局配置的 WebClient.Builder
     * @return 配置好的 WebClient 实例
     */
    @Bean(name = "service1WebClient")
    public WebClient service1WebClient(WebClient.Builder builder) {
        // 为 service1 配置特定的 base URL 和默认头部
        return builder
                .baseUrl("http://localhost:8081")
                .defaultHeader("Content-Type", "application/json")
                .build();
    }

    /**
     * 针对 service2 的 WebClient 配置
     *
     * @param builder 全局配置的 WebClient.Builder
     * @return 配置好的 WebClient 实例
     */
    @Bean(name = "service2WebClient")
    public WebClient service2WebClient(WebClient.Builder builder) {
        // 为 service2 配置特定的 base URL 和默认头部
        return builder
                .baseUrl("http://localhost:8082")
                .defaultHeader("Content-Type", "application/json")
                .build();
    }

    /**
     * 请求日志拦截器
     *
     * @return 记录请求日志的 ExchangeFilterFunction
     */
    private ExchangeFilterFunction logRequest() {
        // 拦截请求并打印请求方法和URL
        return ExchangeFilterFunction.ofRequestProcessor(request -> {
            System.out.println("Request: " + request.method() + " " + request.url());
            return Mono.just(request);
        });
    }

    /**
     * 响应日志拦截器
     *
     * @return 记录响应日志的 ExchangeFilterFunction
     */
    private ExchangeFilterFunction logResponse() {
        // 拦截响应并打印响应状态码
        return ExchangeFilterFunction.ofResponseProcessor(response -> {
            System.out.println("Response status: " + response.statusCode());
            return Mono.just(response);
        });
    }
}
package com.example.common.service;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.Map;

/**
 * CommonService 类提供了调用两个不同服务的公共方法,并合并其结果
 */
@Service
public class CommonService {

    // service1 的 WebClient 实例
    private final WebClient service1WebClient;
    // service2 的 WebClient 实例
    private final WebClient service2WebClient;

    /**
     * 构造函数注入 WebClient 实例
     *
     * @param service1WebClient service1 的 WebClient
     * @param service2WebClient service2 的 WebClient
     */
    public CommonService(WebClient service1WebClient, WebClient service2WebClient) {
        this.service1WebClient = service1WebClient;
        this.service2WebClient = service2WebClient;
    }

    /**
     * 异步调用 service1 和 service2,并返回合并结果(JSON 格式)
     *
     * @return 包含两个服务响应的 Mono 对象
     */
    public Mono<Map<String, Map<String, String>>> callServicesAsync() {
        // 调用 service1,返回 Map 响应
        Mono<Map<String, String>> service1Response = service1WebClient.get()
                // 设置请求的URI
               .uri("/api/service1/data")
                // 检索响应
               .retrieve()
                // 处理错误状态
               .onStatus(
                        // 检查状态是否为4xx或5xx
                        status -> status.is4xxClientError() || status.is5xxServerError(),
                        // 如果是,创建一个运行时异常
                        response -> Mono.error(new RuntimeException("Service1 Error: " + response.statusCode()))
                )
                // 将响应体转换为Mono<Map<String, String>>
               .bodyToMono(new ParameterizedTypeReference<Map<String, String>>() {})
                // 处理错误
               .onErrorResume(e -> {
                    // 打印错误信息
                    System.err.println("Error calling service1: " + e.getMessage());
                    // 返回一个包含错误信息的Map
                    return Mono.just(Map.of("error", "Fallback response for service1"));
                });

        // 调用 service2,返回 Map 响应
        Mono<Map<String, String>> service2Response = service2WebClient.get()
                // 设置请求的URI
               .uri("/api/service2/info")
                // 检索响应
               .retrieve()
                // 处理错误状态
               .onStatus(
                        // 检查状态是否为4xx或5xx
                        status -> status.is4xxClientError() || status.is5xxServerError(),
                        // 如果是,创建一个运行时异常
                        response -> Mono.error(new RuntimeException("Service2 Error: " + response.statusCode()))
                )
                // 将响应体转换为Mono<Map<String, String>>
               .bodyToMono(new ParameterizedTypeReference<Map<String, String>>() {})
                // 处理错误
               .onErrorResume(e -> {
                    // 打印错误信息
                    System.err.println("Error calling service2: " + e.getMessage());
                    // 返回一个包含错误信息的Map
                    return Mono.just(Map.of("error", "Fallback response for service2"));
                });

        // 合并两个响应
        return Mono.zip(service1Response, service2Response, (response1, response2) -> Map.of(
                "service1", response1,
                "service2", response2
        ))
        // 处理合并过程中的错误
       .onErrorResume(e -> {
            // 打印错误信息
            System.err.println("Error combining responses: " + e.getMessage());
            // 返回一个包含错误信息的Map
            return Mono.just(Map.of(
                    "error", Map.of(
                            "status", "error",
                            "message", e.getMessage() // 捕获异常并输出信息
                    )
            ));
        });
    }
}
package com.example.common.controller;

import com.example.common.service.CommonService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import java.util.Map;

@RestController
@RequestMapping("/api/common")
public class CommonController {

    private final CommonService commonService;

    public CommonController(CommonService commonService) {
        this.commonService = commonService;
    }

    /**
     * 提供异步调用的 REST 接口,返回 JSON 格式的数据
     */
    @GetMapping("/service")
    public Mono<Map<String, Map<String, String>>> getServicesData() {
        System.out.println("Received request for combined service data");
        return commonService.callServicesAsync()
                .doOnSuccess(response -> System.out.println("Successfully retrieved data: " + response))
                .doOnError(error -> System.err.println("Error occurred while fetching service data: " + error.getMessage()));
    }
}

测试接口 

结语 

WebClient 是一个功能强大且灵活的非阻塞 HTTP 客户端,特别适合在高并发和响应式编程场景下使用,是替代传统 RestTemplate 的优秀选择。在实际项目中,通过合理配置(如超时、连接池)和优化(如负载均衡、重试机制),可以显著提高服务间通信的效率和可靠性,降低延迟和资源消耗。

同时,结合 Spring WebFlux 提供的响应式编程支持,WebClient 能够更好地应对微服务架构中复杂的通信需求,成为开发现代分布式系统的重要工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2251048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉搜索树讲解

二叉搜索树概念和定义 二叉搜索树是一个二叉树&#xff0c;其中每个节点的值都满足以下条件&#xff1a; 节点的左子树只包含小于当前节点值的节点。节点的右子树只包含大于当前节点值的节点。左右子树也必须是二叉搜索树。 二叉树搜索树性质 从上面的二叉搜索树定义中可以了…

FinalShell工具数据备份升级、密码解密方法

前言 FinalShell 作为国产的服务器管理工具和远程终端软件。一个一体化的运维工具&#xff0c;在国内运维人员中还是比较受欢迎。它整合了多个常用功能&#xff0c;界面友好&#xff0c;使用方便。不过它是一个闭源的商业软件&#xff0c;虽然提供免费版本&#xff0c;但部分高…

241130_昇思MindSpore函数式自动微分

241130_昇思MindSpore函数式自动微分 函数式自动微分是Mindspore学习框架所特有的&#xff0c;更偏向于数学计算的习惯。这里也是和pytorch差距最大的部分&#xff0c;具体体现在训练部分的代码&#xff0c;MindSpore是把各个梯度计算、损失函数计算 在这幅图中&#xff0c;右…

菱形打印(Python)

“以块组合块”&#xff0c;以行凝结循环打印。 (笔记模板由python脚本于2024年11月30日 19:55:22创建&#xff0c;本篇笔记适合正在学习python循环的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”…

【QT入门到晋级】QT项目打生产环境包--(Linux和window)

前言 使用QTcreator完成正常编译后&#xff0c;在构建目录中有可执行程序生成&#xff0c;如果直接把可执行程序拷贝到干净的生产环境上是无法运行成功的&#xff0c;使用ldd&#xff08;查看程序依赖包&#xff09;会发现缺失很多QT的特性包&#xff0c;以及将介绍国产Linux桌…

Super Vlan与Mux Vlan

SuperVlan VLAN Aggregation&#xff0c; 也称 Super-VLAN : 指 在一个物理网络内&#xff0c;用多个 VLAN &#xff08;称为 Sub-VLAN &#xff09;隔离 广播域&#xff0c;并将这些 Sub-VLAN 聚合成一个逻辑的 VLAN &#xff08;称为 Super-VLAN &#xff09;&#xff0c;这…

蓝牙定位的MATLAB程序,四个锚点、三维空间

这段代码通过RSSI信号强度实现了在三维空间中的蓝牙定位&#xff0c;展示了如何使用锚点位置和测量的信号强度来估计未知点的位置。代码涉及信号衰减模型、距离计算和最小二乘法估计等基本概念&#xff0c;并通过三维可视化展示了真实位置与估计位置的关系。 目录 程序描述 运…

Hutool 秒速实现 2FA 两步验证

前言 随着网络安全威胁的日益复杂&#xff0c;传统的用户名和密码认证方式已不足以提供足够的安全保障。为了增强用户账户的安全性&#xff0c;越来越多的应用和服务开始采用多因素认证&#xff08;MFA&#xff09;。基于时间的一次性密码&#xff08;TOTP, Time-based One-Ti…

【继承】—— 我与C++的不解之缘(十九)

前言&#xff1a; 面向对象编程语言的三大特性&#xff1a;封装、继承和多态 本篇博客来学习C中的继承&#xff0c;加油&#xff01; 一、什么是继承&#xff1f; ​ 继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段&#xff0c;它允许我们在保持原有类…

【目标跟踪】Anti-UAV数据集详细介绍

Anti-UAV数据集是在2021年公开的专用于无人机跟踪的数据集&#xff0c;该数据集采用RGB-T图像对的形式来克服单个类型视频的缺点&#xff0c;包含了318个视频对&#xff0c;并提出了相应的评估标准&#xff08;the state accurancy, SA)。 文章链接&#xff1a;https://arxiv.…

偏差-方差权衡(Bias–Variance Tradeoff):理解监督学习中的核心问题

偏差-方差权衡&#xff08;Bias–Variance Tradeoff&#xff09;&#xff1a;理解监督学习中的核心问题 在机器学习中&#xff0c;我们希望构建一个能够在训练数据上表现良好&#xff0c;同时对未见数据也具有强大泛化能力的模型。然而&#xff0c;模型的误差&#xff08;尤其…

Figma入门-原型交互

Figma入门-原型交互 前言 在之前的工作中&#xff0c;大家的原型图都是使用 Axure 制作的&#xff0c;印象中 Figma 一直是个专业设计软件。 最近&#xff0c;很多产品朋友告诉我&#xff0c;很多原型图都开始用Figma制作了&#xff0c;并且很多组件都是内置的&#xff0c;对…

Windows系统怎么把日历添加在桌面上用来记事?

在众多电脑操作系统中&#xff0c;Windows系统以其广泛的用户基础和强大的功能&#xff0c;成为许多人的首选。对于习惯于在电脑前工作和学习的用户来说&#xff0c;能够直接在桌面上查看和记录日历事项&#xff0c;无疑会大大提高工作效率和生活便利性。今天&#xff0c;就为大…

蓝桥杯备赛笔记(一)

这里的笔记是关于蓝桥杯关键知识点的记录&#xff0c;有别于基础语法&#xff0c;很多内容只要求会用就行&#xff0c;无需深入掌握。 文章目录 前言一、编程基础1.1 C基础格式和版本选择1.2 输入输出cin和cout&#xff1a; 1.3 string以下是字符串的一些简介&#xff1a;字符串…

大数据新视界 -- 大数据大厂之 Hive 数据压缩:优化存储与传输的关键(上)(19/ 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

RNN And CNN通识

CNN And RNN RNN And CNN通识一、卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;CNN&#xff09;1. 诞生背景2. 核心思想和原理&#xff08;1&#xff09;基本结构&#xff1a;&#xff08;2&#xff09;核心公式&#xff1a;&#xff08;3&#xff09;关…

求整数的和与均值

求整数的和与均值 C语言代码C 代码Java代码Python代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 读入n&#xff08;1 < n < 10000&#xff09;个整数&#xff0c;求它们的和与均值。 输入 输入第一行是一个整数n&#xff0c;…

配置idea环境进行scala编程

这里用的jdk是jdk-8u161,scala版本是2.12.0 在d盘新建一个本地仓库用来存放下载的maven包&#xff0c;在里面创建如下两个文件 更改settings文件为下面的样子 点击左下角的设置&#xff0c;更改maven本地仓库的位置&#xff08;默认在c盘用户目录下的.m2文件中&#xff0c;更改…

WSL简介与安装流程(Windows 下的 Linux 子系统)

目录 1.wsl安装 1.1 WSL简介 1.1.1 WSL 的主要功能 1.1.2 WSL 的版本 1.1.3 为什么使用 WSL&#xff1f; 1.1.4 WSL 的工作原理 1.1.5 WSL 的常见使用场景 1.1.6 与虚拟机的区别 1.1.7 适合使用 WSL 的人群 1.2 启用 WSL 1.2.1 打开 PowerShell&#xff08;管理员模…

【Java树】二叉树遍历的简单实现

二叉树的遍历 二叉树的遍历是值按照一定顺序访问二叉树中所有结点的过程&#xff0c;确保每个结点被访问且仅被访问一次。遍历操作是对二叉树的基础操作&#xff0c;用于后续的查找、排序和路径计算等功能。 二叉树的遍历有以下几种常见方式&#xff1a;深度遍历&#xff08;…