OpenFeign 万字教程详解

news2025/2/1 10:08:47

OpenFeign 万字教程详解

目录

  • 一、概述

    • 1.1.OpenFeign是什么?
    • 1.2.OpenFeign能干什么
    • 1.3.OpenFeign和Feign的区别
    • 1.4.@FeignClient
  • 二、OpenFeign使用

    • 2.1.OpenFeign 常规远程调用
    • 2.2.OpenFeign 微服务使用步骤
    • 2.3.OpenFeign 超时控制
    • 2.4.OpenFeign 日志打印
    • 2.5.OpenFeign 添加Header
    • 2.6.手动创建 Feign 客户端
    • 2.7.Feign 继承支持
    • 2.8.Feign 和Cache集成
    • 2.9.OAuth2 支持

一、概述

1.1.OpenFeign是什么?

Feign是一个声明式的Web服务客户端(Web服务客户端就是Http客户端),让编写Web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。

cloud官网介绍Feign: https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/

OpenFeign源码: https://github.com/OpenFeign/feign

1.2.OpenFeign能干什么

Java当中常见的Http客户端有很多,除了Feign,类似的还有Apache 的 HttpClient 以及OKHttp3,还有SpringBoot自带的RestTemplate这些都是Java当中常用的HTTP 请求工具。

什么是Http客户端?

当我们自己的后端项目中 需要 调用别的项目的接口的时候,就需要通过Http客户端来调用。在实际开发当中经常会遇到这种场景,比如微服务之间调用,除了微服务之外,可能有时候会涉及到对接一些第三方接口也需要使用到 Http客户端 来调用 第三方接口。

所有的客户端相比较,Feign更加简单一点,在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定。

1.3.OpenFeign和Feign的区别
Feign:

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency> 
OpenFeign:

OpenFeign是Spring Cloud 在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

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

Feign是在2019就已经不再更新了,通过maven网站就可以看出来,随之取代的是OpenFeign,从名字上就可以知道,他是Feign的升级版。

1.4.@FeignClient

使用OpenFeign就一定会用到这个注解,@FeignClient属性如下:

  • **name:**指定该类的容器名称,类似于@Service(容器名称)
  • url: url一般用于调试,可以手动指定@FeignClient调用的地址
  • *decode404:*当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
  • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
  • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
  • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
  • path: 定义当前FeignClient的统一前缀,当我们项目中配置了server.context-path,server.servlet-path时使用
下面这两种本质上没有什么区别:

他们都是一个作用就是将FeignClient注入到spring容器当中

@FeignClient(name = "feignTestService", url = "http://localhost/8001")
public interface FeignTestService {
}
@Component
@FeignClient(url = "http://localhost/8001")
public interface PaymentFeignService{
}

远程调用接口当中,一般我们称提供接口的服务为提供者,而调用接口的服务为消费者。而OpenFeign一定是用在消费者上。

二、OpenFeign使用

2.1.OpenFeign 常规远程调用

所谓常规远程调用,指的是对接第三方接口,和第三方并不是微服务模块关系,所以肯定不可能通过注册中心来调用服务。

第一步:导入OpenFeign的依赖

第二步:启动类需要添加@EnableFeignClients

第三步:提供者的接口

@RestController
@RequestMapping("/test")
public class FeignTestController {

    @GetMapping("/selectPaymentList")
    public CommonResult<Payment> selectPaymentList(@RequestParam int pageIndex, @RequestParam int pageSize) {
        System.out.println(pageIndex);
        System.out.println(pageSize);
        Payment payment = new Payment();
        payment.setSerial("222222222");
        return new CommonResult(200, "查询成功, 服务端口:" + payment);
    }

    @GetMapping(value = "/selectPaymentListByQuery")
    public CommonResult<Payment> selectPaymentListByQuery(Payment payment) {
        System.out.println(payment);
        return new CommonResult(200, "查询成功, 服务端口:" + null);
    }

    @PostMapping(value = "/create", consumes = "application/json")
    public CommonResult<Payment> create(@RequestBody Payment payment) {
        System.out.println(payment);
        return new CommonResult(200, "查询成功, 服务端口:" + null);
    }

    @GetMapping("/getPaymentById/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") String id) {
        System.out.println(id);
        return new CommonResult(200, "查询成功, 服务端口:" + null);
    }
}

第四步:消费者调用提供者接口

@FeignClient(name = "feignTestService", url = "http://localhost/8001")
public interface FeignTestService {

    @GetMapping(value = "/payment/selectPaymentList")
    CommonResult<Payment> selectPaymentList(@RequestParam int pageIndex, @RequestParam int pageSize);

