原生Feign進行HTTP調用


使用原生的Feign適用於SpringMVC項目。在配置上花費了時間,並且踩了一些坑,感覺還是不太值得。願世間沒有這么多的配置。

通過7個步驟配置完成

一、添加依賴

 <!--feign的客戶端-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>9.7.0</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
            <version>9.7.0</version>
        </dependency>
        <!--因為使用的是jackson 序列化,所以引入此包-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-jackson</artifactId>
            <version>9.7.0</version>
        </dependency>
        <!--客戶端使用的okhttp所以引入此包-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
            <version>11.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.48.sec06</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>22.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

二、Feign的配置http

/**
 * @author chris wang
 * @date 2021年04月23日 9:17
 * @description Feign http配置
 */
@Configuration
public class FeignClientConfiguration {

    @Autowired
    private Contract environmentFeignContract;

    @Bean
    public Feign feign() {
        return Feign.builder() //創建feign的構建者
                .encoder(new JacksonEncoder())  //JSON編碼
                .decoder(new MyDecoder()) //JSON解碼
                .options(new Request.Options(1000, 3500))  //設置超時
                .retryer(new Retryer.Default(5000, 5000, 2)).contract(environmentFeignContract).
                        build();  //設置重試
    }
}
 
/**
 * @author chris wang
 * @date 2021年04月23日 9:16
 * @description 自定義解析ApiClient注解的占位符 $viptoken
 */
public abstract class AbstractFeignContract extends Contract.Default {

    @Override
    protected void processAnnotationOnClass(MethodMetadata data, Class<?> targetType) {
        super.processAnnotationOnClass(data, targetType);
        handleHeaders(data);
    }

    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, Annotation annotation, Method method) {
        super.processAnnotationOnMethod(data, annotation, method);
        handleHeaders(data);
    }

    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
        return super.processAnnotationsOnParameter(data, annotations, paramIndex);
    }

    private void handleHeaders(MethodMetadata data) {
        if (data == null || CollectionUtils.isEmpty(data.template().headers())) return;
        for (Map.Entry<String, Collection<String>> entry : data.template().headers().entrySet()) {
            if (StringUtils.isEmpty(entry.getKey())) continue;
            Collection<String> values = entry.getValue();
            if (CollectionUtils.isEmpty(values)) continue;
            Collection<String> result = Lists.newArrayList();
            Collection<String> exludes = Lists.newArrayList();
            for (String val : values) {
                exludes.add(val);
                if (val.startsWith(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_PREFIX) && val.endsWith(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_SUFFIX)) {
                    String placeholder = val.substring(val.indexOf(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_PREFIX) + 2, val.indexOf(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_SUFFIX));
                    val = findProperty(placeholder);
                }
                result.add(val);
            }
            values.removeAll(exludes);
            values.addAll(result);
        }
    }

    public abstract String findProperty(String key);
}
/**
 * @author chris wang
 * @date 2021年04月27日 12:55
 * @description properties獲取
 */
@Configuration
public class EnvironmentFeignContract extends AbstractFeignContract {

    @Autowired
    private Environment environment;

    @Override
    public String findProperty(String key) {
        return environment.getProperty(key);
    }
}

/**
 * @author chris wang
 * @date 2021年04月23日 9:17
 * @description 定義解碼規則
 */
public class MyDecoder extends JacksonDecoder {

    @Override
    public Object decode(Response response, Type type) throws IOException {
        //包裝一個IocResponse<T>
        Type wapperType = ParameterizedTypeImpl.make(MyResponse.class, new Type[]{
                type
        }, null);
        Object decodeObj = super.decode(response, wapperType);
        if (decodeObj != null && decodeObj instanceof MyResponse) {
            MyResponse iocResponse = (MyResponse) decodeObj;
            if (!iocResponse.isSuccess()) throw new RuntimeException(iocResponse.getMessage());
            return iocResponse.getData();
        }
        throw new RuntimeException(JSON.toJSONString(decodeObj));
    }
}

三、定義一個ApiClient

/**
 * @author chris wang
 * @date 2021年04月23日 9:16
 * @description api接口client
 */
public interface ApiClient {

    @Headers({"Content-Type: application/json", "Accept: application/json", "viptoken: ${viptoken}"})
    @RequestLine("POST /my/api/system_metric/continuous_build")
    List<ContinuousBuildResp> getContinuousBuild(ContinuousBuildReq req);
}

四、定義一個Client工廠

/**
 * @author chris wang
 * @date 2021年04月23日 9:16
 * @description 定義一個Client工廠
 */
@Configuration
public class FeignClientApiFactory {

    @Value("${myUrl}")
    private String myUrl;

    @Autowired
    private Feign feign;

    @Bean
    public ApiClient getMyApi() {
        return feign.newInstance(new Target.HardCodedTarget<>(ApiClient.class, myUrl));
    }
}

五、泛型Response

/**
 * @author chris wang
 * @date 2021年04月27日 9:28
 * @description 使用泛型的一個返回
 */
public class MyResponse<T> {

    private String message;
    private boolean success;
    private T data;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

六、其他類

/**
 * @author chris wang
 * @date 2021年04月27日 9:28
 * @description
 */
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ContinuousBuildResp {

    private int ci_num;
    private int ci_score;
    private int ci_success_num;
    private String ci_success_rate;
    private String rank;
}
/**
 * @author chris wang
 * @date 2021年04月27日 9:28
 * @description
 */
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ContinuousBuildReq {

    private String date_type;
    private String start_time;
    private String end_time;
}

七、application.properties

myUrl=http://localhost:8090
viptoken=xxxxxxxxx

參考引用:

使用原生的Feign進行HTTP調用
如何通過HTTP優雅調用第三方-Feign
教你如何在SpringMVC項目中單獨使用Feign組件(含源碼分析)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM