1
1、依赖引入
<!--客户端依赖-->
<dependencies>
<!--由于使用了lombok减缓模型对象的编写,所以需要添加该依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<!-- 因为使用web进行测试,所以需要引入Web依赖-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<!-- 使用openfeign,所以必须引入该依赖-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
</dependencies>
<!--服务端依赖-->
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!--使用json序列化,所以添加该依赖-->
<dependency>
<artifactId>fastjson</artifactId>
<groupId>com.alibaba</groupId>
<version>1.2.62</version>
</dependency>
<!--由于使用了lombok减缓模型对象的编写,所以需要添加该依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
2、服务端代码
@RestController
@RequestMapping("server")
public class ServerController {
@GetMapping("get")
public String getFunc(@RequestParam(value = "name") String name) {
return "get --- " + name;
}
@PostMapping("post")
public Student PostFunc(@RequestParam(value = "remark") String remark, @RequestBody Student student) {
student.setRemark(remark);
return student;
}
@PutMapping("put")
public Student putFunc(@RequestParam(value = "remark") String remark, @RequestBody Student student) {
student.setRemark(remark);
return student;
}
@DeleteMapping("delete")
public String deleteFunc(@RequestParam(value = "remark") String name) {
return "delete --- " + name;
}
@PostMapping("path/{remark}")
public Student pathFunc(@PathVariable(value = "remark") String remark, @RequestBody Student student) {
student.setRemark(remark);
return student;
}
}
3、定义客户端Feign接口,在客户端中使用两种方式进行调用测试
3.1通过SpringBoot自动注入Feign对象,不改变调用服务器地址创建。该接口定义如下:
import com.mnyc.model.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
//为了能看清楚自动创建对象和SpringBoot创建对象的区别,因此这个地方需要设置url
//这样Feign就不会去创建负载均衡的底层调用对象,然后就和自己自定url的对象基本相同了
@FeignClient(name = "feign", url = "http://localhost:8080/server")
public interface FeignServerrClient {
@GetMapping("/get")
String getMethod(@RequestParam(value = "name", required = true) String name);
@PostMapping("/post")
String postMethod(@RequestParam("remark") String remark, User user);
@PutMapping("/put")
String putMethod(@RequestParam("remark") String remark, User user);
@DeleteMapping("/delete")
String deleteMethod(@RequestParam("remark") String remark);
@PostMapping("/path/{remark}")
String pathMethod(@PathVariable("remark") String remark, User user);
}
3.2 不指定服务地址,在调用的时候动态指定调用地址
import com.mnyc.model.User;
import feign.Param;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.net.URI;
@FeignClient(name = "test")
public interface FeignTestClient {
//在其他的一些博客中说的在Feign接口上使用@RequestLine,如果使用@RequestLine
//应该是需要配合对应的decoder、encoder、contract,但是我没有找到正确的方式
// 配置正确合适的decoder、encoder、contract,然后通过和SpirngBoot自动创建
// 的Feign对象进行对比,然后在自己创建客户端的时候设置decoder、encoder、
// contract三个核心对象与SpringBoot创建的相同,所以在客户端Feign的接口中使
// 用完全和不动态修改地址的Feign接口相同
@GetMapping("/get")
String getMethod(@RequestParam(value = "name", required = true) String name);
@PostMapping("/post")
String postMethod(@RequestParam("remark") String remark, User user);
@PutMapping("/put")
String putMethod(@RequestParam("remark") String remark, User user);
@DeleteMapping("/delete")
String deleteMethod(@RequestParam("remark") String remark);
@PostMapping("/path/{remark}")
String pathMethod(@PathVariable("remark") String remark, User user);
}
4、为了方便测试,每个调用服务端的Feign都使用单独的服务类进行管理
4.1使用固定服务地址方式调用服务类
import com.mnyc.http.FeignServerrClient;
import com.mnyc.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class FeignServerService {
@Autowired
FeignServerrClient feignServerrClient;
String flag = "FeignClient";
public void get() {
try {
String result = "";
result = feignServerrClient.getMethod(flag);
log.info("Feign ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void post() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
result = feignServerrClient.postMethod(flag, user);
log.info("Feign ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void put() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
result = feignServerrClient.putMethod(flag, user);
log.info("Feign ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void delete() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
result = feignServerrClient.deleteMethod(flag);
log.info("Feign ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void path() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
result = feignServerrClient.pathMethod(flag,user);
log.info("Feign ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
4.2使用动态URL方式调用服务端的服务类
import com.mnyc.http.FeignTestClient;
import com.mnyc.model.User;
import feign.Feign;
import feign.form.spring.SpringFormEncoder;
import feign.optionals.OptionalDecoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Service;
@Slf4j
@Service
//网上说的需要在调用的地方导入该配置类,最后我屏蔽掉该代码好像也可以
@Import(FeignClientsConfiguration.class)
public class FeignTestService {
@Autowired
ObjectFactory<HttpMessageConverters> messageConverters;
String flag = "TestClient";
private FeignTestClient createFeignClient() {
OptionalDecoder decoder = new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters)));
SpringEncoder springEncoder = new SpringEncoder(messageConverters);
SpringFormEncoder encoder = new SpringFormEncoder(springEncoder);
SpringMvcContract contract = new SpringMvcContract();
FeignTestClient feignTestClient = Feign.builder()
.decoder(decoder)
.encoder(encoder)
.contract(contract)
//这个地方的Url可以根据每次调用的时候进行改变
.target(FeignTestClient.class, "http://localhost:8080/server");//传入url
return feignTestClient;
}
public void get() {
try {
FeignTestClient feignClient = createFeignClient();
String result = feignClient.getMethod(flag);
log.info("TEST ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void post() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
FeignTestClient feignClient = createFeignClient();
result = feignClient.postMethod(flag, user);
log.info("TEST ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void put() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
FeignTestClient feignClient = createFeignClient();
result = feignClient.putMethod(flag, user);
log.info("TEST ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void delete() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
FeignTestClient feignClient = createFeignClient();
result = feignClient.deleteMethod(flag);
log.info("TEST ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void path() {
try {
String result = "";
User user = new User();
user.setName("name");
user.setAge(100);
FeignTestClient feignClient = createFeignClient();
result = feignClient.pathMethod(flag, user);
log.info("TEST ========= " + result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
5、核心
5.1 在使用lombok对模型进行标注的时候,因为在controller中有对应模型作为输入参数,所以该模型上必须添加“@NoArgsConstructor”注解
5.2Feign核心部分
private FeignTestClient createFeignClient() {
//1、在创建Feign客户端的时候最核心的对象是decoder、encoder、contract
//通过跟踪源码与SpringBoot自动创建的Feign对象比较,设置decoder、encoder、
//contract为SpringBoot中自动创建对象相同,然后定义Feign接口的时候,
//各种参数的注解和方法的注解就可以和不动态修改url的相同了
//decoder解码器,对返回的结果进行解码
OptionalDecoder decoder = new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters)));
//encoder编码器,对输入的数据进行编码
SpringEncoder springEncoder = new SpringEncoder(messageConverters);
SpringFormEncoder encoder = new SpringFormEncoder(springEncoder);
//该对象是将接口进行解析,方便生成最后调用的网络对象HttpurlConnection
SpringMvcContract contract = new SpringMvcContract();
FeignTestClient feignTestClient = Feign.builder()
.decoder(decoder)
.encoder(encoder)
.contract(contract)
//这个地方的Url可以根据每次调用的时候进行改变
.target(FeignTestClient.class, "http://localhost:8080/server");//传入url
return feignTestClient;
}
DEMO下载地址:https://download.csdn.net/download/wangdaoyin2010/21138515