还在用HttpUtil?SpringBoot 3.0全新HTTP客户端工具来了,用起来够优雅~

news2024/11/26 4:28:46

我们平时开发项目的时候,经常会需要远程调用下其他服务提供的接口,于是我们会使用一些HTTP工具类比如Hutool提供的HttpUtil。前不久SpringBoot 3.0发布了,出了一个Http Interface的新特性,它允许我们使用声明式服务调用的方式来调用远程接口,今天我们就来聊聊它的使用!

SpringBoot实战电商项目mall(50k+star)地址:https://github.com/macrozheng/mall

简介

Http Interface让你可以像定义Java接口那样定义HTTP服务,而且用法和你平时写Controller中方法完全一致。它会为这些HTTP服务接口自动生成代理实现类,底层是基于Webflux的WebClient实现的。

使用声明式服务调用确实够优雅,下面是一段使用Http Interface声明的Http服务代码。

使用

在SpringBoot 3.0中使用Http Interface是非常简单的,下面我们就来体验下。

依赖集成

  • 首先在项目的pom.xml中定义好SpringBoot的版本为3.0.0
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
  • 由于SpringBoot最低要求为Java 17,我们需要先安装好JDK 17,安装完成后配置项目的SDK版本为Java 17,JDK下载地址:https://www.oracle.com/cn/java/technologies/downloads/

  • 由于Http Interface需要依赖webflux来实现,我们还需添加它的依赖。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

基本使用

下面以调用mall-tiny-swagger中的接口为例,我们来体验下Http Interface的基本使用。

  • 首先我们准备一个服务来方便远程调用,使用的是之前的mall-tiny-swagger这个Demo,打开Swagger看下,里面有一个登录接口和需要登录认证的商品品牌CRUD接口,项目地址:https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-swagger

  • 先在application.yml中配置好mall-tiny-swagger的服务地址;
remote:
  baseUrl: http://localhost:8088/
  • 再通过@HttpExchange声明一个Http服务,使用@PostExchange注解表示进行POST请求;
/**
 * @auther macrozheng
 * @description 定义Http接口,用于调用远程的UmsAdmin服务
 * @date 2022/1/19
 * @github https://github.com/macrozheng
 */
@HttpExchange
public interface UmsAdminApi {

    @PostExchange("admin/login")
    CommonResult<LoginInfo> login(@RequestParam("username") String username, @RequestParam("password") String password);
}
  • 再创建一个远程调用品牌服务的接口,参数注解使用我们平时写Controller方法用的那些即可;
/**
 * @auther macrozheng
 * @description 定义Http接口,用于调用远程的PmsBrand服务
 * @date 2022/1/19
 * @github https://github.com/macrozheng
 */
@HttpExchange
public interface PmsBrandApi {
    @GetExchange("brand/list")
    CommonResult<CommonPage<PmsBrand>> list(@RequestParam("pageNum") Integer pageNum, @RequestParam("pageSize") Integer pageSize);

    @GetExchange("brand/{id}")
    CommonResult<PmsBrand> detail(@PathVariable("id") Long id);

    @PostExchange("brand/create")
    CommonResult create(@RequestBody PmsBrand pmsBrand);

    @PostExchange("brand/update/{id}")
    CommonResult update(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrand);

    @GetExchange("brand/delete/{id}")
    CommonResult delete(@PathVariable("id") Long id);
}
  • 为方便后续调用需要登录认证的接口,我创建了TokenHolder这个类,把token存储到了Session中;
/**
 * @auther macrozheng
 * @description 登录token存储(在Session中)
 * @date 2022/1/19
 * @github https://github.com/macrozheng
 */
@Component
public class TokenHolder {
    /**
     * 添加token
     */
    public void putToken(String token) {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
        request.getSession().setAttribute("token", token);
    }

