1.get请求参数比较多时候写param是很累的一种方式:
@GetMapping(value = "/fapi/v1/positionSide/dual") PositionSideResponse getPositionSide(@RequestHeader(value = "X-MBX-APIKEY") String apikey, @SpringQueryMap BaseRequest request);
使用 @SpringQueryMap 可以自动将对象转换为get参数拼接在url上
2.当实体对象中的熟悉需要排序时怎么办呢? 比如sign的参数必须放参数末尾这种情况?
这个时候需要我们自定义实现 BeanQueryMapEncoder 代码如下
import feign.Param;
import feign.QueryMapEncoder;
import feign.codec.EncodeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
public class CustomerBeanQueryMapEncoder implements QueryMapEncoder {
private final Map<Class<?>, CustomerBeanQueryMapEncoder.ObjectParamMetadata> classToMetadata =
new HashMap<>();
@Override
public Map<String, Object> encode(Object object) throws EncodeException {
try {
CustomerBeanQueryMapEncoder.ObjectParamMetadata metadata = getMetadata(object.getClass());
Map<String, Object> propertyNameToValue = new LinkedHashMap<>();
for (PropertyDescriptor pd : metadata.objectProperties) {
Method method = pd.getReadMethod();
Object value = method.invoke(object);
if (value != null && value != object) {
Param alias = method.getAnnotation(Param.class);
String name = alias != null ? alias.value() : pd.getName();
propertyNameToValue.put(name, value);
}
}
return propertyNameToValue;
} catch (IllegalAccessException | IntrospectionException | InvocationTargetException e) {
throw new EncodeException("Failure encoding object into query map", e);
}
}
private CustomerBeanQueryMapEncoder.ObjectParamMetadata getMetadata(Class<?> objectType) throws IntrospectionException {
CustomerBeanQueryMapEncoder.ObjectParamMetadata metadata = classToMetadata.get(objectType);
if (metadata == null) {
metadata = CustomerBeanQueryMapEncoder.ObjectParamMetadata.parseObjectType(objectType);
classToMetadata.put(objectType, metadata);
}
return metadata;
}
private static class ObjectParamMetadata {
private final List<PropertyDescriptor> objectProperties;
private ObjectParamMetadata(List<PropertyDescriptor> objectProperties) {
this.objectProperties = Collections.unmodifiableList(objectProperties);
}
private static CustomerBeanQueryMapEncoder.ObjectParamMetadata parseObjectType(Class<?> type)
throws IntrospectionException {
List<PropertyDescriptor> properties = new ArrayList<PropertyDescriptor>();
for (PropertyDescriptor pd : Introspector.getBeanInfo(type).getPropertyDescriptors()) {
boolean isGetterMethod = pd.getReadMethod() != null && !"class".equals(pd.getName());
if (isGetterMethod) {
properties.add(pd);
}
}
/**
* 实现排序
*/
properties = properties.stream().sorted(Comparator.comparing(x -> {
int orderValue = -1;
try {
Field field = type.getDeclaredField(x.getName());
Order orderAnno = field.getAnnotation(Order.class);
if (orderAnno != null) {
orderValue = orderAnno.value();
}
} catch (NoSuchFieldException e) {
log.error("NoSuchFieldException", e);
}
return orderValue;
})).collect(Collectors.toList());
return new CustomerBeanQueryMapEncoder.ObjectParamMetadata(properties);
}
}
}
然后对feign的queryMapEncoder赋值成我们的
import feign.Feign;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
/**
* @Description 替换解析queryMap的类为自定义map类
*/
@Bean
public Feign.Builder feignBuilder() {
return Feign.builder()
.queryMapEncoder(new CustomerBeanQueryMapEncoder())
.retryer(Retryer.NEVER_RETRY);
}
}
此时在实体对象的属性上标注Order即可实现Encode后字符串的排序
private Long recvWindow;
/**
* 下单时间戳
*/
private Long timestamp = System.currentTimeMillis();
/**
* 签名值
*/
@Order(value = Integer.MAX_VALUE)
private String signature;