httpfetch-一款java語言編寫優雅的http接口調用組件

讓http請求的調用更優雅php

概述

當咱們提到java調用http請求時,咱們想到的是HttpClient或是內置的HttpUrlConnention。 而後會寫下以下一串的代碼訪問http接口:java

HttpClient client = new HttpClient();
        client.getHostConfiguration().setProxy("127.0.0.1", 8888);
        client.getHostConfiguration().setHost("bl.ocks.org", 80, "http");
        GetMethod getMethod = new GetMethod("/mbostock/raw/4090846/us-congress-113.json");
        client.executeMethod(getMethod);
        //打印服務器返回的狀態
        System.out.println(getMethod.getStatusLine().getStatusCode());
        if(getMethod.getStatusLine().getStatusCode() == 200){
            //打印結果頁面
            String response = new String(getMethod.getResponseBodyAsString().getBytes("8859_1"));

            //打印返回的信息
            System.out.println(response);
        }
        getMethod.releaseConnection();

複製代碼

但是咱們是否是有一種更優雅的方式呢?相似於MyBatis,經過必定的配置,而後在須要請求http接口的時候只須要調用一個接口函數即可以完成上述代碼的工做。git

這就是HttpFetch的初衷,讓http請求的調用更優雅。github

下載

git clone https://github.com/youzan/httpfetch.git
複製代碼

QuickStart

https://github.com/youzan/httpfetch/wiki/QuickStartspring

對象

  • ParameterResolver:api參數解析類,自帶的能夠對數組、bean、簡單類型等參數進行解析並封裝成Get、Post、Form等類型請求的參數。也能夠經過Url註解靈活定義api接口的請求地址。
  • Convertor:返回數據封裝類,自帶的僅支持簡單類型和JSON類型的數據進行封裝。經過擴展能夠實現更多的轉換方式。
  • Chain: 責任鏈模式,一層層對請求進行加工和處理。裏面比較重要的是ParameterResolverChain、GenerateResponseChain和ExecuteRequestChain。ParameterResolverChain負責對參數進行處理,GenerateResponseChain負責對返回結果進行處理,ExecuteRequestChain負責最後的請求發送。
  • ResourceReader: 配置信息讀取類,負責對各組件單元的讀取並最終傳給HttpApiConfiguration類。
  • HttpApiConfiguration: 負責對ResourceReader讀取後的配置信息進行封裝,而後將配置信息傳給HttpApiService類。
  • HttpApiService: 負責最後的代理類生成和緩存;

框架

  • 初始化過程json

    初始化過程能夠選擇spring和xml兩種。spring的方式直接將生成的代理類註冊到BeanDefinitionRegistry(可見HttpApiClassPathBeanDefinitionScanner源碼),xml方式能夠在沒有spring組件的狀況下獨立運行(見單測MbostockApiUseXmlTest)。兩種方式均可以完成Chain、ParamterResolver和Convertor註冊。 api

    初始化過程

  • 請求處理流程 請求者發起請求時,會經過配置的各個Chain單元,一步一步的處理和封裝參數併發送最終的Http請求,最後將返回的值進行封裝。 數組

    請求處理流程

使用

Maven

<dependency>
    <groupId>com.github.youzan</groupId>
    <artifactId>http-fetch</artifactId>
    <version>1.1.6</version>
</dependency>
複製代碼

非spring調用

1.建立http-api.xml配置文件:緩存

<?xml version="1.0" encoding="UTF-8"?>
<setting>

    <!-- 請求處理鏈 -->
    <chains>
    </chains>

    <!-- 參數處理類 -->
    <argumentResolvers>
    </argumentResolvers>

    <!-- 結果處理類 -->
    <resultConvertors>
    </resultConvertors>

    <!-- api和url映射關係 -->
    <aliases>
        <alias key="mbostockApi.getUsCongress" value="https://bl.ocks.org/mbostock/raw/4090846/us-congress-113.json" />
    </aliases>

</setting>
複製代碼

2.編寫MbostockApi接口類:bash

package com.github.nezha.httpfetch.mbostock.api;

import com.github.nezha.httpfetch.HttpApi;
import com.github.nezha.httpfetch.Header;
import com.github.nezha.httpfetch.mbostock.vo.UsCongressResponseVo;