    /**
     * 获取token
     */
    public String getToken() {
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
        Object token = request.getSession().getAttribute("token");
        if(token!=null){
            return (String) token;
        }
        return null;
    }

}
  • 创建Java配置,配置好请求用的客户端WebClient及Http服务对象即可,由于品牌服务需要添加认证头才能正常访问,所以使用了过滤器进行统一添加;
@Configuration
public class HttpInterfaceConfig {

    @Value("${remote.baseUrl}")
    private String baseUrl;
    @Autowired
    private TokenHolder tokenHolder;

    @Bean
    WebClient webClient() {
        return WebClient.builder()
                //添加全局默认请求头
                .defaultHeader("source", "http-interface")
                //给请求添加过滤器,添加自定义的认证头
                .filter((request, next) -> {
                    ClientRequest filtered = ClientRequest.from(request)
                            .header("Authorization", tokenHolder.getToken())
                            .build();
                    return next.exchange(filtered);
                })
                .baseUrl(baseUrl).build();
    }

    @Bean
    UmsAdminApi umsAdminApi(WebClient client) {
        HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
        return factory.createClient(UmsAdminApi.class);
    }

    @Bean
    PmsBrandApi pmsBrandApi(WebClient client) {
        HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build();
        return factory.createClient(PmsBrandApi.class);
    }
}
  • 接下来在Controller中注入Http服务对象,然后进行调用即可;
/**
 * @auther macrozheng
 * @description HttpInterface测试接口
 * @date 2022/1/19
 * @github https://github.com/macrozheng
 */
@RestController
@Api(tags = "HttpInterfaceController")
@Tag(name = "HttpInterfaceController", description = "HttpInterface测试接口")
@RequestMapping("/remote")
public class HttpInterfaceController {

    @Autowired
    private UmsAdminApi umsAdminApi;
    @Autowired
    private PmsBrandApi pmsBrandApi;
    @Autowired
    private TokenHolder tokenHolder;

    @ApiOperation(value = "调用远程登录接口获取token")
    @PostMapping(value = "/admin/login")
    public CommonResult<LoginInfo> login(@RequestParam String username, @RequestParam String password) {
        CommonResult<LoginInfo> result = umsAdminApi.login(username, password);
        LoginInfo loginInfo = result.getData();
        if (result.getData() != null) {
            tokenHolder.putToken(loginInfo.getTokenHead() + " " + loginInfo.getToken());
        }
        return result;
    }

    @ApiOperation("调用远程接口分页查询品牌列表")
    @GetMapping(value = "/brand/list")
    public CommonResult<CommonPage<PmsBrand>> listBrand(@RequestParam(value = "pageNum", defaultValue = "1")
                                                        @ApiParam("页码") Integer pageNum,
                                                        @RequestParam(value = "pageSize", defaultValue = "3")
                                                        @ApiParam("每页数量") Integer pageSize) {
        return pmsBrandApi.list(pageNum, pageSize);
    }

    @ApiOperation("调用远程接口获取指定id的品牌详情")
    @GetMapping(value = "/brand/{id}")
    public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) {
        return pmsBrandApi.detail(id);
    }

    @ApiOperation("调用远程接口添加品牌")
    @PostMapping(value = "/brand/create")
    public CommonResult createBrand(@RequestBody PmsBrand pmsBrand) {
        return pmsBrandApi.create(pmsBrand);
    }

    @ApiOperation("调用远程接口更新指定id品牌信息")
    @PostMapping(value = "/brand/update/{id}")
    public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrand) {
        return pmsBrandApi.update(id,pmsBrand);
    }

    @ApiOperation("调用远程接口删除指定id的品牌")
    @GetMapping(value = "/delete/{id}")
    public CommonResult deleteBrand(@PathVariable("id") Long id) {
        return  pmsBrandApi.delete(id);
    }
}

测试

  • 下面我们通过Postman进行测试,首先调用登录接口获取到远程服务返回的token了;

  • 再调用下需要登录认证的品牌列表接口,发现可以正常访问。

总结

