1. Primero realice el proyecto de prestación de servicios ********
pom.xml
<?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.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.frank</groupId>
<artifactId>feign-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>feign-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
server.port=8081
spring.application.name=user-service
server.servlet.context-path=/api
Calificación
package com.frank.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author 小石潭记
* @date 2020/6/25 12:02
* @Description: ${todo}
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Grade {
private int id;
private String name;
private List<User> users;
private String address;
}
Usuario
package com.frank.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 小石潭记
* @date 2020/6/22 21:42
* @Description: ${todo}
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
ServerController
package com.frank.web;
import com.frank.entity.Grade;
import com.frank.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
/**
* @author 小石潭记
* @date 2020/6/22 21:40
* @Description: ${todo}
*/
@RestController
@Slf4j
public class ServerController {
@GetMapping("/getUserInfo")
public Map<String,Object> getUserInfo() {
Map<String,Object> map = new HashMap<>();
map.put("code", 200);
map.put("msg", "success");
map.put("data", new User(1,"小石潭记",26));
log.info("返回成功数据成功:{},{}", map, new Date());
return map;
}
@GetMapping("/getGradeInfo")
public Map<String,Object> getGradeInfo() {
Map<String,Object> map = new HashMap<>();
List<User> users = new ArrayList<>();
users.add(new User(1,"小石潭记",8));
users.add(new User(2,"陋室铭",7));
users.add(new User(3,"桃花源记",9));
Grade grade = new Grade(1,"二年级",users, "重庆市忠县");
map.put("code", 200);
map.put("msg", "success");
map.put("data", grade);
log.info("返回geGradeInfo数据成功:{},{}", map, new Date());
return map;
}
@GetMapping("/getFailInfo")
public Map<String,Object> getFailInfo() {
Map<String,Object> map = new HashMap<>();
map.put("code", 404);
map.put("msg", "fail");
map.put("data", null);
log.info("返回失败数据成功:{},{}", map, new Date());
return map;
}
}
FeignServerApplication
package com.frank;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FeignServerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignServerApplication.class, args);
}
}
Se ha completado la prestación del servicio. . .
2. proyecto de cliente falso ******
pom.xml
<?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.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.frank</groupId>
<artifactId>feign-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>feign-client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
server.port=8082
spring.application.name=feign-client
server.servlet.context-path=/client
# 开启熔断
#feign.hystrix.enabled=true
Mi consejo
package com.frank.advice;
import com.frank.domain.MyException;
import com.frank.domain.dto.BaseResponse;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.servlet.http.HttpServletRequest;
/**
* @author 小石潭记
* @date 2020/6/22 21:07
* @Description: ${todo}
*/
@RestControllerAdvice
public class MyAdvice implements ResponseBodyAdvice<Object> {
/**
* 抛出该自定义异常就会执行该方法
*/
@ExceptionHandler(value = MyException.class)
BaseResponse handleMyException(MyException e, HttpServletRequest request){
return BaseResponse.fail(e.getMessage());
}
/**
* 判断哪些需要拦截 return true 就会执行beforeBodyWrite
*/
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
/**
* 经过decoder之后,就会到达这里,返回结果前,可以对结果进行处理
*/
@Override
public Object beforeBodyWrite(Object obj, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
System.out.println("==>beforeBodyWrite:" + obj.toString() + ","
+ methodParameter);
return obj;
}
}
MyFeignClient
package com.frank.client;
import com.frank.domain.dto.BaseResponse;
import com.frank.domain.dto.Grade;
import com.frank.domain.dto.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author 小石潭记
* @date 2020/6/22 21:48
* @Description: ${todo}
*/
@FeignClient(
//服务名
name = "user-service",
//服务地址
url = "http://localhost:8081/api"
// ,fallback = UserHihystric.class 暂不开启熔断
)
public interface MyFeignClient {
//对应的服务里的接口地址,及请求方式
@RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
@ResponseBody
BaseResponse getUserInfo();
@RequestMapping(value = "/getGradeInfo", method = RequestMethod.GET)
@ResponseBody
BaseResponse getGradeInfo();
@RequestMapping(value = "/getFailInfo", method = RequestMethod.GET)
@ResponseBody
BaseResponse getFailInfo();
}
MyDecoder
package com.frank.decoder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.frank.domain.EnumError;
import com.frank.domain.MyException;
import com.frank.domain.dto.BaseResponse;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.lang.reflect.Type;
/**
* @author 小石潭记
* @date 2020/6/23 21:09
* @Description: 自定义feign的正常返回结果
*/
@Component
public class MyDecoder implements Decoder {
@Autowired
private ObjectMapper mapper;
/**
* 这里统一处理,根据状态码判断返回正常还是异常的,
* 200返回正常的,其他状态码直接抛出异常
*/
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
if (response.status() >= 200 && response.status() <= 299) {
String result = Util.toString(response.body().asReader());
BaseResponse baseResponse = mapper.readValue(result, BaseResponse.class);
int code = baseResponse.getCode();
if (code == 200){
return baseResponse;
}
throw new MyException(EnumError.BAD_REQUEST);
}
throw new MyException(EnumError.OTHER_ERROR);
}
}
MyErrorDecoder
package com.frank.decoder;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.frank.domain.EnumError;
import com.frank.domain.ExceptionInfo;
import com.frank.domain.MyException;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.ErrorDecoder;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* @author 小石潭记
* @date 2020/6/23 20:53
* @Description: 自定义feign错误异常处理
*/
@Configuration
public class MyErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
/*if (response.status() >= 400 && response.status() <= 499) {
return new MyException(EnumError.BAD_REQUEST);
}
if (response.status() >= 500 && response.status() <= 599) {
return new MyException(EnumError.SERVER_ERROR);
}
return new MyException(EnumError.OTHER_ERROR);*/
try {
if (response.body() != null) {
ObjectMapper mapper = new ObjectMapper();
ExceptionInfo exceptionInfo =mapper.readValue(Util.toString(response.body().asReader()),
new TypeReference<ExceptionInfo>() {});
Class clazz = Class.forName(exceptionInfo.getException());
return (Exception) clazz.getDeclaredConstructor(String.class).newInstance(exceptionInfo.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
return FeignException.errorStatus(methodKey, response);
}
}
BaseResponse
package com.frank.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @author 小石潭记
* @date 2020/6/25 12:19
* @Description: ${todo}
*/
@Data
public class BaseResponse<T> {
/**
* 返回的状态码
*/
@JsonProperty("code")
private int code;
/**
* 返回的信息
*/
@JsonProperty("msg")
private String message;
/**
* 返回的数据
*/
@JsonProperty("data")
private T data;
public static BaseResponse success(Object object){
BaseResponse baseResponse = new BaseResponse();
baseResponse.setCode(200);
baseResponse.setMessage("success");
baseResponse.setData(object);
return baseResponse;
}
public static BaseResponse fail(Object object){
BaseResponse baseResponse = new BaseResponse();
baseResponse.setCode(404);
baseResponse.setMessage("fail");
baseResponse.setData(object);
return baseResponse;
}
}
Calificación
package com.frank.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.frank.domain.dto.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author 小石潭记
* @date 2020/6/25 12:02
* @Description: ${todo}
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Grade {
@JsonProperty("id")
private int id;
@JsonProperty("name")
private String name;
@JsonProperty("users")
private List<User> users;
@JsonProperty("address")
private String address;
}
Usuario
package com.frank.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 小石潭记
* @date 2020/6/22 21:42
* @Description: ${todo}
*/
@Data
public class User {
@JsonProperty("id")
private int id;
@JsonProperty("name")
private String name;
@JsonProperty("age")
private int age;
}
EnumError
package com.frank.domain;
/**
* @author 小石潭记
* @date 2020/6/23 21:01
* @Description: ${todo}
*/
public enum EnumError {
SERVER_ERROR(500, "服务器异常,请联系系统运维人员"),
BAD_REQUEST(400, "请求异常"),
OTHER_ERROR(404, "系统异常");
private int status;
private String reason;
EnumError(int status, String reason){
this.status = status;
this.reason = reason;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}}
ExceptionInfo
package com.frank.domain;
import lombok.Data;
/**
* @author 小石潭记
* @date 2020/6/25 21:10
* @Description: ${todo}
*/
@Data
public class ExceptionInfo{
private Long timestamp;
private Integer status;
//异常包结构-"com.crazy.cloud.common.exception.DataConflictException"
private String exception;
//信息--手机已注册
private String message;
private String path;
private String error;
}
MyException
package com.frank.domain;
/**
* @author 小石潭记
* @date 2020/6/25 14:09
* @Description: ${todo}
*/
public class MyException extends RuntimeException{
public MyException(EnumError enumError){
super(enumError.getReason());
}
}
MyHihystric
package com.frank.hihystric;
import com.frank.client.MyFeignClient;
import com.frank.domain.dto.BaseResponse;
import com.frank.domain.dto.Grade;
import com.frank.domain.dto.User;
/**
* @author 小石潭记
* @date 2020/6/23 20:31
* @Description: ${todo}
*/
//@Component 暂不开启熔断, 全部返回的null,如果需要使用熔断,返回默认的一个对象即可
public class MyHihystric implements MyFeignClient {
@Override
public BaseResponse<User> getUserInfo() {
return null;
}
@Override
public BaseResponse<Grade> getGradeInfo() {
return null;
}
@Override
public BaseResponse getFailInfo() {
return null;
}
}
ClientController
package com.frank.web;
import com.frank.client.MyFeignClient;
import com.frank.domain.dto.BaseResponse;
import com.frank.domain.dto.Grade;
import com.frank.domain.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
/**
* @author 小石潭记
* @date 2020/6/20 21:38
* @Description: ${todo}
*/
@RestController
@Slf4j
public class ClientController {
@Autowired
private MyFeignClient userFeignClient;
@GetMapping("/getUserInfo")
public BaseResponse<User> getUserInfo() {
BaseResponse<User> successInfo = userFeignClient.getUserInfo();
log.info("client->getSuccessInfo返回数据:{},{}", successInfo, new Date());
return successInfo;
}
@GetMapping("/getGradeInfo")
public BaseResponse<Grade> getGradeInfo() {
BaseResponse<Grade> successInfo = userFeignClient.getGradeInfo();
log.info("client->getGradeInfo返回数据:{},{}", successInfo, new Date());
return successInfo;
}
@GetMapping("/getFailInfo")
public BaseResponse getFailInfo() {
BaseResponse failInfo = userFeignClient.getFailInfo();
log.info("client返回失败数据:{},{}", failInfo, new Date());
return failInfo;
}
}
Aplicación FeignClient
package com.frank;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
//@EnableHystrixDashboard 暂时不开启熔断
public class FeignClientApplication {
public static void main(String[] args) {
SpringApplication.run(FeignClientApplication.class, args);
}
}
Iniciar la prueba del proyecto:
http: // localhost: 8082 / client / getUserInfo http: // localhost: 8082 / client / getGradeInfo http: // localhost: 8082 / client / getFailInfo