OpenFeign使用Gson编解码时,针对日期时间类型的一些bean编解码不支持,可以通过自定义TypeAdapter来解决
自定义TypeAdapter
- ImprovedDateTypeAdapter
public class ImprovedDateTypeAdapter extends TypeAdapter<Date> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
@SuppressWarnings("unchecked")
TypeAdapter<T> typeAdapter = (TypeAdapter<T>) ((typeToken.getRawType() == Date.class) ? new ImprovedDateTypeAdapter()
: null);
return typeAdapter;
}
};
private final DateFormat enUsFormat;
private final DateFormat localFormat;
private final DateFormat iso8601Format;
private final DateFormat commonFormat;
private List<DateFormat> supportFmt = new ArrayList<>();
public ImprovedDateTypeAdapter() {
this.enUsFormat = DateFormat.getDateTimeInstance(2, 2, Locale.US);
this.localFormat = DateFormat.getDateTimeInstance(2, 2);
this.iso8601Format = buildIso8601Format();
this.commonFormat = buildCommonFormat();
supportFmt.add(commonFormat);
supportFmt.add(localFormat);
supportFmt.add(enUsFormat);
supportFmt.add(iso8601Format);
}
private static DateFormat buildCommonFormat() {
DateFormat commonFormat = new SimpleDateFormat(
DEFAULT_DATE_TIME_FORMAT, Locale.CHINA);
commonFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
return commonFormat;
}
private static DateFormat buildIso8601Format() {
DateFormat iso8601Format = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
return iso8601Format;
}
@Override
public Date read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return deserializeToDate(in.nextString());
}
private synchronized Date deserializeToDate(String json) {
boolean validFastTime = validFastTime(json);
if (validFastTime) {
return new Date(Long.parseLong(json));
}
for (DateFormat dateFormat : supportFmt) {
try {
return dateFormat.parse(json);
} catch (ParseException parseException) {
// try next fmt
}
}
throw new JsonSyntaxException(json);
}
private boolean validFastTime(String json) {
try {
long l = Long.parseLong(json);
return l >= 0;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public synchronized void write(JsonWriter out, Date value)
throws IOException {
if (value == null) {
out.nullValue();
return;
}
String dateFormatAsString = this.commonFormat.format(value);
out.value(dateFormatAsString);
}
}
- LocalDateTypeAdapter
public class LocalDateTypeAdapter extends TypeAdapter<LocalDate> {
@Override
public void write(JsonWriter out, LocalDate value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT);
String localDate = dateTimeFormatter.format(value);
out.value(localDate);
}
@Override
public LocalDate read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT);
return LocalDate.parse(in.nextString(), dateFormatter);
}
}
编解码器的配置
@Configuration
public class GsonConfig {
/**
* FeignClientsConfiguration
* FeignClientsRegistrar
* @return
*/
@Bean("customGsonDecoder")
public Decoder feignDecoder() {
return new GsonDecoder(cusTypeAdapters());
}
@Bean("customGsonEncoder")
public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
return new GsonEncoder(cusTypeAdapters());
}
public List<TypeAdapter<?>> cusTypeAdapters(){
List<TypeAdapter<?>> adapters = new ArrayList<>();
adapters.add(new ImprovedDateTypeAdapter());
adapters.add(new LocalDateTypeAdapter());
adapters.add(new LocalTimeTypeAdapter());
adapters.add(new LocalDateTimeTypeAdapter());
// todo add cus adapter s
return adapters;
}
}
PS
-
字段命名注意
NOT: aBoxLong --> aboxLong
PREFER: boxLong --> boxLong -
jackson 日期格式序列化+时区设置
spring:
jackson:
date-format: ‘yyyy/MM/dd HH:mm:ss’
time-zone: ‘GMT+8’ -
Feign (OKHTTP Client)发送POST请求报错
Content type application/octet-stream not supported
Feign (OKHTTP Client)尝试通过@Headers添加Content-Type无效
NOT: @Headers({“Content-Type: application/json”})
PREFER:
@PostMapping(value = "postForm", consumes = "application/x-www-form-urlencoded")
@PostMapping(value = "postJson", consumes = "application/json")
@PostMapping(value = "postJson", headers = {"ContentType=application/json"})
> Content-Type application/json;charset=UTF-8