SpringMVC 之 自定义Body参数解析
此方式仅仅对 @RequestBody 方式的请求生效,对 parame 方式传参并不生效(?key=value&key=value),比如 Get 请求
GET 请求参数配置请参考:
Java8 时间自定义系列化 与 反系列化:
public class Java8TimeModule extends SimpleModule { public Java8TimeModule() { super(PackageVersion.VERSION); // ======================= 时间序列化规则 =============================== // yyyy-MM-dd HH:mm:ss this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); // yyyy-MM-dd this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); // HH:mm:ss this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); // ======================= 时间反序列化规则 ============================== // yyyy-MM-dd HH:mm:ss this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); // yyyy-MM-dd this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); // HH:mm:ss this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); } }
将自定义的系列化规则配置到服务中:(本文页底和自定义枚举系列化一起)
自定义枚举系列化:
1、抽象约束枚举接口:
@JsonDeserialize(using = IEnumDeserializer.class) public interface IEnumextends Serializable> extends Serializable { IRuntimeException EXCEPTION = new IRuntimeException("操作不允许"); /** * 获取枚举编码 * @return */ int getCode(); /** * 获取枚举值 * @return */ default T getValue() { throw EXCEPTION; } /** * 获取枚举名称 * @return */ default String getName() { return this.name(); } /** * 获取枚举名称 * @return */ String name(); /** * 根据枚举名称获取枚举对象 * @param clazz * @param name * @param * @return */ @SneakyThrows staticextends Enum & IEnum> E sourceOf(Class clazz, String name) { Method valuesMethod = clazz.getMethod("values"); E[] enumInstanceArr = (E[]) valuesMethod.invoke(null); for (E enumInstance : enumInstanceArr) { if (Objects.equals(enumInstance.name(), name)) { return enumInstance; } } throw ExceptionUtil.create(IRuntimeException.class, ErrorResult.PARAMETER_ERROR); } /** * 根据编码获取枚举对象 * @param clazz * @param code * @param * @return */ @SneakyThrows staticextends Enum & IEnum> E codeOf(Class clazz, int code) { Method valuesMethod = clazz.getMethod("values"); E[] enumInstanceArr = (E[]) valuesMethod.invoke(null); for (E enumInstance : enumInstanceArr) { if (code == enumInstance.getCode()) { return enumInstance; } } throw ExceptionUtil.create(IRuntimeException.class, ErrorResult.PARAMETER_ERROR); } }
具体枚举类:
public enum SexEnum implements IEnum{ /** * 男性 */ MALE(1, "男"), /** * 女性 */ FEMALE(2, "女"), /** * 未知 */ UNKNOWN(3, "未知"); /** * 枚举编码 */ @EnumValue private int code; /** * 枚举值 */ private String value; }
手动编写反系列化器(根据自己的业务需求自行编写逻辑)
public class IEnumDeserializer extends JsonDeserializer{ @Override public IEnum deserialize(JsonParser jp, DeserializationContext deserializationContext) throws IOException { JsonNode node = jp.getCodec().readTree(jp); String currentName = jp.currentName(); Object currentValue = jp.getCurrentValue(); @SuppressWarnings("rawtypes") Class enumClazz = BeanUtils.findPropertyType(currentName, currentValue.getClass()); IEnum iEnum; if (node instanceof IntNode) { // 当客户端传值为枚举的 code 的值得时候 iEnum = (IEnum) IEnum.codeOf(enumClazz, node.asInt()); } else if (node instanceof TextNode) { // 当客户端传值为 枚举的 name 时候 iEnum = (IEnum) IEnum.sourceOf(enumClazz, node.asText()); } else { // 若传参的是枚举对象时, JsonNode 为 ObjectNode 类,枚举对象的数据放在一个 LinkedHashMap 中,只需要从 Map 中读取出 name 即可 iEnum = (IEnum) IEnum.sourceOf(enumClazz, node.get("name").asText()); } return iEnum; } }
将反系列化器注册:
public class IEnumModule extends SimpleModule { public IEnumModule() { super(PackageVersion.VERSION); // 自定义通用枚举类反系列化处理 this.addDeserializer(IEnum.class, new IEnumDeserializer()); } }
转换器配置注册(注册方式二选一即可)
1、不推荐
public class IEnumDeserializerConfig implements ApplicationListener{ private boolean isExecute = true; @Override public void onApplicationEvent(ContextRefreshedEvent event) { if (isExecute) { ApplicationContext applicationContext = event.getApplicationContext(); //注册转换器 ObjectMapper bean = applicationContext.getBean(ObjectMapper.class); bean.registerModule(new IEnumModule()); } isExecute = false; } }
2、推荐:
@Configuration @ConditionalOnClass(ObjectMapper.class) @AutoConfigureBefore(JacksonAutoConfiguration.class) public class JacksonConfig { private static final String ASIA_SHANGHAI = "Asia/Shanghai"; /** * 处理 @RequestBody 方式传参的自定义转换 * java8 时间系列化/反系列化 */ @Bean @ConditionalOnMissingBean public Jackson2ObjectMapperBuilderCustomizer java8Customizer() { return (Jackson2ObjectMapperBuilder builder) -> { builder.locale(Locale.CHINA); builder.timeZone(TimeZone.getTimeZone(ASIA_SHANGHAI)); builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN); builder.modules(new Java8TimeModule(), new IEnumModule()); }; } }