1.核心InvocationHandler
package com.tigercontrol.app.microservice.utils.myfeignproxy;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.tigercontrol.app.microservice.utils.NetUtils;
import com.tigercontrol.app.microservice.utils.StringUtils;
import com.tigercontrol.app.microservice.utils.myfeignproxy.annotation.MyDeleteMapping;
import com.tigercontrol.app.microservice.utils.myfeignproxy.annotation.MyGetMapping;
import com.tigercontrol.app.microservice.utils.myfeignproxy.annotation.MyPostMapping;
import com.tigercontrol.app.microservice.utils.myfeignproxy.annotation.MyPutMapping;
import com.tigercontrol.app.microservice.utils.myfeignproxy.common.ErrorCode;
import com.tigercontrol.app.microservice.utils.myfeignproxy.exception.MyFeignException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class FeignInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 排除代理Object类中方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
Map<String, String> pathParamMap = new HashMap<>();
Map<String, String> headerParamMap = new HashMap<>();
String body = null;
Map<String, Object> queryParamMap = new HashMap<>();
// region 获取参数
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Annotation[] annotations = parameters[i].getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof RequestBody) {
body = new ObjectMapper().writeValueAsString(args[i]);
} else if (annotation instanceof RequestParam) {
String name = ((RequestParam) annotation).value();
queryParamMap.put(name, args[i]);
} else if (annotation instanceof RequestHeader) {
String name = ((RequestHeader) annotation).value();
// String userId = RequestParamUtils.getAttribute("userId");
// String userId = "000001";
headerParamMap.put(name, args[i].toString());
} else if (annotation instanceof PathVariable) {
String name = ((PathVariable) annotation).value();
pathParamMap.put(name, args[i].toString());
}
}
}
//endregion
HttpRequest request;
//region 获取request 对象 以及路径参数处理完毕
if (method.isAnnotationPresent(MyGetMapping.class)) {
//Get实现
MyGetMapping myGetMapping = method.getAnnotation(MyGetMapping.class);
String url = null;
if (!pathParamMap.isEmpty()) {
url = StringUtils.replacePlaceholders(myGetMapping.value(), pathParamMap);
} else {
url = myGetMapping.value();
}
request = NetUtils.getRequest(url);
} else if (method.isAnnotationPresent(MyPostMapping.class)) {
//Post实现
MyPostMapping myPostMapping = method.getAnnotation(MyPostMapping.class);
String url = null;
if (!pathParamMap.isEmpty()) {
url = StringUtils.replacePlaceholders(myPostMapping.value(), pathParamMap);
} else {
url = myPostMapping.value();
}
request = NetUtils.postRequest(url);
} else if (method.isAnnotationPresent(MyPutMapping.class)) {
//Put实现
MyPutMapping myPutMapping = method.getAnnotation(MyPutMapping.class);
String url = null;
if (!pathParamMap.isEmpty()) {
url = StringUtils.replacePlaceholders(myPutMapping.value(), pathParamMap);
} else {
url = myPutMapping.value();
}
request = NetUtils.putRequest(url);
} else if (method.isAnnotationPresent(MyDeleteMapping.class)) {
//Delete实现
MyDeleteMapping myDeleteMapping = method.getAnnotation(MyDeleteMapping.class);
String url = null;
if (!pathParamMap.isEmpty()) {
url = StringUtils.replacePlaceholders(myDeleteMapping.value(), pathParamMap);
} else {
url = myDeleteMapping.value();
}
request = NetUtils.putRequest(url);
} else {
throw new MyFeignException(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCode.ERROR_REQUEST, "请添加请求方式!");
}
//endregion
//请求头参数
if (!headerParamMap.isEmpty()) {
headerParamMap.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
request.header(key, value);
}
});
}
//请求体参数
if (body != null) {
request.body(body);
}
//查询字符串参数
if (!queryParamMap.isEmpty()) {
request.form(queryParamMap);
}
HttpResponse execute = request.execute();
int status = execute.getStatus();
if (status == HttpStatus.OK.value()) {
ObjectMapper objectMapper = new ObjectMapper();
// 在这里定义代理类的行为
Type genericReturnType = method.getGenericReturnType();
TypeFactory typeFactory = TypeFactory.defaultInstance();
JavaType javaType = typeFactory.constructType(genericReturnType);
String json = execute.body();
Object result = objectMapper.readValue(json, javaType);
return result;
} else {
throw new MyFeignException(HttpStatus.valueOf(status), ErrorCode.EXCEPTION_REQUEST, body);
}
}
}
2.自定义异常
package com.tigercontrol.app.microservice.utils.myfeignproxy.exception;
import org.springframework.http.HttpStatus;
public class MyFeignException extends RuntimeException{
private HttpStatus httpStatus;
private String code;
private String body;
public MyFeignException(String code, String message) {
super(message);
this.code = code;
this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
}
public MyFeignException(String code, String message,String body) {
super(message);
this.code = code;
this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
this.body = body;
}
public MyFeignException(String code, String message, Throwable cause) {
super(message, cause);
this.code = code;
this.httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
}
public MyFeignException(HttpStatus httpStatus, String code, String message) {
super(message);
this.code = code;
this.httpStatus = httpStatus;
}
public MyFeignException(HttpStatus httpStatus, String code, String message, Throwable cause) {
super(message, cause);
this.code = code;
this.httpStatus = httpStatus;
}
public HttpStatus getHttpStatus() {
return httpStatus;
}
public String getCode() {
return code;
}
public String getBody() {
return body;
}
}
3.自定义注解
这里就举一个例子都一样的
package com.tigercontrol.app.microservice.utils.myfeignproxy.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyGetMapping {
String value();
}
4.被代理的接口
package com.app.microservice.heatsource.feign;
import com.app.microservice.heatsource.model.entity.HeatSource;
import com.app.microservice.heatsource.model.vo.HeatSourceVo;
import com.app.microservice.utils.myfeignproxy.annotation.MyDeleteMapping;
import com.app.microservice.utils.myfeignproxy.annotation.MyGetMapping;
import com.app.microservice.utils.myfeignproxy.annotation.MyPostMapping;
import com.app.microservice.utils.myfeignproxy.annotation.MyPutMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import java.util.List;
public interface HeatSourceFeignClient {
String PREFIX;
/**
*
* @param heatSourceVo
* @param userId
* @return
*/
@MyPostMapping(PREFIX + "/add")
boolean addHeatSource(@RequestBody HeatSourceVo heatSourceVo, @RequestHeader("x-auth-request-user") String userId);
/**
*
* @param orgId
* @param userId
* @return
*/
@MyGetMapping(PREFIX + "/findAll/org/{orgId}")
List<HeatSource> findAllHeatSource(@PathVariable("orgId") String orgId, @RequestHeader("x-auth-request-user") String userId);
/**
*
* @param orgId
* @param userId
* @return
*/
@MyGetMapping(PREFIX + "/{id}/org/{orgId}")
HeatSource findHeatSourceById(@PathVariable("id") String id, @PathVariable("orgId") String orgId, @RequestHeader("x-auth-request-user") String userId);
/**
*
* @param id
* @param heatSourceVo
* @param userId
* @return
*/
@MyPutMapping(PREFIX+"/{id}/update")
boolean updateHeatSource(@PathVariable("id") String id, @RequestBody HeatSourceVo heatSourceVo,@RequestHeader("x-auth-request-user")String userId);
/**
*
* @param id
* @param userId
* @return
*/
@MyDeleteMapping(PREFIX+"/{id}/delete")
boolean deleteHeatSource(@PathVariable("id") String id,@RequestHeader("x-auth-request-user")String userId);
}
5.利用Spring容器注入IOC
package com.tigercontrol.app.microservice.config;
import com.tigercontrol.app.microservice.heatsource.feign.HeatSourceFeignClient;
import com.tigercontrol.app.microservice.utils.myfeignproxy.FeignInvocationHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Proxy;
@Configuration
public class FeignConfig {
@Bean
public FeignInvocationHandler feignInvocationHandler(){
return new FeignInvocationHandler();
}
@Bean
public HeatSourceFeignClient heatSourceFeignClient(FeignInvocationHandler feignInvocationHandler){
return (HeatSourceFeignClient) Proxy.newProxyInstance(
HeatSourceFeignClient.class.getClassLoader(),
new Class[] { HeatSourceFeignClient.class },
feignInvocationHandler
);
}
}
6.异常处理
@ExceptionHandler(IORuntimeException.class)
public ResponseEntity<ErrorResultVo> handleIORuntimeException(IORuntimeException e) {
if (e.getCause() != null) {
logger.error(e.getMessage(), e);
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResultVo(ErrorCode.INTERNET_ERROR, "网络错误"));
}
@ExceptionHandler(MyFeignException.class)
public ResponseEntity<ErrorResultVo> handleMyFeignException(MyFeignException e) {
if (e.getCause() != null) {
logger.error(e.getMessage(), e);
}
HttpStatus httpStatus = e.getHttpStatus();
if (httpStatus == null) {
httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
}
ErrorResultVo errorResultVo = null;
try {
String body = e.getBody();
errorResultVo = JsonUtils.jsonToObj(body, ErrorResultVo.class);
return ResponseEntity.status(httpStatus).body(errorResultVo);
} catch (Exception ex) {
ex.printStackTrace();
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResultVo(ErrorCode.INTERNAL_SERVER_ERROR, "内部错误"));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResultVo> handleException(Exception e) {
if (e.getCause() != null) {
logger.error(e.getMessage(), e);
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResultVo(ErrorCode.INTERNAL_SERVER_ERROR, "内部错误"));
}