Cette situation doit être traitée différemment lorsque l'heure est utilisée comme chaîne Json, car la couche inférieure du json frontal doit le pojo back-end utilise un outil Jackson de séquence Json (HttpMessageConverter
) ; lorsque la chaîne d'heure est transmise en tant que paramètre de requête normal, Converter
est utilisé pour la conversion, et il y a différences dans les méthodes de traitement entre les deux. HttpMessgeConverter
);而时间字符串作为普通请求参数传入时,转换用的是Converter
,两者在处理方式上是有区别。
实现 org.springframework.core.convert.converter.Converter
,自定义参数转换器,如下:
@Configuration public class DateConverterConfig { @Bean public Converter<String, LocalDate> localDateConverter() { return new Converter<String, LocalDate>() { @Override public LocalDate convert(String source) { return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd")); } }; } @Bean public Converter<String, LocalDateTime> localDateTimeConverter() { return new Converter<String, LocalDateTime>() { @Override public LocalDateTime convert(String source) { return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } }; } }
点评:以上两个bean会注入到spring mvc的参数解析器(好像叫做ParameterConversionService
),当传入的字符串要转为LocalDateTime类时,spring会调用该Converter对这个入参进行转换。
注意:关于自定义的参数转换器 Converter,这有个坑,若将上面匿名内部类的写法精简成lambda表达式的方式:
@Bean @ConditionalOnBean(name = "requestMappingHandlerAdapter") public Converter<String, LocalDate> localDateConverter() { return source -> LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)); }
当再次启动项目时会出现异常:
Caused by: java.lang.IllegalArgumentException: Unable to determine source type
and target typefor your Converter [com.example.demo126.config.MappingConverterAdapter$$Lambda2/817994751]; does the class parameterize those types?
是由于:
web项目启动注册requestMappingHandlerAdapter
的时候会初始化WebBindingInitializer
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
而ConfigurableWebBindingInitializer
需要FormattingConversionService,
而FormattingConversionService
会将所有的Converter
添加进来,添加的时候需要获取泛型信息:
@Override public void addFormatters(FormatterRegistry registry) { for (Converter<?, ?> converter : getBeansOfType(Converter.class)) { registry.addConverter(converter); } for (GenericConverter converter : getBeansOfType(GenericConverter.class)) { registry.addConverter(converter); } for (Formatter<?> formatter : getBeansOfType(Formatter.class)) { registry.addFormatter(formatter); } }
添加Converter.class 一般是通过接口获取两个泛型的具体类型
public ResolvableType as(Class<?> type) { if (this == NONE) { return NONE; } Class<?> resolved = resolve(); if (resolved == null || resolved == type) { return this; } for (ResolvableType interfaceType : getInterfaces()) { ResolvableType interfaceAsType = interfaceType.as(type); if (interfaceAsType != NONE) { return interfaceAsType; } } return getSuperType().as(type); }
Lambda表达式的接口是Converter,并不能得到具体的类型,既然如此,那解决办法:
最简单的方法就是不适用Lambda表达式,还使用匿名内部类,这样就不会存在上述问题
就是等requestMappingHandlerAdapterbean
注册完成之后再添加自己的converter就不会注册到FormattingConversionService
中
@Bean @ConditionalOnBean(name = "requestMappingHandlerAdapter") public Converter<String, LocalDateTime> localDateTimeConverter() { return source -> LocalDateTime.parse(source, DateTimeUtils.DEFAULT_FORMATTER); }
还可以对前端传递的string进行正则匹配,如yyyy-MM-dd HH:mm:ss、yyyy-MM-dd、 HH:mm:ss等,进行匹配。以适应多种场景。
@Component public class DateConverter implements Converter<String, Date> { @Override public Date convert(String value) { /** * 可对value进行正则匹配,支持日期、时间等多种类型转换 * 这里在匹配Date日期格式时直接使用了 hutool 为我们已经写好的解析工具类,这里就不重复造轮子了 * cn.hutool.core.date.DateUtil * @param value * @return */ return DateUtil.parse(value.trim()); } }
注:这里在匹配Date日期格式时直接使用了 hutool 为我们已经写好的解析工具类,这里就不重复造轮子了,下面的方法同样使用了该工具类,想要在自己的项目中使用该工具类也很简单,在项目pom文件中引入hutool的依赖就可以了,如下:
<!--hu tool 工具类--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.1.3</version> </dependency>
使用spring自带注解@DateTimeFormat(pattern = "yyyy-MM-dd")
,如下:
@DateTimeFormat(pattern = "yyyy-MM-dd") private Date startDate;
如果使用了自定义参数转化器,Spring会优先使用该方式进行处理,即Spring注解不生效。
@ControllerAdvice public class GlobalExceptionHandler { @InitBinder protected void initBinder(WebDataBinder binder) { binder.registerCustomEditor(LocalDate.class, new PropertyEditorSupport() { @Override public void setAsText(String text) throws IllegalArgumentException { setValue(LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd"))); } }); binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() { @Override public void setAsText(String text) throws IllegalArgumentException { setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); } }); binder.registerCustomEditor(LocalTime.class, new PropertyEditorSupport() { @Override public void setAsText(String text) throws IllegalArgumentException { setValue(LocalTime.parse(text, DateTimeFormatter.ofPattern("HH:mm:ss"))); } }); } }
从名字就可以看出来,这是在controller做环切(这里面还可以全局异常捕获),在参数进入handler之前进行转换;转换为我们相应的对象。
请求类型为:post,content-type=application/json
, 后台用@RequestBody
接收,默认接收及返回值格式为: yyyy-MM-dd HH:mm:ss
在application.propertities文件中增加如下内容:
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
支持(content-type=application/json)
请求中格式为 yyyy-MM-dd HH:mm:ss
的字符串,后台用@RequestBody
接收,及返回值date转为yyyy-MM-dd HH:mm:ss
格式string;
不支持(content-type=application/json
)请求中yyyy-MM-dd
等类型的字符串转为date
; 不支持java8
日期api
org.springframework.core.convert.converter.Converter
, un convertisseur de paramètres personnalisés, comme suit : #🎜🎜#@Configuration public class JacksonConfig { /** 默认日期时间格式 */ public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; /** 默认日期格式 */ public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; /** 默认时间格式 */ public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; @Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); // 忽略json字符串中不识别的属性 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 忽略无法转换的对象 objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); // PrettyPrinter 格式化输出 objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true); // NULL不参与序列化 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 指定时区 objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8:00")); // 日期类型字符串处理 objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT)); // java8日期日期处理 JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))); javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))); javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); objectMapper.registerModule(javaTimeModule); converter.setObjectMapper(objectMapper); return converter; } }
ParameterConversionService
), lorsque la chaîne entrante est convertie en classe LocalDateTime , Spring appellera le Converter pour convertir ce paramètre d'entrée. #🎜🎜##🎜🎜#Remarque : concernant le convertisseur de paramètres personnalisé Converter, il existe un piège si la classe interne anonyme ci-dessus est simplifiée en une expression lambda : #🎜🎜#rrreee#🎜🎜#Quand Une exception se produira lorsque. redémarrer le projet : #🎜🎜##🎜🎜#Causé par : java.lang.IllegalArgumentException : Impossible de déterminer le type de source#🎜🎜# est due à : #🎜🎜##🎜🎜#enregistrement de démarrage du projet Web requestMappingHandlerAdapter initialiseraet le type de cible.config.MappingConverterAdapter$$Lambda$522/817994751] ; la classe paramètre-t-elle ces types ?#🎜🎜#
WebBindingInitializer
#🎜🎜#rrreee#🎜🎜# et ConfigurableWebBindingInitializer
nécessite FormattingConversionService,
et FormattingConversionService code> ajoutera tous les <code>Converter
Lors de l'ajout, vous devez obtenir les informations génériques : #🎜🎜#rrreee#🎜🎜#Add Converter.class, en obtenez généralement deux via l'interface Le type spécifique de générique. #🎜🎜#rrreee#🎜🎜#L'interface de l'expression Lambda est Converter, et le type spécifique ne peut pas être obtenu dans ce cas, la solution : #🎜🎜#requestMappingHandlerAdapterbeanUne fois l'enregistrement terminé, si vous ajoutez votre propre convertisseur, il ne sera pas enregistré dans <code>FormattingConversionService
#🎜🎜#
@DateTimeFormat(pattern = "yyyy-MM-dd")
, comme suit : #🎜🎜#rrreee#🎜🎜#Si un convertisseur de paramètres personnalisé est utilisé, Spring l'utilisera Cette méthode est d'abord utilisée, c'est-à-dire que les annotations Spring ne prennent pas effet. #🎜🎜##🎜🎜#Utiliser ControllerAdvice avec initBinder#🎜🎜#rrreee#🎜🎜#Comme vous pouvez le voir d'après le nom, il s'agit d'une boucle coupée dans le contrôleur (la capture d'exception globale peut également être utilisée ici), avant le les paramètres entrent dans le gestionnaire Convert ; convertissent en notre objet correspondant. #🎜🎜##🎜🎜#Traitement global des paramètres d'entrée JSON et des valeurs de retour#🎜🎜##🎜🎜#Le type de requête est : post,content-type=application/json
, utilisez en arrière-plan que reçoit @RequestBody
, le format par défaut des valeurs de réception et de retour est : aaaa-MM-jj HH:mm:ss
#🎜🎜##🎜🎜#Modifier l'application. fichier yml#🎜🎜# #🎜🎜#Ajoutez le contenu suivant au fichier application.properties : #🎜🎜##🎜🎜#spring :#🎜🎜#Support
jackson :
format de date : aaaa- MM-jj HH:mm : ss
fuseau horaire : GMT+8#🎜🎜#
(content-type=application/json)
Le format dans la requête est aaaa-MM-jj La chaîne de HH:mm:ss
est reçue en arrière-plan à l'aide de @RequestBody
, et la date de la valeur de retour est convertie en aaaa-MM-jj HH:mm:ss code>Format de chaîne ; #🎜🎜##🎜🎜# ne prend pas en charge (<code>content-type=application/json
) les types de chaîne tels que aaaa-MM-jj dans la requête Convertir en date
; ne prend pas en charge la date java8
api
;#🎜🎜# #🎜🎜#Utilisation de la sérialisation et de la désérialisation JSON de Jackson# 🎜🎜 #rrreeeCe qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!