How to use LocalDateTime RequestParam in Spring? I get “Failed to convert String to LocalDateTime”

后端 未结 10 1406
小蘑菇
小蘑菇 2020-11-29 02:35

I use Spring Boot and included jackson-datatype-jsr310 with Maven:


    com.fasterxml.jackson.datatype

        
相关标签:
10条回答
  • 2020-11-29 02:35

    You did everything correct :) . 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 blog post writes about it.

    @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
        }
    }
    

    I guess you had an issue with the format. On my setup everything works well.

    0 讨论(0)
  • 2020-11-29 02:36

    I ran into the same problem and found my solution here (without using Annotations)

    ...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)

    So in your case you would do this:

    public class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {
        public LocalDateTime convert(String source) {
            DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
            return LocalDateTime.parse(source, formatter);
        }
    }
    

    and then just register your bean:

    <bean class="com.mycompany.mypackage.StringToLocalDateTimeConverter"/>
    

    With Annotations

    add it to your ConversionService:

    @Component
    public class SomeAmazingConversionService extends GenericConversionService {
    
        public SomeAmazingConversionService() {
            addConverter(new StringToLocalDateTimeConverter());
        }
    
    }
    

    and finally you would then @Autowire in your ConversionService:

    @Autowired
    private SomeAmazingConversionService someAmazingConversionService;
    

    You can read more about conversions with spring (and formatting) on this site. Be forewarned it has a ton of ads, but I definitely found it to be a useful site and a good intro to the topic.

    0 讨论(0)
  • 2020-11-29 02:41

    TL;DR - you can capture it as a string with just @RequestParam, or you can have Spring additionally parse the string into a java date / time class via @DateTimeFormat on the parameter as well.

    the @RequestParam is enough to grab the date you supply after the = sign, however, it comes into the method as a String. That is why it is throwing the cast exception.

    There are a few ways to achieve this:

    1. parse the date yourself, grabbing the value as a 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...
    }
    
    1. Leverage Spring's ability to automatically parse and expect date formats:
    @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).
    }
    
    0 讨论(0)
  • 2020-11-29 02:41

    SpringBoot 2.X.X update

    If you use the dependency 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.

    This was resolved as Spring Boot issue #9297 and the answer is still valid and relevant:

    @RequestMapping(value = "datetime", method = RequestMethod.POST)
    public void foo(@RequestParam("dateTime") 
                    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime ldt) {
        // IMPLEMENTATION
    }
    
    0 讨论(0)
  • 2020-11-29 02:45

    For global configuration :

    public class LocalDateTimePropertyEditor extends PropertyEditorSupport {
    
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            setValue(LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        }
    
    }
    

    And then

    @ControllerAdvice
    public class InitBinderHandler {
    
        @InitBinder
        public void initBinder(WebDataBinder binder) { 
            binder.registerCustomEditor(OffsetDateTime.class, new OffsetDateTimePropertyEditor());
        }
    
    }
    
    0 讨论(0)
  • 2020-11-29 02:48

    I found workaround here.

    Spring/Spring Boot only supports the date/date-time format in BODY parameters.

    The following configuration class adds support for date/date-time in QUERY STRING (request parameters):

    // 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);
        }
    }
    

    respectively:

    // 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);
        }
    }
    

    It works even if you bind multiple request parameters to some class (@DateTimeFormat annotation helpless in this case):

    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) {
    // ...
    
    0 讨论(0)
提交回复
热议问题