-
Notifications
You must be signed in to change notification settings - Fork 15.5k
Description
版本号:
3.2.0
问题描述:
org.jeecg.common.aspect.DictAspect 108行使用jackson对对象进行序列化报错,原因是没有处理joda-time类型的时间日期。
截图&代码:
org.jeecg.common.aspect.DictAspect:108 - json解析失败Java 8 date/time type java.time.LocalDateTime
not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.leapmotor.app.integration.model.UseDetail["createTime"])
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type java.time.LocalDateTime
not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.leapmotor.app.integration.model.UseDetail["createTime"])
处理方式
方式1【不建议】 org.jeecg.common.aspect.DictAspect ObjectMapper进行配置,代码如下:
private void parseDictText(Object result) {
if (result instanceof Result) {
if (((Result) result).getResult() instanceof IPage) {
List<JSONObject> items = new ArrayList<>();
//step.1 筛选出加了 Dict 注解的字段列表
List<Field> dictFieldList = new ArrayList<>();
// 字典数据列表, key = 字典code,value=数据列表
Map<String, List<String>> dataListMap = new HashMap<>(5);
//ObjectMapper是线程安全的,不要在for循环里重复创建!!!
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
mapper.registerModule(javaTimeModule);
for (Object record : ((IPage) ((Result) result).getResult()).getRecords()) {
String json = "{}";
try {
//解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
json = mapper.writeValueAsString(record);
} catch (JsonProcessingException e) {
log.error("json解析失败" + e.getMessage(), e);
}
//update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);
//update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
//update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
//for (Field field : record.getClass().getDeclaredFields()) {
// 遍历所有字段,把字典Code取出来,放到 map 里
for (Field field : oConvertUtils.getAllFields(record)) {
String value = item.getString(field.getName());
if (oConvertUtils.isEmpty(value)) {
continue;
}
//update-end--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
if (field.getAnnotation(Dict.class) != null) {
if (!dictFieldList.contains(field)) {
dictFieldList.add(field);
}
String code = field.getAnnotation(Dict.class).dicCode();
String text = field.getAnnotation(Dict.class).dicText();
String table = field.getAnnotation(Dict.class).dictTable();
List<String> dataList;
String dictCode = code;
if (!StringUtils.isEmpty(table)) {
dictCode = String.format("%s,%s,%s", table, text, code);
}
dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());
this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));
}
//date类型默认转换string格式化日期
if (CommonConstant.JAVA_UTIL_DATE.equals(field.getType().getName()) && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {
SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
}
}
items.add(item);
}
//step.2 调用翻译方法,一次性翻译
Map<String, List<DictModel>> translText = this.translateAllDict(dataListMap);
//step.3 将翻译结果填充到返回结果里
for (JSONObject record : items) {
for (Field field : dictFieldList) {
String code = field.getAnnotation(Dict.class).dicCode();
String text = field.getAnnotation(Dict.class).dicText();
String table = field.getAnnotation(Dict.class).dictTable();
String fieldDictCode = code;
if (!StringUtils.isEmpty(table)) {
fieldDictCode = String.format("%s,%s,%s", table, text, code);
}
String value = record.getString(field.getName());
if (oConvertUtils.isNotEmpty(value)) {
List<DictModel> dictModels = translText.get(fieldDictCode);
if (dictModels == null || dictModels.size() == 0) {
continue;
}
String textValue = this.translDictText(dictModels, value);
log.debug(" 字典Val : " + textValue);
log.debug(" __翻译字典字段__ " + field.getName() + CommonConstant.DICT_TEXT_SUFFIX + ": " + textValue);
// TODO-sun 测试输出,待删
log.debug(" ---- dictCode: " + fieldDictCode);
log.debug(" ---- value: " + value);
log.debug(" ----- text: " + textValue);
log.debug(" ---- dictModels: " + JSON.toJSONString(dictModels));
record.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);
}
}
}
((IPage) ((Result) result).getResult()).setRecords(items);
}
}
}
方式2【建议】,框架配置org.jeecg.config.WebMvcConfiguration中,去除Jackson2ObjectMapperBuilderCustomizer配置,新增如下全局ObjectMapper:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(objectMapper());
converters.add(jackson2HttpMessageConverter);
}
@Primary
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = JsonMapper.
builder()
.enable(JsonWriteFeature.WRITE_NUMBERS_AS_STRINGS)
.build();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
//设置获取json字段名的方式
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//处理失败
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, false);
//处理bigDecimal
objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
//默认的处理日期时间格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
objectMapper.registerModule(javaTimeModule);
return objectMapper;
}
之后,重构所有使用ObjectMapper的类,将new方式创建改为注入全局ObjectMapper的方式,或者,将上面配置的objectMapper作为单例进行构建,可以直接获取单例,这样,整个框架将使用同一个objectmapper,提高可维护性和统一性
Activity
accpman commentedon May 31, 2022
已修改,待下个版本