    @GetMapping(value = "/payment/selectPaymentListByQuery")
    CommonResult<Payment> selectPaymentListByQuery(@SpringQueryMap Payment payment);

    @PostMapping(value = "/payment/create", consumes = "application/json")
    CommonResult<Payment> create(@RequestBody Payment payment);

    @GetMapping("/payment/getPaymentById/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") String id);
}
@SpringQueryMap注解

spring cloud项目使用feign的时候都会发现一个问题,就是get方式无法解析对象参数。其实feign是支持对象传递的,但是得是Map形式,而且不能为空,与spring在机制上不兼容,因此无法使用。spring cloud在2.1.x版本中提供了@SpringQueryMap注解,可以传递对象参数,框架自动解析。

2.2.OpenFeign 微服务使用步骤

微服务之间使用OpenFeign,肯定是要通过注册中心来访问服务的。提供者将自己的ip+端口号注册到注册中心,然后对外提供一个服务名称,消费者根据服务名称去注册中心当中寻找ip和端口。

第一步:导入OpenFeign的依赖

第二步:启动类需要添加@EnableFeignClients

第三步:作为消费者,想要调用提供者需要掌握以下

CLOUD-PAYMENT-SERVICE是提供者的服务名称。消费者要想通过服务名称来调用提供者,那么就一定需要配置注册中心当中的服务发现功能。假如提供者使用的是Eureka,那么消费者就需要配置Eureka的服务发现,假如是consul就需要配置consul的服务发现。

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {

    @GetMapping(value = "/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

第四步:提供者的接口,提供者可以是集群

@RestController
@Slf4j
public class PaymentController {

    @Autowired
    private PaymentMapper paymentMapper;

    @Value("${server.port}")
    private String serverPort;

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
        Payment payment = paymentMapper.selectById(id);
        log.info("*****查询结果:{}", payment);
        if (payment != null) {
            return new CommonResult(200, "查询成功, 服务端口:" + serverPort, payment);
        } else {
            return new CommonResult(444, "没有对应记录,查询ID: " + id + ",服务端口:" + serverPort, null);
        }
    }
}

第五步:然后我们启动注册中心以及两个提供者服务,启动后浏览器我们进行访问

他不仅限于和Eureka注册中心使用,我这里是基于Eureka来进行使用的,需要了解Eureka注册中心的搭建可以看这篇文章:

https://blog.csdn.net/weixin_43888891/article/details/125325794

使用OpenFeign,假如是根据服务名称调用,OpenFeign他本身就集成了ribbon自带负载均衡。

图片

2.3.OpenFeign 超时控制

第一步:提供方接口,制造超时场景

@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeOut() {
    System.out.println("*****paymentFeignTimeOut from port: " + serverPort);
    //暂停几秒钟线程
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return serverPort;
}

第二步:消费方接口调用

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService{
    @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeOut();
}

当消费方调用提供方时候,OpenFeign默认等待1秒钟,超过后报错

图片

第三步:在消费者添加如下配置

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

在openFeign高版本当中,我们可以在默认客户端和命名客户端上配置超时。OpenFeign 使用两个超时参数:

  • connectTimeout:防止由于服务器处理时间长而阻塞调用者。
  • readTimeout:从连接建立时开始应用,在返回响应时间过长时触发。
2.4.OpenFeign 日志打印

Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解 Feign 中 Http 请求的细节。

说白了就是对Feign接口的调用情况进行监控和输出

日志级别:

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;
  • FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。

配置日志Bean:

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

YML文件里需要开启日志的Feign客户端

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.gzl.cn.service.PaymentFeignService: debug

后台日志查看:

图片

2.5.OpenFeign 添加Header

以下提供了四种方式:

  1. 在@RequestMapping中添加,如下:
@FeignClient(name="custorm",fallback=Hysitx.class)
public interface IRemoteCallService {
 @RequestMapping(value="/custorm/getTest",method = RequestMethod.POST,
  headers = {"Content-Type=application/json;charset=UTF-8"})
    List<String> test(@RequestParam("names") String[] names);
}
  1. 在方法参数前面添加@RequestHeader注解,如下:
@FeignClient(name="custorm",fallback=Hysitx.class)
public interface IRemoteCallService {
 @RequestMapping(value="/custorm/getTest",method = RequestMethod.POST,
  headers = {"Content-Type=application/json;charset=UTF-8"})
    List<String> test(@RequestParam("names")@RequestHeader("Authorization") String[] names);
}

设置多个属性时,可以使用Map,如下:

@FeignClient(name="custorm",fallback=Hysitx.class)
public interface IRemoteCallService {
 @RequestMapping(value="/custorm/getTest",method = RequestMethod.POST,
  headers = {"Content-Type=application/json;charset=UTF-8"})
    List<String> test(@RequestParam("names") String[] names, @RequestHeader MultiValueMap<String, String> headers);
}
  1. 使用@Header注解,如下:
@FeignClient(name="custorm",fallback=Hysitx.class)
public interface IRemoteCallService {
 @RequestMapping(value="/custorm/getTest",method = RequestMethod.POST)
 @Headers({"Content-Type: application/json;charset=UTF-8"})
    List<String> test(@RequestParam("names") String[] names);
}
  1. 实现RequestInterceptor接口(拦截器),如下:

只要通过FeignClient访问的接口都会走这个地方,所以使用的时候要注意一下。

@Configuration
public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate temp) {
        temp.header(HttpHeaders.AUTHORIZATION, "XXXXX");
    }
}
2.6.手动创建 Feign 客户端

