Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >还在用HttpUtil?SpringBoot 3全新HTTP客户端工具来了,用起来够优雅!

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

作者头像
macrozheng
发布于 2024-01-23 11:07:39
发布于 2024-01-23 11:07:39
2.4K00
代码可运行
举报
文章被收录于专栏:mall学习教程mall学习教程
运行总次数:0
代码可运行

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

简介

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

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

使用

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

依赖集成

  • 首先在项目的pom.xml中定义好SpringBoot的版本为3.0.0
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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来实现,我们还需添加它的依赖。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

这或许是一个对你有用的开源项目,mall项目是一套基于 SpringBoot + Vue + uni-app 实现的电商系统(Github标星60K),采用Docker容器化部署,后端支持多模块和微服务架构。包括前台商城项目和后台管理系统,能支持完整的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员、支付等功能!

  • Boot项目:https://github.com/macrozheng/mall
  • Cloud项目:https://github.com/macrozheng/mall-swarm
  • 视频教程:https://www.macrozheng.com/video/

项目演示:

基本使用

下面以调用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的服务地址;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
remote:
  baseUrl: http://localhost:8088/
  • 再通过@HttpExchange声明一个Http服务,使用@PostExchange注解表示进行POST请求;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 定义Http接口,用于调用远程的UmsAdmin服务
 * Created by macro on 2022/1/19.
 */
@HttpExchange
public interface UmsAdminApi {

    @PostExchange("admin/login")
    CommonResult<LoginInfo> login(@RequestParam("username") String username, @RequestParam("password") String password);
}
  • 再创建一个远程调用品牌服务的接口,参数注解使用我们平时写Controller方法用的那些即可;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 定义Http接口,用于调用远程的PmsBrand服务
 * Created by macro on 2022/1/19.
 */
@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中;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 登录token存储(在Session中)
 * Created by macro on 2022/1/19.
 */
@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服务对象即可,由于品牌服务需要添加认证头才能正常访问,所以使用了过滤器进行统一添加;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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服务对象,然后进行调用即可;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * HttpInterface测试接口
 * Created by macro on 2022/1/19.
 */
@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/reference/integration/rest-clients.html

