国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

深圳網(wǎng)站品牌建設(shè)seo關(guān)鍵詞排名優(yōu)化

深圳網(wǎng)站品牌建設(shè),seo關(guān)鍵詞排名優(yōu)化,怎么做app平臺(tái),外包公司是什么介紹本文介紹在項(xiàng)目中時(shí)間類型、枚舉類型的序列化和反序列化自定義的處理類,也可以使用注解。建議枚舉都實(shí)現(xiàn)一個(gè)統(tǒng)一的接口,方便處理。我這定義了一個(gè)Dict接口。枚舉類型注解處理這種方式比較靈活,可以讓枚舉按照自己的方式序列化&#xff0…

介紹

本文介紹在項(xiàng)目中時(shí)間類型、枚舉類型的序列化和反序列化自定義的處理類,也可以使用注解。

建議枚舉都實(shí)現(xiàn)一個(gè)統(tǒng)一的接口,方便處理。我這定義了一個(gè)Dict接口。

枚舉類型注解處理

這種方式比較靈活,可以讓枚舉按照自己的方式序列化,可以序列化code值(推薦),也可以序列化對(duì)象。序列化為對(duì)象:對(duì)于前端來說是比較好的,前端接收到code值和中文label,頁(yè)面顯示label就行了,但是對(duì)于后端,服務(wù)之間調(diào)用,使用feign調(diào)用的時(shí)候,序列化為對(duì)象,被調(diào)用服務(wù)的controller層就接收不到這個(gè)枚舉值了,因?yàn)榻邮盏氖敲杜e序列化的對(duì)象,無法反序列化成枚舉對(duì)象了。除非使用自定義反序列加判斷去處理,比較麻煩。參考改進(jìn)枚舉工具類

定義統(tǒng)一枚舉接口

package com.common.interfaces;public interface Dict {String name();default Integer getCode() {return null;}default String getLabel() {return null;}
}

序列化code值

枚舉代碼

