1、简介
在使用feignclient来发送请求时,请求参数为LocalDate类型时,请求时url上的日期格式为yy-MM-dd。为什么会这样显示呢?
2、分析
feignclient请求参数处理时通过SpringMvcContract#processAnnotationsOnParameter在处理方法参数上的注解时,会根据请求参数得到对应的Expander,用于转为字符串。Expander接口定义为
public interface Expander {
String expand(Object var1);
}
对应处理代码为
@Override
protected boolean processAnnotationsOnParameter(MethodMetadata data,
Annotation[] annotations, int paramIndex) {
boolean isHttpAnnotation = false;
AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(
data, paramIndex);
Method method = processedMethods.get(data.configKey());
for (Annotation parameterAnnotation : annotations) {
AnnotatedParameterProcessor processor = annotatedArgumentProcessors
.get(parameterAnnotation.annotationType());
if (processor != null) {
Annotation processParameterAnnotation;
// synthesize, handling @AliasFor, while falling back to parameter name on
// missing String #value():
processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue(
parameterAnnotation, method, paramIndex);
isHttpAnnotation |= processor.processArgument(context,
processParameterAnnotation, method);
}
}
if (!isMultipartFormData(data) && isHttpAnnotation
&& data.indexToExpander().get(paramIndex) == null) {
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
if (conversionService.canConvert(typeDescriptor, STRING_TYPE_DESCRIPTOR)) {
Param.Expander expander = convertingExpanderFactory
.getExpander(typeDescriptor);
if (expander != null) {
data.indexToExpander().put(paramIndex, expander);
}
}
}
return isHttpAnnotation;
}
通过convertingExpanderFactory.getExpander(typeDescriptor)获取到参数对应TypeDescriptor的Expander。
convertingExpanderFactory是在什么时候初始化的呢?
是通过构造函数来初始化的。
在何处会调用这个构造函数呢?
在FeignClientsConfiguration文件中通过@Bean注解来调用的。
构造函数中的feignConversionService是什么时候构造的?
也是在FeignClientsConfiguration文件中通过@Bean注解来调用的,创建DefaultFormattingConversionService,如果有自定义FeignFormatterRegistrar,则会添加对应的Formatter。
FeignFormatterRegistrar是接口,继承自FormatterRegistrar接口。
通过以上分析,要实现自定义LocalDate到字符串的转换,可以自定义类实现FeignFormatterRegistrar。
3、解决方案
自定义类实现FeignFormatterRegistrar
@Component
public class LocalDateFeignFormatterRegistrar implements FeignFormatterRegistrar {
@Override
public void registerFormatters(FormatterRegistry registry) {
registry.addConverter(LocalDate.class, String.class, new Converter<LocalDate, String>() {
@Override
public String convert(LocalDate source) {
return LocalDateTimeUtil.format(source, DatePattern.NORM_DATETIME_PATTERN);
}
});
}
}