• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

SpringBoot 3.0全新HTTP客户端工具来了

武飞扬头像
MacroZheng
帮助597

前言

我们平时开发项目的时候,经常会需要远程调用下其他服务提供的接口,于是我们会使用一些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
<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下载地址:www.oracle.com/cn/java/tec…

>
  • 由于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接口,项目地址:github.com/macrozheng/…

    >
  • 先在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时会造成一定的麻烦,如果能独立出来就更好了!

    参考资料

    官方文档:docs.spring.io/spring-fram…

    项目源码地址

    github.com/macrozheng/…

    这篇好文章是转载于:学新通技术网

    • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
    • 本站站名: 学新通技术网
    • 本文地址: /boutique/detail/tanfbffh
    系列文章
    更多 icon
    同类精品
    更多 icon
    继续加载