项目源码地址

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 macrozheng 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
还在用HttpUtil?SpringBoot 3.0全新HTTP客户端工具来了,用起来够优雅!
Http Interface让你可以像定义Java接口那样定义HTTP服务,而且用法和你平时写Controller中方法完全一致。它会为这些HTTP服务接口自动生成代理实现类,底层是基于Webflux的WebClient实现的。
macrozheng
2022/12/14
3.5K0
还在用HttpUtil?SpringBoot 3.0全新HTTP客户端工具来了,用起来够优雅!
还在用HttpUtil?试试这款优雅的HTTP客户端工具吧,跟SpringBoot绝配!
Retrofit是适用于Android和Java且类型安全的HTTP客户端工具,在Github上已经有39k+Star。其最大的特性的是支持通过接口的方式发起HTTP请求,类似于我们用Feign调用微服务接口的那种方式。
macrozheng
2022/02/23
1.7K0
还在用HttpUtil?试试这款优雅的HTTP客户端工具吧,跟SpringBoot绝配!
还在用 RedisTemplate?试试 Redis 官方 ORM 框架吧,用起来够优雅!
RedisOM是Redis官方推出的ORM框架,是对Spring Data Redis的扩展。由于Redis目前已经支持原生JSON对象的存储,之前使用RedisTemplate直接用字符串来存储JOSN对象的方式明显不够优雅。通过RedisOM我们不仅能够以对象的形式来操作Redis中的数据,而且可以实现搜索功能!
macrozheng
2022/04/12
5900
还在用 RedisTemplate?试试 Redis 官方 ORM 框架吧,用起来够优雅!
别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!
JUnit是一款Java语言的单元测试框架,目前大多数Java开发环境都已经支持它了。JUnit测试也就是所谓的白盒测试,在程序员知道程序内部逻辑的基础上进行的测试,使用JUnit能让我们快速地完成单元测试。Spring Boot Test将JUnit和其他测试框架结合起来,提供了便捷高效的测试手段,目前Spring Boot 2.7版本采用的是JUnit 5。
macrozheng
2022/12/14
1.5K0
别再用main方法测试了,太Low!这才是专业的SpringBoot项目测试方法!
神器 SpringDoc 横空出世!最适合 SpringBoot 的API文档工具来了!
SpringDoc是一款可以结合SpringBoot使用的API文档生成工具,基于OpenAPI 3,目前在Github上已有1.7K+Star,更新发版还是挺勤快的,是一款更好用的Swagger库!值得一提的是SpringDoc不仅支持Spring WebMvc项目,还可以支持Spring WebFlux项目,甚至Spring Rest和Spring Native项目,总之非常强大,下面是一张SpringDoc的架构图。
macrozheng
2022/04/12
6.5K0
神器 SpringDoc 横空出世!最适合 SpringBoot 的API文档工具来了!
mall整合SpringBoot+MyBatis搭建基本骨架
https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-01
macrozheng
2019/07/22
7220
mall整合SpringBoot+MyBatis搭建基本骨架
mall整合Redis实现缓存功能
https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-03
macrozheng
2019/07/22
7880
mall整合Redis实现缓存功能
还在用Swagger?试试这款零注解侵入的API文档生成工具,跟Postman绝配!
在我们使用Swagger的时候,经常会需要用到它的注解,比如@Api、@ApiOperation这些,Swagger通过它们来生成API文档。比如下面的代码:
macrozheng
2021/11/10
1.1K0
还在用Swagger?试试这款零注解侵入的API文档生成工具,跟Postman绝配!
SpringBoot中处理校验逻辑的两种方式,真的很机智!
这种方式的优点是可以使用注解来实现参数校验,不需要一些重复的校验逻辑,但是也有一些缺点,比如需要在Controller的方法中额外注入一个BindingResult对象,只支持一些简单的校验,涉及到要查询数据库的校验就无法满足了。
macrozheng
2020/03/13
1.3K0
别再用过时的方式了!全新版本Spring Security,这样用才够优雅!
首先修改项目的pom.xml文件,把Spring Boot版本升级至2.7.0版本。
macrozheng
2022/05/31
7.1K0
别再用过时的方式了!全新版本Spring Security,这样用才够优雅!
Spring Data Redis 最佳实践!
使用该注解的方法当缓存存在时,会从缓存中获取数据而不执行方法,当缓存不存在时,会执行方法并把返回结果存入缓存中。一般使用在查询方法上,可以设置如下属性:
macrozheng
2020/03/26
1.6K0
mall整合Swagger-UI实现在线API文档
接口地址:http://localhost:8080/swagger-ui.html
macrozheng
2019/07/22
1.2K0
mall整合Swagger-UI实现在线API文档
微服务应用性能如何?APM监控工具来告诉你!
Elastic APM是基于Elastic Stack构建的应用性能监控(APM)系统。它主要有如下用途:
macrozheng
2020/10/09
1.5K0
微服务应用性能如何?APM监控工具来告诉你!
肝了一周总结的SpringBoot常用注解大全,看完就炉火纯青了!
这里整理了一张SpringBoot常用注解的思维导图,本文主要讲解这些注解的用法。
macrozheng
2022/12/16
1.2K0
肝了一周总结的SpringBoot常用注解大全,看完就炉火纯青了!
给Swagger换了个新皮肤,瞬间高大上了!
knife4j是springfox-swagger的增强UI实现,为Java开发者在使用Swagger的时候,提供了简洁、强大的接口文档体验。knife4j完全遵循了springfox-swagger中的使用方式,并在此基础上做了增强功能,如果你用过Swagger,你就可以无缝切换到knife4j。
macrozheng
2020/07/21
1.5K0
再见前端!纯Java撸个管理系统,这框架用起来贼香!
Erupt是一个低代码全栈类框架,它使用Java 注解动态生成页面以及增、删、改、查、权限控制等后台功能。零前端代码、零CURD、自动建表,仅需一个类文件 + 简洁的注解配置,快速开发企业级后台管理系统。
macrozheng
2024/02/27
5560
再见前端!纯Java撸个管理系统,这框架用起来贼香!
mall-tiny:基于SpringBoot+MyBatis的单应用项目骨架
本项目启动需要依赖MySql、Elasticsearch、Redis、MongoDb、RabbitMq等服务,安装依赖服务请参考mall在Windows环境下的部署,数据库中需要导入mall_tiny.sql脚本。
macrozheng
2019/08/13
1.4K0
mall-tiny:基于SpringBoot+MyBatis的单应用项目骨架
全文检索工具:第一章:Spring-data-elasticSearch搜索
@Document(indexName = "search11", type = "article",shards = 1,replicas = 0)
Java廖志伟
2022/09/28
4270
全文检索工具:第一章:Spring-data-elasticSearch搜索
mall整合SpringSecurity和JWT实现认证和授权(二)
Swagger api地址:http://localhost:8080/swagger-ui.html
macrozheng
2019/07/22
1K0
mall整合SpringSecurity和JWT实现认证和授权(二)
加速 SpringBoot 应用开发,官方热部署神器真带劲!
SpringBoot官方开发工具,如果你的应用集成了它,即可实现热部署和远程调试。
macrozheng
2021/04/16
9430
加速 SpringBoot 应用开发,官方热部署神器真带劲!
推荐阅读
相关推荐
还在用HttpUtil?SpringBoot 3.0全新HTTP客户端工具来了,用起来够优雅!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档