package com.common.enums.app;import com.baomidou.mybatisplus.annotation.EnumValue;
import com.common.interfaces.Dict;
import lombok.AllArgsConstructor;
import lombok.Getter;@Getter
@AllArgsConstructor
public enum DeliverDateModelEnum implements Dict {SAME(0, "相同時(shí)間"),DIFFERENT(2, "不同時(shí)間"),;// mybatis的處理注解                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  @EnumValue// Jackson的序列化處理注解;序列化code值@JsonValueprivate final Integer code;private final String label;}
package com.common.enums.order;import com.common.exception.E;
import com.common.interfaces.Dict;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.AllArgsConstructor;
import lombok.Getter;import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;/*** 訂單采購(gòu)方式枚舉*/
@Getter
@AllArgsConstructor
public enum OrderPurchaseMethodEnum implements Dict {INQUIRY("詢價(jià)"),MALL("商城"),;private String label;private static final Map<String, OrderPurchaseMethodEnum> MAP =Arrays.stream(OrderPurchaseMethodEnum.values()).collect(Collectors.toMap(Enum::name, e -> e));@JsonCreator(mode = JsonCreator.Mode.DELEGATING)public static OrderPurchaseMethodEnum resolve(String code) {if (!MAP.containsKey(code)) {throw new Exception("枚舉類型錯(cuò)誤");}return MAP.get(code);}
}

實(shí)體類

package com.app.dto;import com.common.enums.apply.DeliverDateModelEnum;
import com.common.enums.order.OrderPurchaseMethodEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;@Data
@EqualsAndHashCode(callSuper = false)
public class ApplyInfoDTO2 implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty(value = "主鍵")private Long id;@ApiModelProperty(value = "標(biāo)題", required = true)private String title;@NotNull(message = "時(shí)間方式不能為空")private DeliverDateModelEnum deliverDateModel;// 后期會(huì)用到private OrderPurchaseMethodEnum purchaseMethod;}

測(cè)試代碼

@RestController
@Slf4j
@RequestMapping("/api/test")
public class TestController2 {@PostMapping(value = "/hh")public ApplyInfoDTO2 test9(@RequestBody ApplyInfoDTO2 applyInfoDTO) {System.out.println("hhhhh");applyInfoDTO.setId(55L);System.out.println("----"+ JacksonUtils.toJson(applyInfoDTO));return applyInfoDTO;}
}
請(qǐng)求參數(shù)
{"id":11,"title": "dajf","deliverDateModel":2
}響應(yīng)結(jié)果
{"id": 55,"title": "dajf","deliverDateModel": 2,"purchaseMethod": null
}

序列化對(duì)象

這里只改枚舉就可以了

package com.common.enums.app;import com.baomidou.mybatisplus.annotation.EnumValue;
import com.common.interfaces.Dict;
import lombok.AllArgsConstructor;
import lombok.Getter;@Getter
@AllArgsConstructor
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum DeliverDateModelEnum implements Dict {SAME(0, "相同時(shí)間"),DIFFERENT(2, "不同時(shí)間"),;// mybatis的處理注解@EnumValue// 由于上邊注解標(biāo)記序列化為對(duì)象了,這就不起作用了,可以注掉// @JsonValueprivate final Integer code;private final String label;}

結(jié)果

請(qǐng)求參數(shù)
{"id":11,"title": "dajf","deliverDateModel":0
}響應(yīng)結(jié)果
{"id": 55,"title": "dajf","deliverDateModel": {"code": 0,"label": "相同時(shí)間"},"purchaseMethod": null
}

反序列化處理

這就是說,前端傳code值0,后端可以對(duì)應(yīng)到枚舉字段上,默認(rèn)的是使用下標(biāo)ordinal來反序列化的,按照0,1,2,3...去對(duì)應(yīng)上,如果中跳過了,接收值的時(shí)候就會(huì)報(bào)錯(cuò)。比如上邊的枚舉類DeliverDateModelEnum,傳0不會(huì)報(bào)錯(cuò),傳2就找不到了,錯(cuò)誤如下,

Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `com.common.enums.apply.DeliverDateModelEnum` from number 2: index value outside legal index range [0..1]at [Source: (PushbackInputStream); line: 4, column: 21] (through reference chain: com.cnpc.app.dto.ApplyInfoDTO2["deliverDateModel"])

解決方案:在枚舉類加反序列化處理代碼@JsonCreator

package com.common.enums.app;import com.baomidou.mybatisplus.annotation.EnumValue;
import com.common.interfaces.Dict;
import lombok.AllArgsConstructor;
import lombok.Getter;@Getter
@AllArgsConstructor
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum DeliverDateModelEnum implements Dict {SAME(0, "相同時(shí)間"),DIFFERENT(2, "不同時(shí)間"),;// mybatis的處理注解                      @EnumValue// 由于上邊注解標(biāo)記序列化為對(duì)象了,這就不起作用了,可以注掉// @JsonValueprivate final Integer code;private final String label;private static final Map<Integer, DeliverDateModelEnum> map =Arrays.stream(DeliverDateModelEnum.values()).collect(Collectors.toMap(DeliverDateModelEnum::getCode, e -> e));@JsonCreator(mode = JsonCreator.Mode.DELEGATING)public static DeliverDateModelEnum resolve(Integer code) {if (!map.containsKey(code)) {throw new E("找不到枚舉");}return map.get(code);}}

以上就是注解的枚舉處理方法,統(tǒng)一定義接口后,為了前端可以通過code值展示枚舉中午label,所以又寫了一個(gè)字典解析類,將所以實(shí)現(xiàn)Dict接口的枚舉,都拿到,然后解析存儲(chǔ),再給前端提供一個(gè)請(qǐng)求路徑。前端存儲(chǔ)起來,去解析,退出的時(shí)候,可以清除前端緩存。

將枚舉轉(zhuǎn)字典存儲(chǔ)

package com.dict.service;import com.common.annotation.DictType;
import com.common.exception.E;
import com.common.interfaces.Dict;
import com.dict.vo.DictItemVO;
import com.dict.vo.DictVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.reflections.Reflections;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;/*** 系統(tǒng)字典Service*/
@Slf4j
@Component
public class SystemDictService {/*** 反射要掃描的包路徑*/@Value("${dict.scanPath:com.company}")private String scanPath;/*** 字典集合*/private static Set<DictVO> DICT_SET = new HashSet<>();/*** 提供給外部獲取字典集合的方法** @author sun*/public Set<DictVO> getDictSet() {return DICT_SET;}/*** 啟動(dòng)時(shí)掃描*/@PostConstructpublic void initDict() {DICT_SET = scanDict();}/*** 掃描字典列表*/private Set<DictVO> scanDict() {// 反射要掃描的包路徑Reflections reflections = new Reflections(scanPath);// 反射獲取所有實(shí)現(xiàn) DictInterface 接口的枚舉Set<Class<? extends Dict>> monitorClasses = reflections.getSubTypesOf(Dict.class);/** 封裝字典列表* 過濾掉不是枚舉的實(shí)現(xiàn)* 反射調(diào)用枚舉的 values 方法, 獲取每個(gè)枚舉內(nèi)部的值列表*/return monitorClasses.stream().filter(Class::isEnum).map(sub -> {DictVO vo = new DictVO();try {/* 這塊沒有使用到DictType annotation = sub.getAnnotation(DictType.class);if (Objects.nonNull(annotation) && Strings.isNotBlank(annotation.type())) {// 有DictType注解并且type不是空白時(shí)使用注解中的值作為字典的類別vo.setType(annotation.type());} else {// 否則使用類名作為字典的類別vo.setType(sub.getSimpleName());}*/Method valuesMethod = sub.getMethod("values");Object valuesObj = valuesMethod.invoke(sub);Dict[] values = (Dict[]) valuesObj;List<DictItemVO> collect = Arrays.stream(values).map(item -> {// code和label都可以沒有,全部以name為默認(rèn)String code = item.getCode() != null ? item.getCode().toString() : item.name();String label = item.getLabel() != null ? item.getLabel() : item.name();return new DictItemVO(code, label);}).collect(Collectors.toList());vo.setItems(collect);} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {log.error("{}", e.getMessage(), e);}return vo;})// 這里轉(zhuǎn)map是校驗(yàn)有沒有重復(fù)的type, 如果存在重復(fù)的會(huì)報(bào)錯(cuò).collect(Collectors.toMap(item -> item, item -> item, (a1, a2) -> {throw new E("字典類型:" + a1.getType() + ", 有重復(fù)");})).keySet();}}
// controller層提供外部訪問? ? 
@ApiOperation("系統(tǒng)字典列表查詢")@GetMapping(value = "/system")public R<Set<DictVO>> querySystemDict() {return R.of(systemDictService.getDictSet());}
package com.dict.vo;import lombok.Data;import java.util.List;
import java.util.Objects;/*** 字典VO**/
@Data
public class DictVO {/*** 字典類別名稱*/private String type;/*** 字典項(xiàng)列表*/private List<DictItemVO> items;@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (o == null || getClass() != o.getClass()) {return false;}DictVO dictVO = (DictVO) o;return Objects.equals(type, dictVO.type);}@Overridepublic int hashCode() {return Objects.hash(type);}
}
package com.dict.vo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 字典項(xiàng)*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DictItemVO {/*** 編碼*/private String code;/*** 標(biāo)簽*/private String label;}

自定義枚舉類型處理

由于上邊規(guī)定所有的枚舉都需要實(shí)現(xiàn)Dict接口,下面的反序列化只針對(duì)符合條件的處理

處理工具類

package com.common.config;import com.common.interfaces.Dict;import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;/*** 枚舉匹配工具類*/
public class EnumUtil {private static final Map<Class<? extends Enum<?>>, Map<Integer, ? extends Enum<? extends Dict>>> CLASS_ENUM_MAP =new ConcurrentHashMap<>(16);@SuppressWarnings("unchecked")public static <E extends Enum<E> & Dict> E match(Class<E> enumClass, Integer type) {Map enumMap = CLASS_ENUM_MAP.get(enumClass);if (Objects.isNull(enumMap)) {// Map<Integer, ? extends Enum<? extends Dict>> unmodifiableMap = Arrays.stream(enumClass.getEnumConstants())// 這種表達(dá)式寫法會(huì)報(bào)錯(cuò)//       .collect(Collectors.toMap(Dict::getCode, v -> v));Map<Integer, ? extends Enum<? extends Dict>> unmodifiableMap = Arrays.stream(enumClass.getEnumConstants()).collect(Collectors.toMap(obj -> obj.getCode(), v -> v));CLASS_ENUM_MAP.putIfAbsent(enumClass, unmodifiableMap);return (E) unmodifiableMap.get(type);}return (E) enumMap.get(type);}
}

自定義的反序列化類

package com.common.config;import com.common.interfaces.Dict;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;import java.io.IOException;/*** 枚舉反序列化器*/
public class DictEnumDeserializer extends StdDeserializer<Dict> implements ContextualDeserializer {public DictEnumDeserializer() {super((JavaType) null);}public DictEnumDeserializer(JavaType valueType) {super(valueType);}@Overridepublic JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {return new DictEnumDeserializer(property.getType());}@Override@SuppressWarnings("all")public Dict deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {return (Dict) EnumUtil.match((Class) _valueClass, p.getIntValue());}
}

注入到spring中

注入方式1

由于項(xiàng)目中還配置有時(shí)間的序列化所以就把它們放一起了。建議使用的,把所有的序列化反序列化的都放這。

package com.cnpc.common.config;import com.common.interfaces.Dict;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.ClassKey;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;/*** LocalDateTime配置*/
@Configuration
// public class LocalDateTimeFormatConfig { 改了一個(gè)名字
public class WebCustomerConfig {private static final String DEFAULT_DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";private static final String DEFAULT_TIME_PATTERN = "HH:mm:ss";// 這里加@Primary,在項(xiàng)目啟動(dòng)的時(shí)候一共會(huì)加載12個(gè)convert,第7個(gè)是MappingJackson2HttpMessageConverter
// 處理json映射對(duì)象參數(shù)的類,會(huì)采用這個(gè)ObjectMapper,默認(rèn)的是 new ObjectMapper();這里自己增加了一些序列化處理的方法@Bean@Primarypublic ObjectMapper objectMapper() {ObjectMapper objectMapper = new ObjectMapper();// 注冊(cè)時(shí)間的序列化和反序列化處理JavaTimeModule javaTimeModule = new JavaTimeModule();javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_PATTERN)));javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN)));javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN)));javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_PATTERN)));javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN)));javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_PATTERN)));objectMapper.registerModule(javaTimeModule);//忽略識(shí)別不了的屬性objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 注冊(cè)枚舉的處理序列化和反序列的方式SimpleModule sm = new SimpleModule();//自定義查找規(guī)則sm.setDeserializers(new SimpleDeserializers() {@Overridepublic JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config,BeanDescription beanDesc) throws JsonMappingException {JsonDeserializer enumDeserializer = super.findEnumDeserializer(type, config, beanDesc);if (enumDeserializer != null) {return enumDeserializer;}//遍歷枚舉實(shí)現(xiàn)的接口, 查找反序列化器for (Class typeInterface : type.getInterfaces()) {// 如果實(shí)現(xiàn)了Dict接口但是沒有code值的就返回null,如果項(xiàng)目比較規(guī)范都有code值,或者沒有code值的,沒有實(shí)現(xiàn)Dict接口,可以去掉下面這個(gè)代碼if (typeInterface.equals(Dict.class) ){Dict[] enumConstants = (Dict[]) type.getEnumConstants();if (Objects.isNull(enumConstants[0].getCode())) {return null;}}enumDeserializer = this._classMappings.get(new ClassKey(typeInterface));if (enumDeserializer != null) {return enumDeserializer;}}return null;}});sm.addDeserializer(Dict.class, new TypeEnumDeserializer());// 增加枚舉的序列化方式sm.addSerializer(Dict.class, new JsonSerializer<Dict>() {@Overridepublic void serialize(Dict value, JsonGenerator gen, SerializerProvider serializers) throws IOException {// 相當(dāng)于在枚舉類上加 @JsonFormat(shape = JsonFormat.Shape.OBJECT);返給頁(yè)面的是一個(gè)對(duì)象code和label都返回
//                gen.writeStartObject();
//                gen.writeNumberField("code", value.getCode());
//                gen.writeStringField("label", value.getLabel());
//                gen.writeEndObject();// 相當(dāng)于在枚舉code字段上加 @JsonValue  返回給頁(yè)面一個(gè)code值gen.writeNumber(value.getCode());}@Overridepublic void serializeWithType(Dict value, JsonGenerator gen, SerializerProvider serializers,TypeSerializer typeSer) throws IOException {WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen, typeSer.typeId(value, JsonToken.VALUE_STRING));serialize(value, gen, serializers);typeSer.writeTypeSuffix(gen, typeIdDef);}});objectMapper.registerModule(sm);return objectMapper;}
}

注入方式2

下面這種注入會(huì)影響項(xiàng)目已經(jīng)有配置ObjectMapper的地方,建議都放一起。如果采用下面這種方式,需要自己創(chuàng)建一個(gè)MappingJackson2HttpMessageConverter,并將converter添加到list的第一個(gè),如果添加到最后一個(gè),他會(huì)先找list中前邊的MappingJackson2HttpMessageConverter,大約是第7個(gè)位置,就不會(huì)用自己寫的。

package com.common.config;import com.common.interfaces.Dict;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.ClassKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;/*** 裝載枚舉序列化器*/
@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();converter.setObjectMapper(objectMapperForWebConvert());converters.add(0, stringHttpMessageConverter);// 將這個(gè)MappingJackson2HttpMessageConverter添加到第一個(gè),是為了優(yōu)先找到,否則就有其他MappingJackson2HttpMessageConverter去處理了converters.add(0, converter);}// 這個(gè)沒有時(shí)間的處理配置。public ObjectMapper objectMapperForWebConvert() {ObjectMapper om = new ObjectMapper();om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);SimpleModule sm = new SimpleModule();//自定義查找規(guī)則sm.setDeserializers(new SimpleDeserializers() {@Overridepublic JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config,BeanDescription beanDesc) throws JsonMappingException {JsonDeserializer enumDeserializer = super.findEnumDeserializer(type, config, beanDesc);if (enumDeserializer != null) {return enumDeserializer;}//遍歷枚舉實(shí)現(xiàn)的接口, 查找反序列化器for (Class typeInterface : type.getInterfaces()) {// 如果實(shí)現(xiàn)了Dict接口但是沒有code值的就返回null,如果項(xiàng)目比較規(guī)范都有code值,或者沒有code值的,沒有實(shí)現(xiàn)Dict接口,可以去掉下面這個(gè)代碼if (typeInterface.equals(Dict.class)){Dict[] enumConstants = (Dict[]) type.getEnumConstants();if (Objects.isNull(enumConstants[0].getCode())) {return null;}}// 這里的classKey不要導(dǎo)錯(cuò)包,必須是com.fasterxml.jackson.databind.type.ClassKey,否則會(huì)找不到,導(dǎo)致自定義的反序列化類不起作用enumDeserializer = this._classMappings.get(new ClassKey(typeInterface));if (enumDeserializer != null) {return enumDeserializer;}// 上邊的ClassKey導(dǎo)入包錯(cuò)誤,找不到臨時(shí)加的
//                    if (typeInterface.equals(Dict.class)){
//                        return new DictEnumDeserializer();
//                    }//                    return new DictEnumDeserializer();}return null;}});// 添加枚舉反序列化處理器sm.addDeserializer(Dict.class, new DictEnumDeserializer());sm.addSerializer(Dict.class, new JsonSerializer<Dict>() {@Overridepublic void serialize(Dict value, JsonGenerator gen, SerializerProvider serializers) throws IOException {// 相當(dāng)于在枚舉類上加 @JsonFormat(shape = JsonFormat.Shape.OBJECT);返給頁(yè)面的是一個(gè)對(duì)象code和label都返回
//                gen.writeStartObject();
//                gen.writeNumberField("code", value.getCode());
//                gen.writeStringField("label", value.getLabel());
//                gen.writeEndObject();// 相當(dāng)于在枚舉code字段上加 @JsonValue  返回給頁(yè)面一個(gè)code值gen.writeNumber(value.getCode());}@Overridepublic void serializeWithType(Dict value, JsonGenerator gen, SerializerProvider serializers,TypeSerializer typeSer) throws IOException {WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen, typeSer.typeId(value, JsonToken.VALUE_STRING));serialize(value, gen, serializers);typeSer.writeTypeSuffix(gen, typeIdDef);}});om.registerModule(sm);return om;}
}

這樣就可以測(cè)試了。沒有實(shí)現(xiàn)Dict接口的枚舉會(huì)采用下一個(gè)MappingJackson2HttpMessageConverter的new ObjectMapper()去處理,按照默認(rèn)的去處理

斷點(diǎn)測(cè)試

第一次賦值

加載自定義的ObjectMapper

現(xiàn)在converter變成了14個(gè)了,因?yàn)檫@是注入方式2,自己往里面放了2個(gè),

請(qǐng)求訪問時(shí),斷點(diǎn)

org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(org.springframework.http.HttpInputMessage, org.springframework.core.MethodParameter, java.lang.reflect.Type)

注入方式1斷點(diǎn)測(cè)試

啟動(dòng)過程中會(huì)放入2個(gè)MappingJackson,會(huì)看到第7個(gè)下移到第8個(gè)了

注入方式2斷點(diǎn)測(cè)試

第一次啟動(dòng)地址是15536

走到自己寫的枚舉處理

改進(jìn)枚舉工具類

改進(jìn)之后,即可已返回給前端枚舉對(duì)象,也可以接收對(duì)象類型的,也可以接收數(shù)值,也可以接收字符串

package com.common.config;import com.common.interfaces.Dict;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;import java.io.IOException;/*** 枚舉反序列化器*/
public class DictEnumDeserializer extends StdDeserializer<Dict> implements ContextualDeserializer {public DictEnumDeserializer() {super((JavaType) null);}public DictEnumDeserializer(JavaType valueType) {super(valueType);}@Overridepublic JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {return new DictEnumDeserializer(property.getType());}// 自定義的反序列化器這個(gè)方法,需要傳JsonParser@Override@SuppressWarnings("all")public Dict deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {return (Dict) EnumUtil.match((Class) _valueClass, p);}
}
package com.common.config;import com.common.interfaces.Dict;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;/*** 枚舉匹配工具類
* 改進(jìn)的枚舉工具*/
public class EnumUtil {private static final Map<Class<? extends Enum<?>>, Map<Integer, ? extends Enum<? extends Dict>>> CLASS_ENUM_MAP =new ConcurrentHashMap<>(16);@SuppressWarnings("unchecked")public static <E extends Enum<E> & Dict> E match(Class<E> enumClass, JsonParser jsonParser) throws IOException {Integer code = null;// 接收數(shù)值型的if (jsonParser.currentToken() == JsonToken.VALUE_NUMBER_INT){code = jsonParser.getValueAsInt();// 接收OBJECT類型的參數(shù)} else if (jsonParser.currentToken() == JsonToken.START_OBJECT){while (jsonParser.nextToken() != JsonToken.END_OBJECT) {String fieldname = jsonParser.getCurrentName();if ("code".equals(fieldname)) {jsonParser.nextToken();code = jsonParser.getValueAsInt();break;}}// 接收字符串類型的,需要判斷是純數(shù)字}else  if (jsonParser.currentToken() == JsonToken.VALUE_STRING){String codestr = jsonParser.getValueAsString();if (codestr.matches("^[0-9]*$")) {code = Integer.valueOf(codestr);}}if (Objects.isNull(code)){throw new RuntimeException("沒有code找不到對(duì)應(yīng)的枚舉");}return getDictEnum(enumClass, code);}private static <E extends Enum<E> & Dict> E getDictEnum(Class<E> enumClass, Integer type) {Map enumMap = CLASS_ENUM_MAP.get(enumClass);if (Objects.isNull(enumMap)) {Map<Integer, ? extends Enum<? extends Dict>> unmodifiableMap = Arrays.stream(enumClass.getEnumConstants()).collect(Collectors.toMap(obj -> obj.getCode(), v -> v));CLASS_ENUM_MAP.putIfAbsent(enumClass, unmodifiableMap);E e = (E) unmodifiableMap.get(code);if (Objects.isNull(e)){throw new RuntimeException("指定類型code找不到對(duì)應(yīng)的枚舉code = " + code);}return e;}E e = (E) enumMap.get(code);if (Objects.isNull(e)){throw new RuntimeException("指定類型code找不到對(duì)應(yīng)的枚舉code = " + code);}return e;}// 原來的方法,只能接收數(shù)值code/*public static <E extends Enum<E> & Dict> E match(Class<E> enumClass, Integer type) {Map enumMap = CLASS_ENUM_MAP.get(enumClass);if (Objects.isNull(enumMap)) {Map<Integer, ? extends Enum<? extends Dict>> unmodifiableMap = Arrays.stream(enumClass.getEnumConstants()).collect(Collectors.toMap(Dict::getCode, v -> v));CLASS_ENUM_MAP.putIfAbsent(enumClass, unmodifiableMap);return (E) unmodifiableMap.get(type);}return (E) enumMap.get(type);}*/
}

參考文章

https://developer.aliyun.com/article/979501

http://events.jianshu.io/p/33e537ea6f10

JsonParser的處理

https://blog.csdn.net/band_mmbx/article/details/126749515

http://aloenet.com.cn/news/36099.html

相關(guān)文章:

  • 大連網(wǎng)站建設(shè)設(shè)計(jì)下載百度到桌面上
  • 深圳網(wǎng)站做的好的公司名稱長(zhǎng)春網(wǎng)站建設(shè)技術(shù)托管
  • 網(wǎng)站怎么做要多少錢寧德市教育局官網(wǎng)
  • 武漢網(wǎng)站優(yōu)化百度人工服務(wù)24小時(shí)熱線電話
  • 90設(shè)計(jì)網(wǎng)站怎么樣已備案域名購(gòu)買平臺(tái)
  • 阿里云建站是外包的嗎seo的基礎(chǔ)優(yōu)化
  • 怎么查看網(wǎng)站提交百度的度手機(jī)優(yōu)化助手下載
  • 建設(shè)哪里有百度seo按天計(jì)費(fèi)
  • 廈門快速建網(wǎng)站騰訊控股第三季度營(yíng)收1401億
  • 別人做的網(wǎng)站上海做關(guān)鍵詞推廣企業(yè)
  • 怎么做淘寶客網(wǎng)站賺錢百度指數(shù)官方
  • 網(wǎng)站黨組織規(guī)范化建設(shè)開展情況石家莊seo推廣優(yōu)化
  • 網(wǎng)站域名實(shí)名制市場(chǎng)調(diào)研報(bào)告怎么寫
  • 網(wǎng)站中英文互譯 java怎么做html網(wǎng)頁(yè)制作模板代碼
  • 做海外房產(chǎn)最好的網(wǎng)站關(guān)鍵詞搜索量排名
  • 祥云縣外賣哪個(gè)網(wǎng)站清遠(yuǎn)頭條新聞
  • 舉報(bào)個(gè)人備案網(wǎng)站做經(jīng)營(yíng)性創(chuàng)建站點(diǎn)的步驟
  • 網(wǎng)站規(guī)劃與開發(fā)設(shè)計(jì)汕頭網(wǎng)站建設(shè)技術(shù)外包
  • 網(wǎng)站如何建立品牌形象免費(fèi)開源網(wǎng)站
  • 怎么做網(wǎng)站信息合肥網(wǎng)站優(yōu)化搜索
  • 怎樣做網(wǎng)站策劃網(wǎng)站收錄免費(fèi)咨詢
  • ps個(gè)人網(wǎng)站抖音視頻seo霸屏
  • 空間網(wǎng)站湖北短視頻搜索seo
  • 衡水企業(yè)網(wǎng)站巨量關(guān)鍵詞搜索查詢
  • 網(wǎng)站制作報(bào)價(jià)明細(xì)表bt磁力狗
  • 超市網(wǎng)站模版網(wǎng)絡(luò)推廣培訓(xùn)班
  • 鄭州網(wǎng)站推廣排名公司浙江關(guān)鍵詞優(yōu)化
  • 萬(wàn)網(wǎng)網(wǎng)站建設(shè)購(gòu)買過程汽車推廣軟文
  • 怎么自己的電腦做網(wǎng)站服務(wù)器百度網(wǎng)站是什么
  • 阿里巴巴怎么做公司網(wǎng)站我為什么不建議年輕人做銷售