最近、fegin を使用して呼び出しを行うときに、文字列を日付に変換するときに jackson がサポートしていない形式が多く、エラーが報告されるという問題が見つかりました。
エラーメッセージは次のとおりです。
feign.codec.DecodeException: Error while extracting response for type [com.inforun.common.core.domain.R<java.util.List<com.inforun.common.base.domain.TTaskTime>>] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "23:59:59": not a valid representation (error: Failed to parse Date value '23:59:59': Unparseable date: "23:59:59"); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "23:59:59": not a valid representation (error: Failed to parse Date value '23:59:59': Unparseable date: "23:59:59")
at [Source: (PushbackInputStream); line: 1, column: 82] (through reference chain: com.inforun.common.core.domain.R["data"]->java.util.ArrayList[0]->com.inforun.common.base.domain.TTaskTime["endTime"])
必要なのは時刻と日付だけであり、変換するときに機能しません。インターネットの情報を確認したところ、jackson は以下の型のみをサポートしていることがわかりました
"yyyy-MM-dd'T'HH:mm:ss.SSSZ";
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
"yyyy-MM-dd";
"EEE, dd MMM yyyy HH:mm:ss zzz";
long类型的时间戳
これらの型には明らかに私が渡した形式が含まれていないため、自分で解決策を見つけるしかありません。
1. アノテーションの解決策としては、単一のクラスにアノテーションを追加する方法がありますが、
この方法は少数にしか使えず、数が多い場合は一つずつ追加するのが面倒なので、この方法は使用しませんでした。
2. カスタム型コンバーターの方法
カスタムの時間型コンバーターを作成し、その時間型コンバーターを使用して必要な形式を変換できるため、注釈を 1 つずつ追加する必要がなく、より便利です。
import cn.hutool.core.date.DateUtil;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyDateFormat extends DateFormat {
private DateFormat dateFormat;
private SimpleDateFormat format1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
private SimpleDateFormat format2 = new SimpleDateFormat("yyy-MM-dd");
private SimpleDateFormat format3 = new SimpleDateFormat("HH:mm:ss");
public MyDateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
}
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
return dateFormat.format(date, toAppendTo, fieldPosition);
}
@Override
public Date parse(String source, ParsePosition pos) {
Date date = null;
try {
// 先按我的规则1来
date = format1.parse(source, pos);
} catch (Exception e) {
//方式1不行方式2
try {
date = format2.parse(source, pos);
} catch (Exception e1) {
//方式2不行方式3
try {
date = format3.parse(source, pos);
} catch (Exception e2) {
// 不行,那就按原先的规则吧
date = dateFormat.parse(source, pos);
}
}
}
return date;
} // 主要还是装饰这个方法
@Override
public Date parse(String source) throws ParseException {
Date date = null;
try {
//先按照自己的规则来,动态筛查
date = DateUtil.parse(source);
} catch (Exception e) {
// 不行,那就按原先的规则吧
date = dateFormat.parse(source);
}
return date;
} // 这里装饰clone方法的原因是因为clone方法在jackson中也有用到
@Override
public Object clone() {
Object format = dateFormat.clone();
return new MyDateFormat((DateFormat) format);
}
}
これはカスタム変換クラスです。実際、まだ単一の変換を使用しています。ここでは単一の変換に Hutool ツール クラスを使用しました。一般的に使用される時間タイプを自動的に識別できるため、手間を省くことができます。設定してみましょう。
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inforun.common.security.config.jackson.MyDateFormat;
import com.inforun.common.security.interceptor.HeaderInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.text.DateFormat;
public class WebMvcConfig implements WebMvcConfigurer
{
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
//添加此配置
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
converter.setObjectMapper(objectMapper);
DateFormat dateFormat = objectMapper.getDateFormat();
objectMapper.setDateFormat(new MyDateFormat(dateFormat));
return converter;
}
}
ここまで完了していても、再度変換する場合は問題ありませんので、ぜひ試してみてください。