springboot单独使用feign调用远程http接口
·
项目开发中,我们有时会有调用远程接口的需求。一般,我们会用到Appache的HttpClient,这个方式会有很多代码量,并且每个人的写的HttpClientUtil可能都不一样,这样很不利于代码的同一,也很不优雅。
下面介绍一种优雅的方式来实现远程http接口调用。
feign-client
首先我们基于springboot,pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wandou</groupId>
<artifactId>spring-boot-feign</artifactId>
<version>1.0.0</version>
<name>spring-boot-feign</name>
<description>Demo project for Spring Boot Use Feign</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- 虽然是springboot项目,但是用到了springcloud的组件,统一管理springcloud版本,openfeign就不需要指定版本了-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
feign接口代码如下:
package com.wandou.springbootfeign.feign;
import com.wandou.springbootfeign.config.FeignConfig;
import com.wandou.springbootfeign.dto.BaiduParamDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author liming
* @date 2020/11/16
* @description
*/
@FeignClient(name = "baidu", url = "http://baidu.com/", configuration = FeignConfig.class, primary = false)
public interface BaiduFeign {
@RequestMapping("/s")
String search(@RequestParam("wd") String wd);
@RequestMapping(path = "/s", method = RequestMethod.GET)
String searchV2(@SpringQueryMap BaiduParamDTO param);
}
启动类需要加 @EnableFeignClients ,然后启动测试即可。
我写的测试用例:
package com.wandou.springbootfeign;
import com.wandou.springbootfeign.feign.BaiduFeign;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringBootFeignApplicationTests {
@Autowired
private BaiduFeign baiduFeign;
@Test
void contextLoads() {
}
@Test
public void testFeign() {
String result = baiduFeign.search("如何写出一手好字");
System.out.println("result = " + result);
}
}
测试结果:
result = <!DOCTYPE html>
<!--STATUS OK-->
//中间很多空白
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<meta content="always" name="referrer">
<meta name="theme-color" content="#2932e1">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="icon" sizes="any" mask href="//www.baidu.com/img/baidu_85beaf5496f291521eb75ba38eacbd87.svg">
<link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" />
<title>如何写出一手好字_百度搜索</title>
<style data-for="result" type="text/css" id="css_newi_result">body{color:#333;background:#fff;padding:6px 0 0;margin:0;position:relative}
body,th,td,.p1,.p2{font-family:arial}
p,form,ol,ul,li,dl,dt,dd,h3{margin:0;padding:0;list-style:none}
input{padding-top:0;padding-bottom:0;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
table,img{border:0}
td{font-size:9pt;line-height:18px}
em{font-style:normal}
.......... 省略 ..........
由此可见我们已经请求通百度,并返回了数据。
集成项目可能出现的问题及解决方向
1. springboot和springcloud版本不匹配
解决方案:spring官网,有介绍各版本的支持与匹配
https://spring.io/projects/spring-cloud#learn
https://docs.spring.io/spring-cloud/docs/Hoxton.SR9/reference/html/
2. Maven Jar包间有版本冲突(在开发中常见)
因为我们工作中的项目都会比较复杂,引入很多相关依赖,不会像我这个示例程序这么简单,所以Maven Jar间容易产生版本号冲突,引起一些莫名的问题。
解决方案:看我前面的文章
《IDEA解决maven包冲突》
3. 方法上使用 @RequestMapping 报错
报错如下:
Caused by: java.lang.IllegalStateException: Method BaiduFeign#search(String) not annotated with HTTP method type (ex. GET, POST)
Warnings:
- Class BaiduFeign has annotations [FeignClient] that are not used by contract Default
- Method search has an annotation RequestMapping that is not used by contract Default
at feign.Util.checkState(Util.java:129)
at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:100)
at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:62)
at feign.DeclarativeContract.parseAndValidateMetadata(DeclarativeContract.java:38)
at feign.ReflectiveFeign$ParseHandlersByName.apply(ReflectiveFeign.java:151)
at feign.ReflectiveFeign.newInstance(ReflectiveFeign.java:49)
at feign.Feign$Builder.target(Feign.java:269)
at org.springframework.cloud.openfeign.HystrixTargeter.target(HystrixTargeter.java:38)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:369)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:327)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:169)
... 93 more
是因为在 config 中用了 Contract.Default() :
@Configuration
public class FeignConfig {
/**
* 如需使用spring系的注解(RequestMapping、RequestParam等)可以不加如下 Contract 配置,
* 或者返回 SpringMvcContract。
*/
@Bean
public Contract feignContract() {
//SpringMvcContract springMvcContract = new SpringMvcContract();
Contract.Default defaultContract = new Contract.Default();
return defaultContract;
}
}
Contract 源码摘录:
package feign;
/**
* Defines what annotations and values are valid on interfaces.
* 定义在接口上哪些注释和值是有效的。
*/
public interface Contract {
// ....... some code ......
}
这个接口的作用是,定义在 feign 接口上哪些注释和值是有效的。那 Contract.Default() 中只处理了feign包自己一些注解(如 feign.RequestLine),所以使用 @RequestMapping 报错。去掉配置,或者换成 SpringMvcContract 即可解决。
更多推荐
所有评论(0)