【openfeign】OpenFeign的使用、GET请求和POST请求

RPC全称是Remote Procedure Call,即远程过程调用,其对应的是我们的本地调用。

RPC的目的是:让我们调用远程方法像调用本地方法一样。

//本地调用
R result = orderService.findOrderByUserId(id);
//RPC远程调用  orderService为代理对象
R result = orderService.findOrderByUserId(id);

RPC框架设计架构:

那么微服务之间如何方便优雅的实现服务间的远程调用?

什么是Feign

Feign是Netflix开发的声明式、模板化的HTTP客户端,Feign可帮助我们更加便捷、优雅地调用HTTP API。

Feign可以做到使用HTTP请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP请求。它像Dubbo一样,consumer直接调用接口方法调用provider,而不需要通过常规的Http Client构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

Spring Cloud openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便。

Feign的设计架构:

Spring Cloud Alibaba快速整合Feign

引入依赖

<!-- openfeign 远程调用 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

编写调用接口+@FeignClient注解

package com.morris.user.client;import com.morris.user.entity.Order;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.util.List;@FeignClient(value = "order-service", path = "/order")
public interface OrderClient {@GetMapping("findOrderByUserId")List<Order> findOrderByUserId(@RequestParam("userId") Long userId);}

调用端在启动类上添加@EnableFeignClients注解

package com.morris.user;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients // 开启OpenFeign
@SpringBootApplication
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}}

发起调用,像调用本地方式一样调用远程服务

package com.morris.user.controller;import com.morris.user.client.OrderClient;
import com.morris.user.entity.Order;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.List;@RestController
@RequestMapping("user3")
public class OpenFeignController {@Resourceprivate OrderClient orderClient;@GetMapping("findOrderByUserId1")public List<Order> findOrderByUserId1(Long userId) {return orderClient.findOrderByUserId(userId);}}

Feign的继承特性可以让服务的接口定义单独抽出来,作为公共的依赖,以方便使用。

GET请求

没有参数

没有参数就很简单,只需要使用@GetMapping标识好请求路径就可以了。

@GetMapping("getOrder")
Order getOrder();

多个基础类型参数

Get请求多个参数时,需要使用@RequestParam或者@PathVariable注解,这是因为在加载方法元数据的时候,如果该形参没有注解,默认会直接将其放在请求体中,这样GET请求时就会报错。

而且注解中的value属性必须指定绑定的参数名,不然会报错RequestParam.value() was empty on parameter 0

@GetMapping("findOrderByUserId")
List<Order> findOrderByUserId(@RequestParam("userId") Long userId);@GetMapping("findOrderByUserId/{userId}")
List<Order> findOrderByUserId2(@PathVariable("userId") Long userId);

集合数据参数

使用GET请求传递集合参数时,需要这么写:

    @GetMapping("getOrders")List<Order> getOrders(@RequestParam("idList") List<Long> idList);

在请求时,URL集合值使用逗号隔开:

http://localhost:8030/user3/getOrders=1,2

在使用Feign调用时,可以从日志看到,Feign自动将集合类型的参数进行了解析拼接。

2023-08-14 16:07:23.283 DEBUG 20288 --- [nio-8030-exec-6] com.morris.user.client.OrderClient       : [OrderClient#getOrders] ---> GET http://order-service/order/getOrders?idList=1&idList=2 HTTP/1.1

单个对象参数

当Get请求参数超过三个时,就需要进行查询参数封装为对象。

上面说到当参数没有注解时,就会放入到请求体中,但是@RequestParam不支持直接传递对象类,这时就需要使用@SpringQueryMap注解,它可以将对象属性及值,转为键值对拼接在URL后面。

@GetMapping("checkOrder")
Order checkOrder(@SpringQueryMap Order order);

从日志中可以看出对象被转为键值对拼接在URL后面:

2023-08-14 16:10:05.108 DEBUG 20288 --- [nio-8030-exec-9] com.morris.user.client.OrderClient       : [OrderClient#checkOrder] ---> GET http://order-service/order/checkOrder?goodName=Iphone%2013&price=9999&id=1&userId=1 HTTP/1.1

多个对象参数(不支持)

多个对象参数时,只需要使用多个@SpringQueryMap即可:

@GetMapping("getOrderUser")
Order getOrderUser(@SpringQueryMap Order order, @SpringQueryMap User user);

从日志中可以看出第二个对象不会被转为键值对拼接在URL后面:

2023-08-14 16:21:09.061 DEBUG 24776 --- [nio-8030-exec-3] com.morris.user.client.OrderClient       : [OrderClient#getOrderUser] ---> GET http://order-service/order/getOrderUser?goodName=Iphone%2013&price=9999&id=1&userId=1 HTTP/1.1

一个对象+基础类型参数

需要注意实体类中的属性和这个基础类型参数名不能相同,不然拼接到URL中,两个同名参数传递过去就会覆盖了。

@GetMapping("getOrderName")
Order getOrderName(@SpringQueryMap Order order, @RequestParam("name") String name);

下载文件

下载文件需要注意的是,应该返回二进制数据,还有GET请求时,需要对URL进行编码,不然会报错编码不符合规范,其他没什么区别。

@GetMapping("/download")
byte[] download(@RequestParam("filePath") String filePath);

POST请求

POST请求也支持将参数放在URL上,使用方式与GET请求类似。

传递单个对象参数

服务消费者的参数不需要增加任何注解,就会放入到请求体中,这个时候会使用编码器,将对象编码,并以Content-Type: application/json形式发送请求。

@PostMapping("saveOrder")
Long saveOrder(Order order);

所以只要注意在服务提供者中,添加@RequestBody注解,将请求体转为对象即可。

传递多个对象参数(不支持)

如果像下面这样使用两个@RequestBody,消费者启动时是会报错的:

@PostMapping("saveOrderAndUser")
Long saveOrderAndUser(Order order, User user);

报错日志如下:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.morris.user.client.OrderClient': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Method has too many Body parameters: public abstract java.lang.Long com.morris.user.client.OrderClient.saveOrderAndUser(com.morris.user.entity.Order,com.morris.user.entity.User)
Warnings:

这时候需要将两个对象封装在一个对象中,变成单个对象进行请求传递。

上传文件

上传文件时,需要注意的是需要使用@RequestPart注解,Fiegn会解析这个注解,标记为上传文件请求,还需要指定consumes为MULTIPART_FORM_DATA_VALUE,编码器会根据这个配置,将文件对象进行编码。

@PostMapping(value = "upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String upload(@RequestPart("file") MultipartFile file);

在调用方,上传文件时,则需要将文件对象转为MultipartFile。

@GetMapping("upload")
public String upload() throws URISyntaxException {File file = new File(OpenFeignController.class.getResource("/application.yml").toURI());MultipartFile multipartFile =fileToMultipartFile(file);return orderClient.upload(multipartFile);
}private MultipartFile fileToMultipartFile(File file) {String fieldName = "file";FileItemFactory factory = new DiskFileItemFactory(16, null);FileItem item = factory.createItem(fieldName, "multipart/form-data", true, file.getName());int bytesRead = 0;byte[] buffer = new byte[8192];try {FileInputStream fis = new FileInputStream(file);OutputStream os = item.getOutputStream();while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {os.write(buffer, 0, bytesRead);}os.close();fis.close();} catch (IOException e) {e.printStackTrace();}return new CommonsMultipartFile(item);
}

一般不采用Feign去上传文件,这种方式请求链路比较长,性能很低,一般都是前端直接上传到文件服务器,然后再告诉后台上传了哪个文件。

header中加参数

有时候接口验签的场景header中需要追加一些参数,可以通过@RequestHeader注解实现。

@GetMapping("header1")
String header1(@RequestHeader(name = "authorization")String authorization);

如果是固定参数,可以通过@Headers指定:

@PostMapping("header2")
@Headers({"Content-Type:application/json","Authorization:{authorization}"})
String header2(@RequestHeader(name = "authorization")String authorization, User user);

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高效使用ChatGPT之ChatGPT客户端

ChatGPT客户端&#xff0c;支持Mac, Windows, and Linux 下载地址见文章结尾 软件截图 Windows: Mac&#xff1a; 说明 chatgpt桌面版&#xff0c;相比于网页版的chatgpt&#xff0c;最大的特色是支持历史聊天对话记录导出&#xff0c;且支持三种格式&#xff1a;PNG、PDF、…

Ae 效果:CC Line Sweep

过渡/CC Line Sweep Transition/CC Line Sweep CC Line Sweep&#xff08;CC 线条扫描&#xff09;通过线条的扫描动作来制作一个过渡效果&#xff0c;线条可以根据设定的方向、厚度、倾斜度和方向翻转来扫过画面&#xff0c;从而将一个场景过渡到另一个。 ◆ ◆ ◆ 效果属性…

如何关闭“若要接收后续google chrome更新,您需使用windows10或更高版本”

Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\Policies\Google\Chrome] "SuppressUnsupportedOSWarning"dword:00000001 如何关闭“若要接收后续 google chrome 更新,您需使用 windows 10 或更高版本” - 知乎

数学建模及数据分析 || 4. 深度学习应用案例分享

PyTorch 深度学习全连接网络分类 文章目录 PyTorch 深度学习全连接网络分类1. 非线性二分类2. 泰坦尼克号数据分类2.1 数据的准备工作2.2 全连接网络的搭建2.3 结果的可视化 1. 非线性二分类 import sklearn.datasets #数据集 import numpy as np import matplotlib.pyplot as…

YOLOX在启智AI GPU/CPU平台部署笔记

文章目录 1. 概述2. 部署2.1 拉取YOLOX源码2.2 拉取模型文件yolox_s.pth2.3 安装依赖包2.4 安装yolox2.5 测试运行2.6 运行报错处理2.6.1 ImportError: libGL.so.1: cannot open shared object file: No such file or directory2.6.2 ImportError: libgthread-2.0.so.0: cannot…

2、Spring_DI

DI 1.概述 概述&#xff1a;Dependency Injection 依赖注入&#xff0c;给对象设置属性&#xff0c;曾经我们需要自己去创建 mapper 对象&#xff0c;才能调用&#xff0c;现在交给 spring 创建&#xff0c;并且使用 DI 注入&#xff0c;直接拿来用&#xff0c;程序员就可以更…

[语音识别] 基于Python构建简易的音频录制与语音识别应用

语音识别技术的快速发展为实现更多智能化应用提供了无限可能。本文旨在介绍一个基于Python实现的简易音频录制与语音识别应用。文章简要介绍相关技术的应用&#xff0c;重点放在音频录制方面&#xff0c;而语音识别则关注于调用相关的语音识别库。本文将首先概述一些音频基础概…

Midjourney API 申请及使用

Midjourney API 申请及使用 在人工智能绘图领域&#xff0c;想必大家听说过 Midjourney 的大名吧&#xff01; Midjourney 以其出色的绘图能力在业界独树一帜。无需过多复杂的操作&#xff0c;只要简单输入绘图指令&#xff0c;这个神奇的工具就能在瞬间为我们呈现出对应的图…

多种编程语言运行速度排名-10亿次除7求余数为0的数量

最佳方式是运行10次&#xff0c;取平均数&#xff0c;用时秒数显示3位小数。 因为第一次打开&#xff0c;可能CPU还没优化好&#xff0c;多次取平均&#xff0c;比较准确 第1次共10次&#xff0c;用时3秒&#xff0c;平均3秒 第2次共10次&#xff0c;用时4秒&#xff0c;平均3.…

框架(Git基础详解及Git在idea中集成步骤)

目录 基础&#xff1a; idea集成Git并添加项目到git仓库 1.idea集成git&#xff0c;集成.git.exe文件 2.初始化本地Git仓库项目 3. 将工作区代码添加到暂存区 4.将暂存区代码添加到本地仓库 5.Git本地库操作 Idea集成Gitee并提交代码到第三方库 1.setting里搜索gitee 2.添…

分布式ID

分布式ID 背景Snowflake(雪花算法)uid-generatorleaf背景 分布式系统,用什么做为主键呢? uuid 太长(MySQL官方有明确的建议主键要尽量越短越好[4],36个字符长度的UUID不符合要求。)、 无规律(在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能。…

Redis Lua脚本执行原理和语法示例

Redis Lua脚本语法示例 文章目录 Redis Lua脚本语法示例0. 前言参考资料 1. Redis 执行Lua脚本原理1.1. 对Redis源码中嵌入Lua解释器的简要解析&#xff1a;1.2. Redis Lua 脚本缓存机制 2. Redis Lua脚本示例1.1. 场景示例1. 请求限流2. 原子性地从一个list移动元素到另一个li…

三维重建 PyQt Python MRP 四视图(横断面,冠状面,矢状面,3D)

本文实现了 Python MPR 的 四视图&#xff0c;横断面&#xff0c;冠状面&#xff0c;矢状面&#xff0c;3D MPR(multi-planner reformation)也称多平面重建&#xff0c;多重面重建是将扫描范围内所有的轴位图像叠加起来再对某些标线标定的重组线所指定的组织进行冠状、矢状位、…

Mac下Jmeter安装及基本使用

本篇文章只是简单的介绍下Jmeter的下载安装和最基本使用 1、初识Jmeter 前一段时间客户端app自测的过程中&#xff0c;有偶现请求某个接口返回数据为空的问题&#xff0c;领导让我循环100次请求这个接口&#xff0c;看看有没有结果为空的问题。听同事说有Jmeter的专业测试工具…

HCIP的交换机(STP,VRRP)实验

实验要求&#xff1a; 拓扑图&#xff1a; 链路聚合 LSW1 [lsw3]interface Eth-Trunk 1 [lsw3-Eth-Trunk1]trunkport GigabitEthernet 0/0/3 0/0/4 [lsw3-Eth-Trunk1]q [lsw3]vlan batch 1 2 [lsw3]interface Eth-Trunk 1 [lsw3-Eth-Trunk1]port link-type trunk [lsw3-Eth-…

C++并发及互斥保护示例

最近要写一个多线程的并发数据库&#xff0c;主要是希望使用读写锁实现库的并发访问&#xff0c;同时考虑到其他平台(如Iar)没有C的读写锁&#xff0c;需要操作系统提供&#xff0c;就将读写锁封装起来。整个过程还是比较曲折的&#xff0c;碰到了不少问题&#xff0c;在此就简…

计算机网络————IP数据报的首部各字段详解(很重要)

目录 1. IP数据报的介绍2. 首部的固定部分的各字段说明2.1 Version&#xff08;版本&#xff09;2.2 IHL&#xff08;首部长度&#xff09;2.3 Type of service&#xff08;区分服务&#xff09;2.4 Total Length&#xff08;总长度&#xff09;2.5 Identification&#xff08;…

http学习笔记3

第 11 章 Web 的攻击技术 11.1 针对 Web 的攻击技术 简单的 HTTP 协议本身并不存在安全性问题&#xff0c;因此协议本身几乎不会成为攻击的对象。应用 HTTP 协议的服务器和客户端&#xff0c;以及运行在服务器上的 Web 应用等资源才是攻击目标。目前&#xff0c;来自互联网的攻…

Python爬虫——scrapy_多条管道下载

定义管道类&#xff08;在pipelines.py里定义&#xff09; import urllib.requestclass DangDangDownloadPipelines:def process_item(self, item, spider):url http: item.get(src)filename ../books_img/ item.get(name) .jpgurllib.request.urlretrieve(url, filename…

js 小程序限流函数 return闭包函数执行不了

问题&#xff1a; 调用限流 &#xff0c;没走闭包的函数&#xff1a; checkBalanceReq&#xff08;&#xff09; loadsh.js // 限流 const throttle (fn, context, interval) > {console.log(">>>>cmm throttle", context, interval)let canRun…