/** * Created by daiqiang on 17/3/14. */
public interface MbostockApi {

    @HttpApi(timeout = 1000, headers = {@Header(key="user-agent", value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")})
    UsCongressResponseVo getUsCongress();

}
複製代碼

3.編寫測試類:

SourceReader xmlReader = new XmlReader(Arrays.asList("httpapi.xml"));

        HttpApiConfiguration configuration = new HttpApiConfiguration();
        configuration.setSourceReaders(Arrays.asList(xmlReader));
        configuration.init();

        HttpApiService service = new HttpApiService(configuration);
        service.init();

        MbostockApi mbostockApi = service.getOrCreateService(MbostockApi.class);

        UsCongressResponseVo responseVo = mbostockApi.getUsCongress();
        System.out.println("type=="+responseVo.getType());
        System.out.println("arcs->size=="+responseVo.getArcs().size());
        System.out.println("objects->districts->bbox->size=="+responseVo.getObjects().getDistricts().getBbox().size());
        System.out.println("objects->districts->type=="+responseVo.getObjects().getDistricts().getType());
        System.out.println("objects->districts->geometries->size=="+responseVo.getObjects().getDistricts().getGeometries().size());
        System.out.println("transform->scale=="+responseVo.getTransform().getScale());
        System.out.println("transform->translate=="+responseVo.getTransform().getTranslate());
複製代碼

以上就是非spring方式的調用

spring方式的調用

1.建立application-httpapi.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ">

	<bean id="springReader" class="com.github.nezha.httpfetch.spring.SpringReader" >
	    <!-- 請求處理鏈 -->
		<property name="chains" >
			<list>
				<bean class="com.github.nezha.httpfetch.bookworm.chains.BookWormTokenChain" />
			</list>
		</property>
		<!-- 參數處理類 -->
		<property name="parameterResolvers">
			<list>
			</list>
		</property>
		<!-- 結果處理類 -->
		<property name="convertors">
			<list>
			</list>
		</property>
		<!-- api和url映射關係 -->
		<property name="urlAlias">
			<map>
				<entry key="mbostockApi.getUsCongress" value="${mock.host}/mbostock/raw/4090846/us-congress-113.json" />
			</map>
		</property>
	</bean>

	<bean id="httpApiConfiguration" class="com.github.nezha.httpfetch.HttpApiConfiguration" init-method="init">
		<property name="sourceReaders">
			<list>
				<ref bean="springReader" />
			</list>
		</property>
	</bean>

	<bean id="httpApiService" class="com.github.nezha.httpfetch.HttpApiService" init-method="init">
		<constructor-arg index="0" ref="httpApiConfiguration" />
	</bean>

    <!-- http api代理註冊 -->
	<bean class="com.github.nezha.httpfetch.spring.HttpApiScannerConfigurer">
		<property name="basePackage" value="com.github.nezha.httpfetch.bookworm.api,com.github.nezha.httpfetch.mbostock.api,com.github.nezha.httpfetch.youzan.api" />
	</bean>

</beans>
複製代碼

2.編寫MbostockApi接口類:

package com.github.nezha.httpfetch.mbostock.api;

import com.github.nezha.httpfetch.HttpApi;
import com.github.nezha.httpfetch.Header;
import com.github.nezha.httpfetch.mbostock.vo.UsCongressResponseVo;

/** * Created by daiqiang on 17/3/14. */
public interface MbostockApi {

    @HttpApi(timeout = 1000, headers = {@Header(key="user-agent", value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")})
    UsCongressResponseVo getUsCongress();

}
複製代碼

3.編寫測試類:

public class MbostockApiTest extends BaseTest {

    @Autowired
    private MbostockApi mbostockApi;

    @Test
    public void test(){
        UsCongressResponseVo responseVo = mbostockApi.getUsCongress();
        System.out.println("type=="+responseVo.getType());
        System.out.println("arcs->size=="+responseVo.getArcs().size());
        System.out.println("objects->districts->bbox->size=="+responseVo.getObjects().getDistricts().getBbox().size());
        System.out.println("objects->districts->type=="+responseVo.getObjects().getDistricts().getType());
        System.out.println("objects->districts->geometries->size=="+responseVo.getObjects().getDistricts().getGeometries().size());
        System.out.println("transform->scale=="+responseVo.getTransform().getScale());
        System.out.println("transform->translate=="+responseVo.getTransform().getTranslate());
    }

}
複製代碼

URL映射

url的映射使用了三種方式:

1.使用xml進行配置:

<aliases>
        <alias key="mbostockApi.getUsCongress" value="https://bl.ocks.org/mbostock/raw/4090846/us-congress-113.json" />
    </aliases>
複製代碼

2.使用註解方式:

package com.github.nezha.httpfetch.bookworm.api;

import com.github.nezha.httpfetch.Header;
import com.github.nezha.httpfetch.HttpApi;
import com.github.nezha.httpfetch.resolver.RequestBody;

import java.util.Map;

/** * Created by daiqiang on 17/6/16. */
public interface AlarmJobApi {

    @HttpApi(method = "POST", headers = @Header(url = "http://alert.s.qima-inc.com/api/v1/alert", key = "Content-type", value = "application/json"), timeout = 2000)
    String alert(@RequestBody Map<String, Object> param);

}
複製代碼

3.使用參數方式傳入:

@HttpApi(timeout = 1000, headers = {@Header(key="user-agent", value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")})
    UsCongressResponseVo getUsCongress(@URL String url);
複製代碼

測試類:

public void test_url_param(){
        String url = "https://bl.ocks.org/mbostock/raw/4090846/us-congress-113.json";
        UsCongressResponseVo responseVo = mbostockApi.getUsCongress(url);
        System.out.println("type=="+responseVo.getType());
        System.out.println("arcs->size=="+responseVo.getArcs().size());
        System.out.println("objects->districts->bbox->size=="+responseVo.getObjects().getDistricts().getBbox().size());
        System.out.println("objects->districts->type=="+responseVo.getObjects().getDistricts().getType());
        System.out.println("objects->districts->geometries->size=="+responseVo.getObjects().getDistricts().getGeometries().size());
        System.out.println("transform->scale=="+responseVo.getTransform().getScale());
        System.out.println("transform->translate=="+responseVo.getTransform().getTranslate());
    }
複製代碼

參數封裝

1.Get請求參數: 使用QueryParam註解標記,並填寫參數的名稱

@HttpApi(timeout = 2000, url = "http://bookworm365.com/uploadImage")
    @BookWormApi
    UploadFileResponseVo uploadFile(@QueryParam("name") String name, @QueryParam("n_value") String nValue);
複製代碼

2.Post請求參數: 使用PostParam註解標記,並填寫參數的名稱

Map audit(@PostParam("advertisementId") Integer advertisementId);
複製代碼

3.Form請求參數: 使用FormParam註解標記,並填寫參數的名稱

@HttpApi(timeout = 2000, url = "http://bookworm365.com/uploadImage")
    @BookWormApi
    UploadFileResponseVo uploadFile(@FormParam("file") File file, @QueryParam("name") String name, @QueryParam("n_value") String nValue);
複製代碼

4.BeanParam註解使用: 當咱們傳遞一個bean作爲參數,可是但願對這個bean進行解析而後做爲http請求參數時,咱們可使用BeanParam註解。

@HttpApi(timeout = 2000, url = "http://bookworm365.com/uploadImage")
    @BookWormApi
    UploadFileResponseVo uploadFile(@BeanParam @QueryParam UploadFileRequestVo requestVo);
複製代碼
package com.github.nezha.httpfetch.bookworm.vo;

import com.alibaba.fastjson.annotation.JSONField;
import java.io.File;

public class UploadFileRequestVo {
    @JSONField(name = "file")
    private File file;
    private String name;
    @JSONField(name="n_value")
    private String nValue;
    public File getFile() {return file;}
    public void setFile(File file) {this.file = file;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getnValue() {return nValue;}
    public void setnValue(String nValue) {this.nValue = nValue;}
}
複製代碼

http的請求最終爲:http://bookworm365.com/uploadImage?file=XXX&name=XXX&n_value=XXX

5.RequestBody註解使用: 當你須要傳遞消息體給服務器是,能夠經過該註解。 例如咱們想要傳遞一個application\json的請求:

@HttpApi(method = "POST",timeout = 2000,headers = {@Header(key = "Content-type", value = "application/json;charset=UTF-8")})
    @WechatApi
    WechatBaseResponseVo<AddCustomAudiencesResponseVo> add(@RequestBody AddCustomAudiencesRequestVo requestVo);
複製代碼

結果封裝

結果封裝默認支持簡單類型和JSON兩種: 1.簡單類型,若是返回值是String、int、long等,api的返回對象能夠直接指定對應類:

@HttpApi(timeout = 2000, url = "http://bookworm365.com/checkHeader")
    @BookWormApi
    String checkHeader();
複製代碼

2.JSON,若是返回值是一個json字符串,能夠直接編寫對應的bean做爲返回類,內部使用fastjson進行反序列化:

@HttpApi(timeout = 1000, headers = {@Header(key="user-agent", value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")})
    UsCongressResponseVo getUsCongress();
複製代碼
package com.github.nezha.httpfetch.mbostock.vo;

import com.alibaba.fastjson.annotation.JSONField;
import java.util.List;

public class UsCongressResponseVo {
    @JSONField(name="type")
    private String type;
    @JSONField(name="objects")
    private ObjectsVo objects;
    @JSONField(name="arcs")
    private List<List<List<Integer>>> arcs;
    @JSONField(name="transform")
    private TransformVo transform;
    public String getType() {return type;}
    public void setType(String type) {this.type = type;}
    public ObjectsVo getObjects() {return objects;}
    public void setObjects(ObjectsVo objects) {this.objects = objects;}
    public List<List<List<Integer>>> getArcs() {return arcs;}
    public void setArcs(List<List<List<Integer>>> arcs) {this.arcs = arcs;}
    public TransformVo getTransform() {return transform;}
    public void setTransform(TransformVo transform) {this.transform = transform;}
}
複製代碼
package com.github.nezha.httpfetch.mbostock.vo;

import com.alibaba.fastjson.annotation.JSONField;
import com.github.nezha.httpfetch.BaseTest;

public class ObjectsVo {
    @JSONField(name="districts")
    private DistrictsVo districts;
    public DistrictsVo getDistricts() {return districts;}
    public void setDistricts(DistrictsVo districts) {this.districts = districts;}
}
複製代碼

另外返回的類還支持泛型。

@HttpApi(timeout = 1000, headers = {@Header(key="user-agent", value = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")})
    UsCongressResponseVo<TransformVo> getUsCongress();
複製代碼

重試策略

須要升級到1.2.0以後纔可使用。
HttpApi註解中增長了retry和retryPolicy兩個變量:
retry:重試次數;
retryPolicy:重試策略,默認爲ConnectFailureRetryPolicy,超時和鏈接異常會進行重試;

自定義重試策略

類圖:

類圖

全部的重試策略須要繼承RetryPolicy接口,並實現needRetry函數。

/** * 重試校驗接口 */  
public interface RetryPolicy {  
  
    /** * * @param result http請求結果 * @param retryTimes 重試次數 * @param remainRetryTimes 剩餘重試次數 * @return */  
    boolean needRetry(HttpResult result, int retryTimes, int remainRetryTimes);  
  
}  
複製代碼

ConnectFailureRetryPolicy:

public class ConnectFailureRetryPolicy implements RetryPolicy {  
  
    private static final Logger LOGGER = LoggerFactory.getLogger(ConnectFailureRetryPolicy.class);  
  
    /** * 若是是網絡異常則重試 * @param result http請求結果 * @param retryTimes 重試次數 * @param remainRetryTimes 剩餘重試次數 * @return */  
    @Override  
    public boolean needRetry(HttpResult result, int retryTimes, int remainRetryTimes) {  
        Exception e = result.getException();  
        if(e instanceof SocketTimeoutException || e instanceof ConnectException){  
            LOGGER.info("超時重試: {}, 重試次數: {} 剩餘次數: {}", e, retryTimes, remainRetryTimes);  
            return true;  
        }  
        return false;  
    }  
  
}  
複製代碼

實現完本身的重試策略後,只須要在HttpApi註解中設置retryPolicy的值就能夠了。

更多示例能夠在項目的test目錄中查看

開源協議

本項目基於 MIT協議,請自由地享受和參與開源。

貢獻

若是你有好的意見或建議,歡迎給咱們提 [issue] 或 [PR],爲優化 [http-fetch] 貢獻力量

相關文章
相關標籤/搜索