feign 的简介
feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
feign强调服务之间的调用
一 服务提供者准备
- application.yml 配置
server:
port: 8602
spring:
application:
name: testservice
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8800/eureka/
app:
ip: localhost
- DTO准备
创建共用的ResponseDTO:Result.java
public class result{
private int code;
private String message;
private Object content;
private String serviceName;
private String host;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getContent() {
return content;
}
public void setContent(Object content) {
this.content = content;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
创建Plus.java用作加法运算RequestDTO
public class Plus {
private int numA;
private int numB;
public int getNumA() {
return numA;
}
public void setNumA(int numA) {
this.numA = numA;
}
public int getNumB() {
return numB;
}
public void setNumB(int numB) {
this.numB = numB;
}
}
- 编写服务入口
创建服务入口 TestController.java
@RestController
public class TestController {
@Value("${spring.application.name}")
private String serviceName;
@Value("${app.ip}")
private String address;
@Value("${server.port}")
private String port;
@RequestMapping("/")
public Object index() {
Result result = new Result();
result.setServiceName(serviceName);
result.setHost(String.format("%s:%s", address, port));
result.setMessage("hello");
return result;
}
@RequestMapping("/plus")
public Object plus(Plus plus) {
Result result = new Result();
result.setServiceName(serviceName);
result.setHost(String.format("%s:%s", address, port));
result.setMessage("success");
result.setContent(plus.getNumA() + plus.getNumB());
return result;
}
@RequestMapping("/plus2")
public Object plus2(@RequestBody Plus plus) {
Result result = new Result();
result.setServiceName(serviceName);
result.setHost(String.format("%s:%s", address, port));
result.setMessage("success");
result.setContent(plus.getNumA() + plus.getNumB());
return result;
}
}
- 访问测试
启动TestService
分别以端口8602,8603启动testservice。 此时testservice等于是在Eureka Server注册了两个实例
分别访问 http://localhost:8602,http://localhost:8603
二、服务消费者搭建(Feign)
- 创建Feign项目
在pom.xml加入相关依赖
<groupId>io.ken.springcloud.feignclient</groupId>
<artifactId>feignclient</artifactId>
<version>1.0-SNAPSHOT</version>
<name>feignclient</name>
<url>http://ken.io</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</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-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<finalName>feignclient</finalName>
</build>
- 配置Eureka Client:application.yml
server:
port: 8605
spring:
application:
name: feignclient
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8800/eureka/
- 配置Fegin启动类
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
- 创建共用的ResponseDTO:Result.java
- 创建Plus.java作为加法运算RequestDTO
public class Result {
private int code;
private String message;
private Object content;
private String serviceName;
private String host;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getContent() {
return content;
}
public void setContent(Object content) {
this.content = content;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
public class Plus {
private int numA;
private int numB;
public int getNumA() {
return numA;
}
public void setNumA(int numA) {
this.numA = numA;
}
public int getNumB() {
return numB;
}
public void setNumB(int numB) {
this.numB = numB;
}
}
- 编写Eureka服务访问
import io.ken.springcloud.feignclient.model.Plus;
import io.ken.springcloud.feignclient.model.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "testservice")
public interface TestService {
@RequestMapping(value = "/", method = RequestMethod.GET)
String indexService();
@RequestMapping(value = "/plus", method = RequestMethod.GET)
Result plusService(@RequestParam(name = "numA") int numA, @RequestParam(name = "numB") int numB);
@RequestMapping(value = "/plus", method = RequestMethod.POST, consumes = "application/json")
Result plusabService(Plus plus);
@RequestMapping(value = "/plus2", method = RequestMethod.POST)
Result plus2Service(@RequestBody Plus plus);
}
- 编写服务入口:创建 TestController.java 作为访问testservice的入口
import io.ken.springcloud.feignclient.model.Plus;
import io.ken.springcloud.feignclient.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
private TestService testService;
@RequestMapping("/")
public Object index() {
return "feign client";
}
@RequestMapping("/ti")
public Object ti() {
return testService.indexService();
}
@RequestMapping("/plus")
public Object plus(@RequestParam("numa") int numA, @RequestParam("numb") int numB) {
return testService.plusService(numA, numB);
}
@RequestMapping("/plusab")
public Object plusA(@RequestParam("numa") int numA, @RequestParam("numb") int numB) {
Plus plus = new Plus();
plus.setNumA(numA);
plus.setNumB(numB);
return testService.plusabService(plus);
}
@RequestMapping("/plus2")
public Object plus2(Plus plus) {
return testService.plus2Service(plus);
}
}
- 服务消费/访问测试
FeignClient项目启动后,访问 http://localhost:8605/ti 会交替显示以下内容
{
"code": 0,
"message": "hello",
"content": null,
"serviceName": "testservice",
"host": "localhost:8602"
}
{
"code": 0,
"message": "hello",
"content": null,
"serviceName": "testservice",
"host": "localhost:8603"
}
okhttp简介
OkHttp是一个开源的Java/Android HTTP客户端库,它由Square公司开发并维护。OkHttp的目标是成为一个快速、高效、可扩展且易于使用的HTTP客户端库,为Android应用程序提供网络访问的支持。
使用OkHttp,我们可以轻松地完成一些常见的HTTP操作,如GET和POST请求,并进行文件上传和下载。它还支持异步请求和同步请求,并包含有用的功能,如重试请求、缓存响应和加密通信。
更强调,调取第三方接口
更好的http客户端:https://mp.weixin.qq.com/s/iXVAIz_H8eMRZADLlQL6wA
创建一个配置类
@Configuration
public class OkHttpClientConfig {
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient();
}
}
创建一个Service类,使用@Autowired注解将OkHttpClient注入:
@Service
public class ApiService {
private final OkHttpClient okHttpClient;
public ApiService(@Autowired OkHttpClient okHttpClient) {
this.okHttpClient = okHttpClient;
}
public String sendRequest(String url) throws IOException {
Request request = new Request.Builder().url(url).build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
return Objects.requireNonNull(response.body()).string();
}
}
}
最后,在控制器中调用该Service:
@RestController
public class ApiController {
private final ApiService apiService;
public ApiController(@Autowired ApiService apiService) {
this.apiService = apiService;
}
@GetMapping("/get")
public String getData() throws IOException {
String url = "http://example.com/data";
return apiService.sendRequest(url);
}
}
关于okhttp的其他类型请求
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import okhttp3.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("okhttp")
public class OkHttpController {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static final MediaType XML = MediaType.parse("application/xml; charset=utf-8");
private OkHttpClient client = new OkHttpClient();
/**
* get请求
* @return
*/
@RequestMapping("get")
public String Get(){
String url = "http://localhost:36247/weatherforecast/string";
Request request = new Request.Builder()
.url(url)
.build();
try{
Response response = client.newCall(request).execute();
return response.body().string();
}catch (Exception e){
throw new RuntimeException("HTTP GET同步请求失败 URL:"+url,e);
}
}
/**
* get请求
* @return
*/
@RequestMapping("getUser")
public String GetUser(){
String url = "http://localhost:36247/weatherforecast/getuser?name=admin_get&password=123456_get";
Request request = new Request.Builder()
.url(url)
.build();
try{
Response response = client.newCall(request).execute();
return response.body().string();
}catch (Exception e){
throw new RuntimeException("HTTP GET同步请求失败 URL:"+url,e);
}
}
/**
* post 请求
* FormData 参数
* @return
*/
@RequestMapping("postForm")
public String PostForm(){
String url = "http://localhost:36247/weatherforecast/form";
FormBody.Builder form = new FormBody.Builder();
form.add("name","admin_form");
form.add("password","123456_form");
Request request = new Request.Builder()
.url(url)
.post(form.build())
.build();
try{
Response response = client.newCall(request).execute();
return response.body().string();
}catch (Exception e){
throw new RuntimeException("HTTP GET同步请求失败 URL:"+url,e);
}
}
/**
* post 请求
* JSON 参数
* @return
*/
@RequestMapping("postJson")
public String PostJson(){
String url = "http://localhost:36247/weatherforecast";
/**
* OK
*/
JSONObject json = new JSONObject();
json.put("name","admin_json");
json.put("password","123456_json");
/**
* OK
*/
Map<String,Object> map = new HashMap<>();
map.put("name","admin_map");
map.put("password","123456_map");
RequestBody requestBody = RequestBody.create(JSON,String.valueOf(json));
//RequestBody requestBody = RequestBody.create(JSON,new Gson().toJson(map));
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
try{
Response response = client.newCall(request).execute();
return response.body().string();
}catch (Exception e){
throw new RuntimeException("HTTP POST请求失败 URL:"+url,e);
}
}
}
``