@FeignClient无法支持同一service具有多种不同配置的FeignClient,因此,在必要时需要手动build FeignClient。

@FeignClient(value = “CLOUD-PAYMENT-SERVICE”)

以这个为例,假如出现两个服务名称为CLOUD-PAYMENT-SERVICE的FeignClient,项目直接会启动报错,但是有时候我们服务之间调用的地方较多,不可能将所有调用都放到一个FeignClient下,这时候就需要自定义来解决这个问题!

官网当中也明确提供了自定义FeignClient,以下是在官网基础上对自定义FeignClient的一个简单封装,供参考!

首先创建FeignClientConfigurer类,这个类相当于build FeignClient的工具类

import feign.*;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.slf4j.Slf4jLogger;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Import;

@Import(FeignClientsConfiguration.class)
public class FeignClientConfigurer {

    private Decoder decoder;
    private Encoder encoder;
    private Client client;
    private Contract contract;

    public FeignClientConfigurer(Decoder decoder, Encoder encoder, Client client, Contract contract) {
        this.decoder = decoder;
        this.encoder = encoder;
        this.client = client;
        this.contract = contract;
    }

    public RequestInterceptor getUserFeignClientInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                // 添加header
            }
        };
    }

    public <T> T buildAuthorizedUserFeignClient(Class<T> clazz, String serviceName) {
        return getBasicBuilder().requestInterceptor(getUserFeignClientInterceptor())
                //默认是Logger.NoOpLogger
                .logger(new Slf4jLogger(clazz))
                //默认是Logger.Level.NONE(一旦手动创建FeignClient,全局配置的logger就不管用了,需要在这指定)
                .logLevel(Logger.Level.FULL)
                .target(clazz, buildServiceUrl(serviceName));
    }

    private String buildServiceUrl(String serviceName) {
        return "http://" + serviceName;
    }

    protected Feign.Builder getBasicBuilder() {
        return Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract);
    }
}

使用工具类的方法创建多个FeignClient配置

import com.gzl.cn.service.FeignTest1Service;
import feign.Client;
import feign.Contract;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignClientConfiguration extends FeignClientConfigurer {
    public FeignClientConfiguration(Decoder decoder, Encoder encoder, Client client, Contract contract) {
        super(decoder, encoder, client, contract);
    }

    @Bean
    public FeignTest1Service feignTest1Service() {
        return super.buildAuthorizedUserFeignClient(FeignTest1Service.class, "CLOUD-PAYMENT-SERVICE");
    }

    // 假如多个FeignClient在这里定义即可
}

其中,super.buildAuthorizedUserFeignClient()方法中,第一个参数为调用别的服务的接口类,第二个参数为被调用服务在注册中心的service-id。

public interface FeignTest1Service {

    @GetMapping(value = "/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

使用的时候正常注入使用即可

@Resource
private FeignTest1Service feignTest1Service;
2.7.Feign 继承支持

Feign 通过单继承接口支持样板 API。这允许将常用操作分组到方便的基本接口中。

UserService.java

public interface UserService {
    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
    User getUser(@PathVariable("id") long id);
}

UserResource.java

@RestController
public class UserResource implements UserService {
}

UserClient.java

package project.user;

@FeignClient("users")
public interface UserClient extends UserService {

}
2.8.Feign 和Cache集成

如果@EnableCaching使用注解,CachingCapability则创建并注册一个 bean,以便您的 Feign 客户端识别@Cache*其接口上的注解:

public interface DemoClient {
    @GetMapping("/demo/{filterParam}")
    @Cacheable(cacheNames = "demo-cache", key = "#keyParam")
    String demoEndpoint(String keyParam, @PathVariable String filterParam);
}

您还可以通过 property 禁用该功能feign.cache.enabled=false

注意feign.cache.enabled=false只有在高版本才有

2.9.OAuth2 支持

可以通过设置以下标志来启用 OAuth2 支持:

feign.oauth2.enabled=true

当标志设置为 true 并且存在 oauth2 客户端上下文资源详细信息时,将OAuth2FeignRequestInterceptor创建一个类 bean。在每个请求之前,拦截器解析所需的访问令牌并将其作为标头包含在内。有时,当为 Feign 客户端启用负载平衡时,您可能也希望使用负载平衡来获取访问令牌。

为此,您应该确保负载均衡器位于类路径 (spring-cloud-starter-loadbalancer) 上,并通过设置以下标志显式启用 OAuth2FeignRequestInterceptor 的负载均衡:

feign.oauth2.load-balanced=true

ring keyParam, @PathVariable String filterParam);
}


