Java如何优雅地调用发送HTTP请求,支持上传和下载文件(GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS/TRACE)

9 篇文章 0 订阅
6 篇文章 0 订阅

HTTP接口调用框架

项目地址:https://github.com/dadiyang/http-api-invoker

让http调用跟本地方法调用一样自然优雅

将http请求url和接口绑定,由框架生成接口的代理类,直接调用接口的方法就会自动构建请求参数并发送请求,然后处理请求响应转换为接口方法的返回值返回(支持泛型)。

若与 Spring 集成(可选),更能使用 @Autowired 进行自动注入接口的代理实现。

项目特色

  1. 像 MyBatis 一样,只写接口,由框架提供实现
  2. 轻量级,不要求依赖Spring,只使用少量注解
  3. 若使用 Spring ,则可以使用 Autowired 自动注入接口的实现
  4. 完善的文档用例和单元测试

原理

技术:动态代理 + 反射 + 注解 + 自动包扫描

  • 使用@HttpReq 注解 使接口方法与http服务地址绑定
  • 使用 动态代理,生成绑定了http请求的接口的代理实现类
  • 通过 反射 获取方法参数和返回值信息,根据这些信息处理请求
  • 利用 包扫描,注入所有HttpApi注解标注的接口到Spring容器中

当调用接口的方法的时候框架会完成以下三个步骤

  1. 将方法参数根据规则序列化为所需的请求参数,并且填充路径参数(如果有的话)
  2. 发送请求(使用Jsoup发送)
  3. 将请求响应序列化为方法的返回值(使用fastJson反序列化)

核心注解

@HttpApiScan

启动包扫描,类似@ComponentScan。

  • value属性设定扫包的 basePackage,如果没有设置则使用被标注的类所在的包为基包
  • configPaths属性指定配置文件

@HttpApi

标注一个类是与Http接口绑定的,需要被包扫描的接口。类似Spring中的@Component注解

@HttpReq

标注方法对应的url

@Param

指定方法参数名对应的请求参数名称

@Headers

指定方法参数为 Headers,目前只允许打在类型为 Map<String, String> 的参数上,否则会抛出 IllegalArgumentException

@Cookies

指定方法参数为 Cookies,目前只允许打在类型为 Map<String, String> 的参数上,否则会抛出 IllegalArgumentException

使用

一、添加maven依赖

 <dependency>
    <groupId>com.github.dadiyang</groupId>
    <artifactId>http-api-invoker</artifactId>
    <version>1.1.9</version>
 </dependency>

二、定义接口

将请求url与接口方法绑定(支持路径参数,例如 {cityName}; 保留路径参数到请求体,例如 #{id}; 配置项,例如 ${api.url.city})

注:路径参数占位符 {} 和配置项占位符 ${}, 参数被匹配为路径参数时会被移除,若不想移除可以使用 #{}

示例:完整实例 请查看CityServiceTest

@HttpApi(prefix="${api.url.city}/city")
public interface CityService {
    /**
     * 使用URI,会自动添加prefix指定的前缀
     */
    @HttpReq("/allCities")
    List<City> getAllCities();
    /**
    * 使用Param注解指定方法参数对应的请求参数名称
    */
    @HttpReq("/getById")
    City getCity(@Param("id") int id);
    /**
    * 默认使用GET方法,可以通过method指定请求方式
    * 如果是集合类或数组的参数数据会直接当成请求体直接发送
    */
    @HttpReq(value = "/save", method = "POST")
    boolean saveCities(List<City> cities);
    /**
    * 使用完整的路径,不会添加前缀
    */
    @HttpReq(value = "http://localhost:8080/city/saveCity", method = "POST")
    boolean saveCity(@Param("id") String id, @Param("name") String name, @Param("wubaId") int wubaId);
    /**
     * 支持路径参数
     */
    @HttpReq("/getCityRest/{id}")
    City getCityRest(@Param("id") int id);
    /**
     * 可以通过返回 byte[]或 InputStream 来下载资源
     * @return 调用接口返回的字节数组
     */
    @HttpReq("/picture/landscape.png")
    byte[] download();
    /**
     * 上传输入流
     * @param fileName 文件名
     * @param in 输入流
     */
    @HttpReq(value="/picture/upload", method = "POST")
    void upload(@Param("fileName") String fileName,
                     @Param(value = "media", isBody = true) InputStream in);
    /**
     * 上传文件
     * @param file 文件
     */
    @HttpReq(value="/picture/upload", method = "POST")
    void upload(@Param(value = "media", isBody = true) File file);
    /**
     * 带正确请求头的方法
     */
    @HttpReq("/getCityRest/{id}")
    City getCityWithHeaders(@Param("id") int id, @Headers Map<String, String> headers);
    /**
     * 带cookie的方法
     */
    @HttpReq("/getCityRest/{id}")
    City getCityWithCookies(@Param("id") int id, @Cookies Map<String, String> cookies);
}

三、获取代理类

你唯一需要做的就是定义上面的接口,然后在使用的时候就可以通过工厂类获取接口的代理实现类了。

如果你使用Spring,那简单地配置一下就可以使用@Autowired注解直接注入你的接口实现了

工厂方法示例:

使用 HttpApiProxyFactory.getProxy(接口.class) 获取接口代理类

Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("conf.properties"));
// properties 是可选的,若不提供则默认使用 System.getProperties() 提供的配置
CityService service = new HttpApiProxyFactory(properties).getProxy(CityService.class);

Spring 集成

配置

像@ComponentScan注解一样,在有 @Configuration 注解的类上加上 @HttpApiScan 注解开启服务接口扫描

注: configPaths是可选的,用于填充url中使用的配置占位符,如 ${api.url} 对应 api.url 配置项,这些配置项会自动从Spring的Environment中获取,如果有需要,也可以通过指定 configPaths 加载特定的配置文件。

@Configuration
// 启动服务接口扫描,configPaths是可选的,用于填充url中使用的配置项
@HttpApiScan(configPaths = "classpath:conf.properties")
public class TestApplication {
}
使用 @Autowired 注入

因为是动态代理生成并注册到Spring容器中的,所以IDE可能会警告 “Could not autowired. no beans of type ‘xxx’ type found.” 忽略即可。

@Autowired
private CityService cityService;

四、使用示例

可查看项目单元测试类 CityServiceTest

Spring集成使用

@Autowired
private CityService cityService;

public void test() {
    List<City> cities = cityService.getAllCities();
    for (City city : cities) {
        System.out.println(city);
    }
}

工厂方式使用

public void getProxyTest() throws Exception {
     CityService service = new HttpApiProxyFactory().getProxy(CityService.class);
     List<City> cities = service.getAllCities();
     for (City city : cities) {
         System.out.println(city);
     }
}

项目地址: https://github.com/dadiyang/http-api-invoker

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值