OpenFeign返回参数统一处理

自定义解码器

package com.itheima.feign;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.exception.BusinessException;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import org.springframework.core.ResolvableType;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;

/**
 * @author 阿呆
 * @desciption:
 * @since 2023/4/23 23:09
 */
public abstract class AbstractCustomDecoder <T> implements Decoder{


	protected final Class<T> targetClazz;

	protected Set<Class> clazzSet;

	protected ObjectMapper objectMapper;

	protected AbstractCustomDecoder(ObjectMapper objectMapper) {
		this.targetClazz = retrieveAnnotationType();
		this.objectMapper = objectMapper;
		this.clazzSet = new HashSet<>();
		this.clazzSet.add(this.targetClazz);
		this.fillTargetClazz(this.clazzSet);
	}

	protected abstract <D> Supplier<D> getData(T obj);
	protected abstract <C> Supplier<C> getCode(T obj);
	protected abstract <M> Supplier<M> getMes(T obj);

	protected abstract boolean isSuccess(T obj);

	protected abstract void fillTargetClazz(Set<Class> clazzSet);

	@Override
	public Object decode(Response response, Type type) throws IOException {
		return customDecoder(response, type);
	}


	/**
	 * 检索泛型对应的实际类型
	 * @return
	 */
	private Class<T> retrieveAnnotationType(){
		Type type = getClass().getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) type;
			for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) {
				if (actualTypeArgument instanceof Class) {
					return (Class) actualTypeArgument;
				}
			}
		}
		return null;
	}

	protected Object customDecoder(Response response, Type type) throws IOException {
		String body = Util.toString(response.body().asReader(StandardCharsets.UTF_8));
		Class<?> clazz = ResolvableType.forType(type).getRawClass();
		if (this.clazzSet.contains(clazz)){
			return this.objectMapper.readValue(body,clazz);
		}
		try{
			return this.objectMapper.readValue(body,clazz);
		}catch (Exception e){
			JavaType paramterType = this.objectMapper.getTypeFactory().constructType(type);
			JavaType resultType = this.objectMapper.getTypeFactory().constructParametricType(this.targetClazz, paramterType);
			T data = (T)this.objectMapper.readValue(body,resultType);
			if (isSuccess(data)){
				return getData(data).get();
			}
			throw new BusinessException(Integer.valueOf(getCode(data).get().toString()),getMes(data).get().toString());
		}
	}

}


package com.itheima.feign;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.common.entry.FeignResponse;
import com.itheima.common.entry.Result;
import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Set;
import java.util.function.Supplier;

/**
 * @author 阿呆
 * @desciption: @Configuration 加入 该注解后 全局有效 , 替换 SpringDecoder 没有 局部引用也会生效
 * @since 2023/4/23 23:27
 */

public class CustomDecoderConfig extends AbstractCustomDecoder<FeignResponse> {

	protected CustomDecoderConfig(ObjectMapper objectMapper) {
		super(objectMapper);
	}

	@Override
	protected Supplier getData(FeignResponse obj) {
		return obj::getData;
	}

	@Override
	protected Supplier<String> getCode(FeignResponse obj) {
		return obj::getCode;
	}

	@Override
	protected Supplier<String> getMes(FeignResponse obj) {
		return obj::getMsg;
	}

	@Override
	protected boolean isSuccess(FeignResponse obj) {
		return obj.isSuccess();
	}

	@Override
	protected void fillTargetClazz(Set<Class> clazzSet) {
		clazzSet.add(Result.class);
	}

}

package com.itheima.feign;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.common.entry.FeignResponse;
import com.itheima.common.entry.Result;
import feign.codec.Decoder;
import feign.optionals.OptionalDecoder;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Set;
import java.util.function.Supplier;

/**
 * @author 阿呆
 * @desciption: @Configuration 加入 该注解后 全局有效 , 替换 SpringDecoder 没有 局部引用也会生效
 * @since 2023/4/23 23:27
 */