您还可以通过 property 禁用该功能feign.cache.enabled=false

> ❝
>
> 注意feign.cache.enabled=false只有在高版本才有
>
> ❞

#### 2.9.OAuth2 支持

可以通过设置以下标志来启用 OAuth2 支持:

feign.oauth2.enabled=true


当标志设置为 true 并且存在 oauth2 客户端上下文资源详细信息时,将OAuth2FeignRequestInterceptor创建一个类 bean。在每个请求之前,拦截器解析所需的访问令牌并将其作为标头包含在内。有时,当为 Feign 客户端启用负载平衡时,您可能也希望使用负载平衡来获取访问令牌。

为此,您应该确保负载均衡器位于类路径 (spring-cloud-starter-loadbalancer) 上,并通过设置以下标志显式启用 OAuth2FeignRequestInterceptor 的负载均衡:

feign.oauth2.load-balanced=true


注意feign.cache.enabled=false只有在高版本才有

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

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

相关文章

垃圾回收器和内存分配

垃圾回收器和内存分配策略 概述 垃圾回收&#xff08;Garbage Collection&#xff09;简称GC&#xff0c;早在Lisp还在胚胎时期时&#xff0c;其作者John McCarthy就思考过垃圾回收需要完成的三件事情&#xff1a; 哪些内存需要回收 什么时候回收 如何回收 今天的内存动态…

PHP下载安装以及基本配置

目录 引言 官网 下载 配置 1. 鼠标右键“此电脑”>“属性” 2. 打开高级系统设置 3. 打开环境变量 4. 双击系统变量中的path 5. 新建新的path 6. 将刚刚安装的位置加入环境变量 7. 检查是否安装成功 引言 PHP&#xff08;"PHP: Hypertext Preprocessor"…

OCC:第一个程序,对话框中显示一个BOX

1. OCC库的获取 从github上获取 gitgithub.com:tpaviot/oce.git&#xff0c;自己编译官网获取二进制包&#xff08;获取下来的只有release 版本的&#xff0c;而且VS版本不一定适合自己&#xff09;官网源码&#xff0c;然后自己编译&#xff08;稍微折腾点&#xff0c;建议按…

【Java】IO流相关操作

目录 常见的文件操作 创建文件 得到文件信息 目录操作 IO流 FileInputStream FileOutputStream FileReader FileWriter BufferedReader BufferedWriter ObjectOutputStream ObjectInputStream InputStreamReader OutputStreamReader PrintStream PrintWriter Properties prope…

【JAVA面试题】基本类型的强制类型转换是否会丢失精度?引用类型的强制类型转换需要注意什么?

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 思路 1、继承关系 2、运行时类型检查 结语 我的其他博客 前言 在Java编程中&#xff0c;强制类型转换是一个常见的操作&#xf…

鸿蒙应用开发ArkTS容器组件的使用

线性布局——Column/Row 线性布局是应用中最常用的布局&#xff0c;通过线性容器 Row 和 Column 构建 线性布局是其他布局的基础&#xff0c;其子元素在水平方向和垂直方向依次排列 线性布局的排列方向由所选容器组件决定&#xff0c;Column 容器内子元素按照垂直方向排列&a…

CSS-计数器 counter-reset、counter-increment、counter-reset

计数器 CSS的计数器通过在 content 上应用 counter() 或 counters()函数来显示计数的。其中计数器是由counter-reset和counter-increment 来进行操作的。 counter-increment 语法 counter-increment参数1&#xff1a;计算器名称 该标识符由不区分大小写的字母 a 到 z&#xf…

服务熔断(Hystrix)

服务雪崩 多个微服务之间调用的时候&#xff0c;假设微服务A调用微服务B和微服务C&#xff0c;微服务B和微服务C又调用其他的微服务&#xff0c;这就是所谓的“扇出”&#xff0c;如果扇出的链路上某个微服务的调用响应时间过长&#xff0c;或者不可用&#xff0c;对微服务A的…

