如何在Spring中使用LocalDateTime RequestParam?我得到 "Failed to convert String to LocalDateTime"
How to use LocalDateTime RequestParam in Spring? I get "Failed to convert String to LocalDateTime"
我使用 Spring 启动并在 Maven 中包含 jackson-datatype-jsr310
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.7.3</version>
</dependency>
当我尝试使用 Java 8 Date/Time 类型的 RequestParam 时,
@GetMapping("/test")
public Page<User> get(
@RequestParam(value = "start", required = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start) {
//...
}
并用这个 URL:
进行测试
/test?start=2016-10-8T00:00
我收到以下错误:
{
"timestamp": 1477528408379,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
"message": "Failed to convert value of type [java.lang.String] to required type [java.time.LocalDateTime]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime] for value '2016-10-8T00:00'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2016-10-8T00:00]",
"path": "/test"
}
TL;DR - 您可以仅使用 @RequestParam
将其捕获为字符串,或者您可以让 Spring 将字符串另外解析为 java 日期/时间 class 也通过参数 @DateTimeFormat
。
@RequestParam
足以获取您在 = 符号后提供的日期,但是,它作为 String
进入方法。这就是它抛出强制转换异常的原因。
有几种方法可以实现:
- 自己解析日期,获取字符串形式的值。
@GetMapping("/test")
public Page<User> get(@RequestParam(value="start", required = false) String start){
//Create a DateTimeFormatter with your required format:
DateTimeFormatter dateTimeFormat =
new DateTimeFormatter(DateTimeFormatter.BASIC_ISO_DATE);
//Next parse the date from the @RequestParam, specifying the TO type as
a TemporalQuery:
LocalDateTime date = dateTimeFormat.parse(start, LocalDateTime::from);
//Do the rest of your code...
}
- 利用 Spring 自动解析和预期日期格式的能力:
@GetMapping("/test")
public void processDateTime(@RequestParam("start")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
LocalDateTime date) {
// The rest of your code (Spring already parsed the date).
}
我 运行 遇到了同样的问题并找到了我的解决方案 here(不使用注释)
...you must at least properly register a string to [LocalDateTime] Converter in
your context, so that Spring can use it to automatically do this for
you every time you give a String as input and expect a [LocalDateTime]. (A big
number of converters are already implemented by Spring and contained
in the core.convert.support package, but none involves a [LocalDateTime]
conversion)
所以在你的情况下你会这样做:
public class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {
public LocalDateTime convert(String source) {
DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
return LocalDateTime.parse(source, formatter);
}
}
然后只需注册您的 bean:
<bean class="com.mycompany.mypackage.StringToLocalDateTimeConverter"/>
有注释
将其添加到您的 ConversionService:
@Component
public class SomeAmazingConversionService extends GenericConversionService {
public SomeAmazingConversionService() {
addConverter(new StringToLocalDateTimeConverter());
}
}
最后,您将在 ConversionService 中使用@Autowire:
@Autowired
private SomeAmazingConversionService someAmazingConversionService;
您可以在此 site 上阅读有关使用 spring(和格式)进行转换的更多信息。请注意,它有大量广告,但我确实发现它是一个有用的网站,并且是该主题的一个很好的介绍。
你做的一切都是正确的:)。 Here is an example that shows exactly what you are doing. Just Annotate your RequestParam with @DateTimeFormat
. There is no need for special GenericConversionService
or manual conversion in the controller. This 博客 post 写了它。
@RestController
@RequestMapping("/api/datetime/")
final class DateTimeController {
@RequestMapping(value = "datetime", method = RequestMethod.POST)
public void processDateTime(@RequestParam("datetime")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateAndTime) {
//Do stuff
}
}
我猜你的格式有问题。在我的设置中一切正常。
就像我在评论中所说的那样,您也可以在签名方法中使用此解决方案:@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start
我找到了解决方法 here。
Spring/Spring Boot only supports the date/date-time format in BODY parameters.
以下配置class在QUERY STRING(请求参数)中添加对date/date-time的支持:
// Since Spring Framwork 5.0 & Java 8+
@Configuration
public class DateTimeFormatConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
分别是:
// Until Spring Framwork 4.+
@Configuration
public class DateTimeFormatConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
即使您将多个请求参数绑定到某些 class 也能正常工作(@DateTimeFormat
注释在这种情况下无能为力):
public class ReportRequest {
private LocalDate from;
private LocalDate to;
public LocalDate getFrom() {
return from;
}
public void setFrom(LocalDate from) {
this.from = from;
}
public LocalDate getTo() {
return to;
}
public void setTo(LocalDate to) {
this.to = to;
}
}
// ...
@GetMapping("/api/report")
public void getReport(ReportRequest request) {
// ...
以下适用于 Spring Boot 2.1.6:
控制器
@Slf4j
@RestController
public class RequestController {
@GetMapping
public String test(RequestParameter param) {
log.info("Called services with parameter: " + param);
LocalDateTime dateTime = param.getCreated().plus(10, ChronoUnit.YEARS);
LocalDate date = param.getCreatedDate().plus(10, ChronoUnit.YEARS);
String result = "DATE_TIME: " + dateTime + "<br /> DATE: " + date;
return result;
}
@PostMapping
public LocalDate post(@RequestBody PostBody body) {
log.info("Posted body: " + body);
return body.getDate().plus(10, ChronoUnit.YEARS);
}
}
Dto classes:
@Value
public class RequestParameter {
@DateTimeFormat(iso = DATE_TIME)
LocalDateTime created;
@DateTimeFormat(iso = DATE)
LocalDate createdDate;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostBody {
LocalDate date;
}
测试class:
@RunWith(SpringRunner.class)
@WebMvcTest(RequestController.class)
public class RequestControllerTest {
@Autowired MockMvc mvc;
@Autowired ObjectMapper mapper;
@Test
public void testWsCall() throws Exception {
String pDate = "2019-05-01";
String pDateTime = pDate + "T23:10:01";
String eDateTime = "2029-05-01T23:10:01";
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("")
.param("created", pDateTime)
.param("createdDate", pDate))
.andExpect(status().isOk())
.andReturn();
String payload = result.getResponse().getContentAsString();
assertThat(payload).contains(eDateTime);
}
@Test
public void testMapper() throws Exception {
String pDate = "2019-05-01";
String eDate = "2029-05-01";
String pDateTime = pDate + "T23:10:01";
String eDateTime = eDate + "T23:10:01";
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("")
.param("created", pDateTime)
.param("createdDate", pDate)
)
.andExpect(status().isOk())
.andReturn();
String payload = result.getResponse().getContentAsString();
assertThat(payload).contains(eDate).contains(eDateTime);
}
@Test
public void testPost() throws Exception {
LocalDate testDate = LocalDate.of(2015, Month.JANUARY, 1);
PostBody body = PostBody.builder().date(testDate).build();
String request = mapper.writeValueAsString(body);
MvcResult result = mvc.perform(MockMvcRequestBuilders.post("")
.content(request).contentType(APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk())
.andReturn();
ObjectReader reader = mapper.reader().forType(LocalDate.class);
LocalDate payload = reader.readValue(result.getResponse().getContentAsString());
assertThat(payload).isEqualTo(testDate.plus(10, ChronoUnit.YEARS));
}
}
上面的答案对我不起作用,但我犯了一个错误,在这里找到了一个答案:https://blog.codecentric.de/en/2017/08/parsing-of-localdate-query-parameters-in-spring-boot/ 获胜的片段是 ControllerAdvice 注释,它的优点是可以在所有控制器上应用此修复:
@ControllerAdvice
public class LocalDateTimeControllerAdvice
{
@InitBinder
public void initBinder( WebDataBinder binder )
{
binder.registerCustomEditor( LocalDateTime.class, new PropertyEditorSupport()
{
@Override
public void setAsText( String text ) throws IllegalArgumentException
{
LocalDateTime.parse( text, DateTimeFormatter.ISO_DATE_TIME );
}
} );
}
}
您可以添加到配置中,此解决方案适用于可选参数和非可选参数。
@Bean
public Formatter<LocalDate> localDateFormatter() {
return new Formatter<>() {
@Override
public LocalDate parse(String text, Locale locale) {
return LocalDate.parse(text, DateTimeFormatter.ISO_DATE);
}
@Override
public String print(LocalDate object, Locale locale) {
return DateTimeFormatter.ISO_DATE.format(object);
}
};
}
@Bean
public Formatter<LocalDateTime> localDateTimeFormatter() {
return new Formatter<>() {
@Override
public LocalDateTime parse(String text, Locale locale) {
return LocalDateTime.parse(text, DateTimeFormatter.ISO_DATE_TIME);
}
@Override
public String print(LocalDateTime object, Locale locale) {
return DateTimeFormatter.ISO_DATE_TIME.format(object);
}
};
}
对于全局配置:
public class LocalDateTimePropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
}
然后
@ControllerAdvice
public class InitBinderHandler {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(OffsetDateTime.class, new OffsetDateTimePropertyEditor());
}
}
Spring引导 2.X.X 和更新
如果使用依赖项spring-boot-starter-web
version 2.0.0.RELEASE
or higher, there is no longer needed to explicitely include jackson-datatype-jsr310
dependency, which is already provided with spring-boot-starter-web
through spring-boot-starter-json
。
这已解决为 Spring 启动问题 #9297 and the 仍然 有效且相关:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
@RequestMapping(value = "datetime", method = RequestMethod.POST)
public void foo(
@RequestParam("dateTime")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime ldt) {
// IMPLEMENTATION
}
这是另一个带参数转换器的通用解决方案:
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import ru.diasoft.micro.msamiddleoffice.ftcaa.customerprofile.config.JacksonConfig;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class LocalDateTimeConverter implements Converter<String, LocalDateTime>{
private static final List<String> SUPPORTED_FORMATS = Arrays.asList("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "[another date time format ...]");
private static final List<DateTimeFormatter> DATE_TIME_FORMATTERS = SUPPORTED_FORMATS
.stream()
.map(DateTimeFormatter::ofPattern)
.collect(Collectors.toList());
@Override
public LocalDateTime convert(String s) {
for (DateTimeFormatter dateTimeFormatter : DATE_TIME_FORMATTERS) {
try {
return LocalDateTime.parse(s, dateTimeFormatter);
} catch (DateTimeParseException ex) {
// deliberate empty block so that all parsers run
}
}
throw new DateTimeException(String.format("unable to parse (%s) supported formats are %s",
s, String.join(", ", SUPPORTED_FORMATS)));
}
}
您可以在 application properties
中全局配置日期时间格式。
喜欢:
spring.mvc.format.date=yyyy-MM-dd
spring.mvc.format.date-time=yyyy-MM-dd HH:mm:ss
spring.mvc.format.time=HH:mm:ss
检查mavern:org.springframework.boot:spring-boot-autoconfigure:2.5.3
我在相关上下文中遇到了类似的问题
我正在使用 WebRequestDataBinder 将请求参数动态映射到模型。
Object domainObject = ModelManager.getEntity(entityName).newInstance();
WebRequestDataBinder binder = new WebRequestDataBinder(domainObject);
binder.bind(request);
这段代码适用于基元,但不适用于 LocalDateTime 类型属性
为了解决这个问题,在调用 binder.bind 之前,我在调用 bind()
之前注册了一个自定义编辑器
binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text) throws IllegalArgumentException
{
setValue(LocalDateTime.parse(text, DateTimeFormatter.ISO_DATE_TIME));
}
@Override
public String getAsText() {
return DateTimeFormatter.ISO_DATE_TIME.format((LocalDateTime) getValue());
}
}
);
这解决了问题。
我使用 Spring 启动并在 Maven 中包含 jackson-datatype-jsr310
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.7.3</version>
</dependency>
当我尝试使用 Java 8 Date/Time 类型的 RequestParam 时,
@GetMapping("/test")
public Page<User> get(
@RequestParam(value = "start", required = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start) {
//...
}
并用这个 URL:
进行测试/test?start=2016-10-8T00:00
我收到以下错误:
{
"timestamp": 1477528408379,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
"message": "Failed to convert value of type [java.lang.String] to required type [java.time.LocalDateTime]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime] for value '2016-10-8T00:00'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2016-10-8T00:00]",
"path": "/test"
}
TL;DR - 您可以仅使用 @RequestParam
将其捕获为字符串,或者您可以让 Spring 将字符串另外解析为 java 日期/时间 class 也通过参数 @DateTimeFormat
。
@RequestParam
足以获取您在 = 符号后提供的日期,但是,它作为 String
进入方法。这就是它抛出强制转换异常的原因。
有几种方法可以实现:
- 自己解析日期,获取字符串形式的值。
@GetMapping("/test")
public Page<User> get(@RequestParam(value="start", required = false) String start){
//Create a DateTimeFormatter with your required format:
DateTimeFormatter dateTimeFormat =
new DateTimeFormatter(DateTimeFormatter.BASIC_ISO_DATE);
//Next parse the date from the @RequestParam, specifying the TO type as
a TemporalQuery:
LocalDateTime date = dateTimeFormat.parse(start, LocalDateTime::from);
//Do the rest of your code...
}
- 利用 Spring 自动解析和预期日期格式的能力:
@GetMapping("/test")
public void processDateTime(@RequestParam("start")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
LocalDateTime date) {
// The rest of your code (Spring already parsed the date).
}
我 运行 遇到了同样的问题并找到了我的解决方案 here(不使用注释)
...you must at least properly register a string to [LocalDateTime] Converter in your context, so that Spring can use it to automatically do this for you every time you give a String as input and expect a [LocalDateTime]. (A big number of converters are already implemented by Spring and contained in the core.convert.support package, but none involves a [LocalDateTime] conversion)
所以在你的情况下你会这样做:
public class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {
public LocalDateTime convert(String source) {
DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
return LocalDateTime.parse(source, formatter);
}
}
然后只需注册您的 bean:
<bean class="com.mycompany.mypackage.StringToLocalDateTimeConverter"/>
有注释
将其添加到您的 ConversionService:
@Component
public class SomeAmazingConversionService extends GenericConversionService {
public SomeAmazingConversionService() {
addConverter(new StringToLocalDateTimeConverter());
}
}
最后,您将在 ConversionService 中使用@Autowire:
@Autowired
private SomeAmazingConversionService someAmazingConversionService;
您可以在此 site 上阅读有关使用 spring(和格式)进行转换的更多信息。请注意,它有大量广告,但我确实发现它是一个有用的网站,并且是该主题的一个很好的介绍。
你做的一切都是正确的:)。 Here is an example that shows exactly what you are doing. Just Annotate your RequestParam with @DateTimeFormat
. There is no need for special GenericConversionService
or manual conversion in the controller. This 博客 post 写了它。
@RestController
@RequestMapping("/api/datetime/")
final class DateTimeController {
@RequestMapping(value = "datetime", method = RequestMethod.POST)
public void processDateTime(@RequestParam("datetime")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateAndTime) {
//Do stuff
}
}
我猜你的格式有问题。在我的设置中一切正常。
就像我在评论中所说的那样,您也可以在签名方法中使用此解决方案:@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start
我找到了解决方法 here。
Spring/Spring Boot only supports the date/date-time format in BODY parameters.
以下配置class在QUERY STRING(请求参数)中添加对date/date-time的支持:
// Since Spring Framwork 5.0 & Java 8+
@Configuration
public class DateTimeFormatConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
分别是:
// Until Spring Framwork 4.+
@Configuration
public class DateTimeFormatConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
即使您将多个请求参数绑定到某些 class 也能正常工作(@DateTimeFormat
注释在这种情况下无能为力):
public class ReportRequest {
private LocalDate from;
private LocalDate to;
public LocalDate getFrom() {
return from;
}
public void setFrom(LocalDate from) {
this.from = from;
}
public LocalDate getTo() {
return to;
}
public void setTo(LocalDate to) {
this.to = to;
}
}
// ...
@GetMapping("/api/report")
public void getReport(ReportRequest request) {
// ...
以下适用于 Spring Boot 2.1.6:
控制器
@Slf4j
@RestController
public class RequestController {
@GetMapping
public String test(RequestParameter param) {
log.info("Called services with parameter: " + param);
LocalDateTime dateTime = param.getCreated().plus(10, ChronoUnit.YEARS);
LocalDate date = param.getCreatedDate().plus(10, ChronoUnit.YEARS);
String result = "DATE_TIME: " + dateTime + "<br /> DATE: " + date;
return result;
}
@PostMapping
public LocalDate post(@RequestBody PostBody body) {
log.info("Posted body: " + body);
return body.getDate().plus(10, ChronoUnit.YEARS);
}
}
Dto classes:
@Value
public class RequestParameter {
@DateTimeFormat(iso = DATE_TIME)
LocalDateTime created;
@DateTimeFormat(iso = DATE)
LocalDate createdDate;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostBody {
LocalDate date;
}
测试class:
@RunWith(SpringRunner.class)
@WebMvcTest(RequestController.class)
public class RequestControllerTest {
@Autowired MockMvc mvc;
@Autowired ObjectMapper mapper;
@Test
public void testWsCall() throws Exception {
String pDate = "2019-05-01";
String pDateTime = pDate + "T23:10:01";
String eDateTime = "2029-05-01T23:10:01";
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("")
.param("created", pDateTime)
.param("createdDate", pDate))
.andExpect(status().isOk())
.andReturn();
String payload = result.getResponse().getContentAsString();
assertThat(payload).contains(eDateTime);
}
@Test
public void testMapper() throws Exception {
String pDate = "2019-05-01";
String eDate = "2029-05-01";
String pDateTime = pDate + "T23:10:01";
String eDateTime = eDate + "T23:10:01";
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("")
.param("created", pDateTime)
.param("createdDate", pDate)
)
.andExpect(status().isOk())
.andReturn();
String payload = result.getResponse().getContentAsString();
assertThat(payload).contains(eDate).contains(eDateTime);
}
@Test
public void testPost() throws Exception {
LocalDate testDate = LocalDate.of(2015, Month.JANUARY, 1);
PostBody body = PostBody.builder().date(testDate).build();
String request = mapper.writeValueAsString(body);
MvcResult result = mvc.perform(MockMvcRequestBuilders.post("")
.content(request).contentType(APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk())
.andReturn();
ObjectReader reader = mapper.reader().forType(LocalDate.class);
LocalDate payload = reader.readValue(result.getResponse().getContentAsString());
assertThat(payload).isEqualTo(testDate.plus(10, ChronoUnit.YEARS));
}
}
上面的答案对我不起作用,但我犯了一个错误,在这里找到了一个答案:https://blog.codecentric.de/en/2017/08/parsing-of-localdate-query-parameters-in-spring-boot/ 获胜的片段是 ControllerAdvice 注释,它的优点是可以在所有控制器上应用此修复:
@ControllerAdvice
public class LocalDateTimeControllerAdvice
{
@InitBinder
public void initBinder( WebDataBinder binder )
{
binder.registerCustomEditor( LocalDateTime.class, new PropertyEditorSupport()
{
@Override
public void setAsText( String text ) throws IllegalArgumentException
{
LocalDateTime.parse( text, DateTimeFormatter.ISO_DATE_TIME );
}
} );
}
}
您可以添加到配置中,此解决方案适用于可选参数和非可选参数。
@Bean
public Formatter<LocalDate> localDateFormatter() {
return new Formatter<>() {
@Override
public LocalDate parse(String text, Locale locale) {
return LocalDate.parse(text, DateTimeFormatter.ISO_DATE);
}
@Override
public String print(LocalDate object, Locale locale) {
return DateTimeFormatter.ISO_DATE.format(object);
}
};
}
@Bean
public Formatter<LocalDateTime> localDateTimeFormatter() {
return new Formatter<>() {
@Override
public LocalDateTime parse(String text, Locale locale) {
return LocalDateTime.parse(text, DateTimeFormatter.ISO_DATE_TIME);
}
@Override
public String print(LocalDateTime object, Locale locale) {
return DateTimeFormatter.ISO_DATE_TIME.format(object);
}
};
}
对于全局配置:
public class LocalDateTimePropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
}
然后
@ControllerAdvice
public class InitBinderHandler {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(OffsetDateTime.class, new OffsetDateTimePropertyEditor());
}
}
Spring引导 2.X.X 和更新
如果使用依赖项spring-boot-starter-web
version 2.0.0.RELEASE
or higher, there is no longer needed to explicitely include jackson-datatype-jsr310
dependency, which is already provided with spring-boot-starter-web
through spring-boot-starter-json
。
这已解决为 Spring 启动问题 #9297 and the
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
@RequestMapping(value = "datetime", method = RequestMethod.POST)
public void foo(
@RequestParam("dateTime")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime ldt) {
// IMPLEMENTATION
}
这是另一个带参数转换器的通用解决方案:
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import ru.diasoft.micro.msamiddleoffice.ftcaa.customerprofile.config.JacksonConfig;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class LocalDateTimeConverter implements Converter<String, LocalDateTime>{
private static final List<String> SUPPORTED_FORMATS = Arrays.asList("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "[another date time format ...]");
private static final List<DateTimeFormatter> DATE_TIME_FORMATTERS = SUPPORTED_FORMATS
.stream()
.map(DateTimeFormatter::ofPattern)
.collect(Collectors.toList());
@Override
public LocalDateTime convert(String s) {
for (DateTimeFormatter dateTimeFormatter : DATE_TIME_FORMATTERS) {
try {
return LocalDateTime.parse(s, dateTimeFormatter);
} catch (DateTimeParseException ex) {
// deliberate empty block so that all parsers run
}
}
throw new DateTimeException(String.format("unable to parse (%s) supported formats are %s",
s, String.join(", ", SUPPORTED_FORMATS)));
}
}
您可以在 application properties
中全局配置日期时间格式。
喜欢:
spring.mvc.format.date=yyyy-MM-dd
spring.mvc.format.date-time=yyyy-MM-dd HH:mm:ss
spring.mvc.format.time=HH:mm:ss
检查mavern:org.springframework.boot:spring-boot-autoconfigure:2.5.3
我在相关上下文中遇到了类似的问题
我正在使用 WebRequestDataBinder 将请求参数动态映射到模型。
Object domainObject = ModelManager.getEntity(entityName).newInstance();
WebRequestDataBinder binder = new WebRequestDataBinder(domainObject);
binder.bind(request);
这段代码适用于基元,但不适用于 LocalDateTime 类型属性
为了解决这个问题,在调用 binder.bind 之前,我在调用 bind()
之前注册了一个自定义编辑器binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text) throws IllegalArgumentException
{
setValue(LocalDateTime.parse(text, DateTimeFormatter.ISO_DATE_TIME));
}
@Override
public String getAsText() {
return DateTimeFormatter.ISO_DATE_TIME.format((LocalDateTime) getValue());
}
}
);
这解决了问题。