Http Interface让我们只需定义接口,无需定义方法实现就能进行远程HTTP调用,确实非常方便!但是其实现依赖Webflux的WebClient,在我们使用SpringMVC时会造成一定的麻烦,如果能独立出来就更好了!

参考资料

官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html

项目源码地址

https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-http-interface

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

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

相关文章

PreScan快速入门到精通第四十讲目标边界传感器

边界矩形传感器提供了关于传感器可检测物体的边界矩形的信息,并作为对摄像机输入的边界矩形算法的参考。一个例子是行人识别算法,该算法用于检测夜间、雾、雨或雪等恶劣照明条件下的行人。输出的检测到的边界矩形是按距离排序的--最近的在前。 注意:边界矩形传感器不检测(或…

Qt扫盲-QDoubleSpinBox理论总结

QDoubleSpinBox理论总结1. 简述2. 调值与值转换3. 信号4. 修饰&外观1. 简述 QDoubleSpinBox 主要是对于浮点数据的输入进行便捷的封装。QDoubleSpinBox和QSpinBox的使用基本一致&#xff0c;只是有些控制有些不同嘛。比如对于浮点数的小数点精度位数的控制啦。 QDoubleSpi…

第五章. 可视化数据分析图表—常用图表的绘制4—箱形图,3D图表

第五章. 可视化数据分析图 5.3 常用图表的绘制4—箱形图&#xff0c;3D图表 本节主要介绍常用图表的绘制&#xff0c;主要包括箱形图&#xff0c;3D柱形图&#xff0c;3D曲面图。 1.箱形图&#xff08;matplotlib.pyplot.boxplot&#xff09; 箱形图又称箱线图、盒须图或盒式…

你还在为 “动态规划” 发愁吗?看完本秘籍,带你斩杀这类题~

目录 前言 一、动态规划——解题思路 二、动态规划——模板以及题目 2.1、Fibonacci 2.2、字符串分割(Word Break) 2.3、三角矩阵(Triangle&#xff09; 2.4、路径总数(Unique Paths&#xff09; 2.5、最小路径和(Minimum Path Sum) 2.6、背包问题 2.7、回文串分割(Pa…

第08讲:使用脚手架创建vue项目

一、安装NodeJS 二、配置环境变量 2.1、软件安装完成之后配置npm的环境变量 第1步&#xff1a;获取npm安装位置 使用管理员身份打开CMD&#xff0c;用如下命令获取npm的安装位置&#xff1a; npm config list第2步&#xff1a;配置环境变量 将以上获取的路径保存到path变…

flask请求与响应、session执行流程

目录 请求对象 响应对象 session的使用和原理 闪现(flash) 请求扩展 蓝图 请求对象 请求对象request是全局的&#xff0c;需要导入这个全局的request&#xff0c;在哪个视图函数中就是当次的request对象 请求数据&#xff1a; request.method # 获取提交的方法 …

文件包含漏洞简介

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是文件包含漏洞简介。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权设备…

一些好玩的js小作品

今天小编给大家带来了一些很实用的js小作品&#xff0c;下面请一看究竟。 1、计算详细年龄工具js脚本 2、检测是否安装Flash插件及版本号js脚本 3、无法查看源码的页面 4、面积换算js脚本 5、体积和容积换算js脚本 6、长度换算js脚本 7、重量换算js脚本 8、只能输入汉字…

记一些女装数据分析

文章目录服装维度女装生命周期门店维度常见度量值衍生指标服装维度 尺码&#xff1a;XS、S、M、L、XL颜色&#xff1a;黑、红、蓝、白……一级分类&#xff1a;上半身、下半身、全身季节&#xff1a;春、夏、秋、冬价格类型&#xff1a;正价、特价、折扣价、降价、优惠券…价格…

Android自定义ViewGroup布局进阶,完整的九宫格实现

自定义ViewGroup九宫格 前言 在之前的文章我们复习了 ViewGroup 的测量与布局&#xff0c;那么我们这一篇效果就可以在之前的基础上实现一个灵活的九宫格布局。 那么一个九宫格的 ViewGroup 如何定义&#xff0c;我们分解为如下的几个步骤来实现&#xff1a; 先计算与测量九…

【Linux学习】进程信号

文章目录前言一、信号初识1. 信号的概念2. Linux中的普通信号3. 信号的处理二、信号产生1. 终端按键产生信号2. 系统调用发送信号2.1 kill函数2.2 raise函数2.3 abort函数3. 由软件条件产生信号3.1 SIGPIPE信号3.2 alarm函数4. 由硬件异常产生信号三、信号阻塞1. 信号阻塞即其他…

[前端面试题]flex上下布局

[前端面试题]flex上下布局 [万字长文]一文教你彻底搞懂flex布局 [CSS]一些flex的应用场景 页面中有两个元素。元素bottom固定在底部&#xff0c;靠内容来撑开&#xff1b;而元素top在上边&#xff0c;高度自适应&#xff0c;自动铺满除bottom剩下的空间&#xff0c;且top内容…

第十四届蓝桥杯集训——JavaC组第十篇——分支语句

第十四届蓝桥杯集训——JavaC组第十篇——分支语句 目录 第十四届蓝桥杯集训——JavaC组第十篇——分支语句 if单分支 if单分支语法 if单分支语句示例 单分支例题&#xff1a; 连续单分支示例 if简写语法 if双分支语句 if双分支语法 if双分支语法示例 if双分支简写法…

全栈jmeter接口测试教程之Jmeter+ant+jenkins实现持续集成

jmeterantjenkins持续集成 一、下载并配置jmeter 首先下载jmeter工具&#xff0c;并配置好环境变量&#xff1b;参考&#xff1a;https://www.cnblogs.com/YouJeffrey/p/16029894.html jmeter默认保存的是.jtl格式的文件&#xff0c;要设置一下bin/jmeter.properties,文件内容…

圣诞节快来了~用python做一个粒子烟花震撼众人赚个女孩回来吧~

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 准备 准备一下你运行效果的背景图 以及一首你喜欢或那你女朋友喜欢的音乐 效果 代码展示 导入模块 import random import pygame as py import tkinter as tk from time import time, sleep fr…

Fuzzing with Data Dependency Information阅读笔记

相关数据 论文&#xff1a;https://www.s3.eurecom.fr/docs/eurosp22_mantovani.pdf 开源代码&#xff1a;https://github.com/elManto/DDFuzz 论文背景 这篇论文是2022年发表在sp上的一篇论文&#xff0c;也是在afl的基础上进行改进的一篇论文。afl是在afl的基础上进行整合…

第二十六章 linux-输入子系统二

第二十六章 linux-输入子系统二 文章目录第二十六章 linux-输入子系统二框架三个重要结构体struct input_devstruct input_handlerstruct input_handle框架 Linux系统支持的输入设备繁多&#xff0c;例如键盘、鼠标、触摸屏、手柄或者是一些输入设备像体感输入等等&#xff0c…

[附源码]Python计算机毕业设计电子投票系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

30岁转行网络安全来得及吗?有发展空间吗?

30岁转行网络安全来得及吗?有发展空间吗? 现阶段&#xff0c;很多30岁左右的人群都面临就业难的问题&#xff0c;尤其是对于年龄已过30.没有一技之长的人。现阶段&#xff0c;网络安全行业已成了风口行业&#xff0c;也有很多30岁人群也想转行学习网络安全&#xff0c;但又担…

python之界面案例

目录 一、海龟绘图 二、图形化编程入门 窗口创建 三、表格控件的简单认知 四、综合案例 一、海龟绘图 海龟绘图作用&#xff1a;提升界面美观度&#xff0c;吸引用户使用 学习网址&#xff1a; turtle --- 海龟绘图 — Python 3.8.14 文档 二、图形化编程入门 窗口创建 …