智能优化算法应用:基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.骑手优化算法4.实验参数设定5.算法结果6.…

Open3D 入门教程

文章目录 1、概述2、安装3、点云读写4、点云可视化 4.1、可视化单个点云4.2、同一窗口可视化多个点云4.3、 可视化的属性设置 5、k-d tree 与 Octree 5.1、k-d tree5.2、Octree 5.2.1、从点云中构建Octree5.2.2、从体素栅格中构建 Octree 6、点云滤波 6.1、体素下采样6.2、统计…

java.lang.IllegalStateException: Duplicate key

序言 最近监控扫描出我们项目的某些异常信息&#xff0c;报错java.lang.IllegalStateException: Duplicate key xxx&#xff0c;看到异常来自stream流&#xff0c;然后定位看了一下是某位同事的代码使用stream流把List转Map集合出现重复的key异常信息。List集合A对象来源于某个…

Python命名规范中的[单/双][前导/后缀]下划线小结

如图所示 出处 Single and Double Underscores in Python Names

「C/C++ 01」 深拷贝和浅拷贝

目录 一、概念 1. 浅拷贝 2. 深拷贝 3. 深浅拷贝问题 4. 总结 二、在C的类中实现深拷贝 1. 拷贝构造函数 中实现深拷贝 a. 自己开辟一个新空间&#xff0c;然后将内容拷贝到新空间 b. 借助构造函数来实现深拷贝 2. operator 中实现深拷贝 a. 自己开辟一个新空间&#xff0c;…

JAVA版的鸿鹄云商B2B2C:多商家入驻直播商城系统特性解析 商城免 费搭建

鸿鹄云商 b2b2c产品概述 【b2b2c平台】&#xff0c;以传统电商行业为基石&#xff0c;鸿鹄云商支持“商家入驻平台自营”多运营模式&#xff0c;积极打造“全新市场&#xff0c;全新 模式”企业级b2b2c电商平台&#xff0c;致力干助力各行/互联网创业腾飞并获取更多的收益。从消…

pyqt5实现wget下载视频文件的进度条显示

简介&#xff1a; 最近在写一个项目&#xff0c;用到了wget下载视频&#xff0c;为了更好的视觉效果&#xff0c;所以使用pyqt5中QProgressBar来实现下载进度条。当视频开始下载就会弹出下载进度条&#xff0c;下载完成后进度条消失。效果如下图; 具体代码实现 &#xff1a; …

Sobit:将BRC20资产桥接到Solana ,加速铭文市场的火热

2023 年 1 月份后&#xff0c;比特币 Ordinals 协议出现后为铭文赛道的出现奠定了基础&#xff0c;它以聪为单位将比特币分成份&#xff0c;并在每一聪上攥刻不同的信息以达到非同质化资产的效果&#xff0c;而此后包括 BRC20 在内的诸多采用了 Ordinals 方案的应用不断面向市场…

生成式AI大模型对人类进化的影响

你是不是发现每天的工作都离不开ChatGPT之类的语言生成模型&#xff1f;离不开类似Midjourney的图像生成模型&#xff1f;离不开一些设计类的AI辅助工具&#xff1f;如果是&#xff0c;那说明你已经逐步被AI侵蚀了&#xff0c;你的创造力也正在逐渐下降&#xff0c;大模型正在剥…

使用通道和模式

通过通道、选择语句和最佳实践掌握 Go 中的并发编程 并发编程是构建高效和响应迅速的软件的强大范例。Go&#xff0c;也被称为 Golang&#xff0c;通过通道提供了一种健壮且优雅的解决方案来进行并发通信。在这篇文章中&#xff0c;我们将探讨通道的概念、它们在并发编程中的作…

Qt配置opencv,cmake编译参考笔记,已成功

Qt版本&#xff1a;Qt5.14.2 opencv&#xff1a;4.5.4&#xff08;不要用4.5.5&#xff01;&#xff01;很坑别问我为什么知道&#xff09; cmake&#xff1a;下的最新版本 前言&#xff1a;为什么非得要用cmake编译呢&#xff1f;跳过cmake不好吗&#xff1f; 之前用的opencv…

pickle反序列化

文章目录 基础知识pickle简介可序列化对象object.__reduce__() 函数 pickle过程详细解读opcode简介pickletools 漏洞利用利用思路如何手写opcode 工具pker实战例题[MTCTF 2022]easypickle[HZNUCTF 2023 preliminary]pickle 基础知识 pickle简介 与PHP类似&#xff0c;python也…