@Configuration
public class FeignClientCustomDecoderConfig {

	@Bean
	public Decoder decoder(ObjectMapper objectMapper) {
		// 方法入口:feign.InvocationContext , 默认执行链: ResponseEntityDecoder、OptionalDecoder、SpringDecoder
		return new ResponseEntityDecoder(
				new OptionalDecoder(
						new CustomDecoderConfig(objectMapper)
				)
		);
	}
}

局部、全价有效

全价有效,FeignClientCustomDecoderConfig需要配置@Configuration 进行标记,局部有效则去掉。没有配置的默认使用SpringDecoder 进行解码

package com.itheima.client;

import com.itheima.common.entry.FeignResponse;
import com.itheima.common.entry.User;
import com.itheima.feign.FeignClientCustomDecoderConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;

/**
 * 局部有效,FeignClientCustomDecoderConfig 不要注入bean , 不然会替换掉默认的SpringDecode 解码器
 * value 服务名称   contextId  bean名称 
 */
@FeignClient(value = "nacos-client-feign", contextId = "nacosClientFeignWrapper", configuration = FeignClientCustomDecoderConfig.class)
public interface NacosClientFeignWrapper {


    @RequestMapping("/findWrapUsers")
    List<User> findWrapUsers(@RequestBody User user);


    @RequestMapping("/updateWrapperUser")
    User updateWrapperUser(@RequestBody User user);


    @RequestMapping("/findWrapUsers")
    FeignResponse<List<User>> findWrapUsers2(@RequestBody User user);


    @RequestMapping("/updateWrapperUser")
    FeignResponse<User> updateWrapperUser2(@RequestBody User user);


    @RequestMapping("/handlerError")
    FeignResponse<User> handlerError(@RequestBody User user);

}

Feign接口编写,继承实现方式

package com.itheima.client;

import com.itheima.common.entry.FeignResponse;
import com.itheima.common.entry.User;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

# 共有类

/**
 * @author 阿呆
 * @desciption:
 * @since 2024/10/26 20:26
 */
public interface UserWebApi {


	@RequestMapping("/user/findWrapUsers")
	List<User> findWrapUsers(@RequestBody User user);


	@RequestMapping("/user/updateWrapperUser")
	User updateWrapperUser(@RequestBody User user);


	@RequestMapping("/user/findWrapUsers")
	FeignResponse<List<User>> findWrapUsers2(@RequestBody User user);


	@RequestMapping("/user/updateWrapperUser")
	FeignResponse<User> updateWrapperUser2(@RequestBody User user);


	@RequestMapping("/user/handlerError")
	FeignResponse<User> handlerError(@RequestBody User user);

}


# 调用方 实现接口

package com.itheima.client;

import com.itheima.feign.FeignClientCustomDecoderConfig;
import org.springframework.cloud.openfeign.FeignClient;

/**
 * @author 阿呆
 * @desciption:
 * @since 2024/10/26 20:27
 */
@FeignClient(value = "nacos-client-feign", contextId = "nacosClientFeignWrapper", configuration = FeignClientCustomDecoderConfig.class)
public interface UserFeignApi extends UserWebApi{

}


# 提供方服务器接口实现

package com.itheima.client;

import com.itheima.common.entry.FeignResponse;
import com.itheima.common.entry.User;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author 阿呆
 * @desciption:
 * @since 2024/10/26 20:28
 */
@RestController
public class UserController implements UserWebApi{

	@Override
	public List<User> findWrapUsers(User user) {
		return null;
	}

	@Override
	public User updateWrapperUser(User user) {
		return null;
	}

	@Override
	public FeignResponse<List<User>> findWrapUsers2(User user) {
		return null;
	}

	@Override
	public FeignResponse<User> updateWrapperUser2(User user) {
		return null;
	}

	@Override
	public FeignResponse<User> handlerError(User user) {
		return null;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值