Ich benutze Spring Boot und in jackson-datatype-jsr310
Maven enthalten:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.7.3</version>
</dependency>
Wenn ich versuche, ein RequestParam mit einem Java 8-Datums- / Uhrzeittyp zu verwenden,
@GetMapping("/test")
public Page<User> get(
@RequestParam(value = "start", required = false)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start) {
//...
}
und testen Sie es mit dieser URL:
/test?start=2016-10-8T00:00
Ich erhalte folgende Fehlermeldung:
{
"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"
}
spring
spring-boot
spring-mvc
java-time
jsr310
Kery Hu
quelle
quelle
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start
Du hast alles richtig gemacht :). Hier ist ein Beispiel, das genau zeigt, was Sie tun. Kommentieren Sie einfach Ihr RequestParam mit
@DateTimeFormat
. Es ist keine spezielleGenericConversionService
oder manuelle Konvertierung in der Steuerung erforderlich . Dieser Blog-Beitrag schreibt darüber.@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 } }
Ich denke, Sie hatten ein Problem mit dem Format. Bei meinem Setup funktioniert alles gut.
quelle
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) public @interface DateTimeFormat {
.startDate
undendDate
) zur Anforderungsmethode das Verhalten der Methode zu verschlechtern.Ich habe hier eine Problemumgehung gefunden .
Die folgende Konfigurationsklasse unterstützt Datum / Uhrzeit in QUERY STRING (Anforderungsparameter):
// 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); } }
beziehungsweise:
// 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); } }
@DateTimeFormat
Dies funktioniert auch dann, wenn Sie mehrere Anforderungsparameter an eine Klasse binden ( in diesem Fall hilflose Anmerkungen):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) { // ...
quelle
Wie ich im Kommentar angegeben habe, können Sie diese Lösung auch in der Signaturmethode verwenden:
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start
quelle
Ich bin auf dasselbe Problem gestoßen und habe hier meine Lösung gefunden (ohne Anmerkungen zu verwenden).
In Ihrem Fall würden Sie also Folgendes tun:
public class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> { public LocalDateTime convert(String source) { DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE; return LocalDateTime.parse(source, formatter); } }
und dann registrieren Sie einfach Ihre Bohne:
<bean class="com.mycompany.mypackage.StringToLocalDateTimeConverter"/>
Mit Anmerkungen
Fügen Sie es Ihrem ConversionService hinzu:
@Component public class SomeAmazingConversionService extends GenericConversionService { public SomeAmazingConversionService() { addConverter(new StringToLocalDateTimeConverter()); } }
und schließlich würden Sie dann @Autowire in Ihrem ConversionService:
@Autowired private SomeAmazingConversionService someAmazingConversionService;
Weitere Informationen zu Conversions mit Spring (und Formatierung) finden Sie auf dieser Website . Seien Sie gewarnt, es gibt eine Menge Anzeigen, aber ich fand es definitiv eine nützliche Website und eine gute Einführung in das Thema.
quelle
Folgendes funktioniert gut mit Spring Boot 2.1.6:
Regler
@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 Klassen:
@Value public class RequestParameter { @DateTimeFormat(iso = DATE_TIME) LocalDateTime created; @DateTimeFormat(iso = DATE) LocalDate createdDate; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class PostBody { LocalDate date; }
Testklasse:
@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)); } }
quelle
SpringBoot 2.XX Update
Wenn Sie die Abhängigkeit ausnützt
spring-boot-starter-web
Version2.0.0.RELEASE
oder höher, gibt es nicht mehr erforderlich , um explizit enthältjackson-datatype-jsr310
Abhängigkeit, die bereits mit vorgesehen ist ,spring-boot-starter-web
durchspring-boot-starter-json
.Dies wurde als Spring Boot-Problem Nr. 9297 behoben und die Antwort ist weiterhin gültig und relevant:
@RequestMapping(value = "datetime", method = RequestMethod.POST) public void foo(@RequestParam("dateTime") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime ldt) { // IMPLEMENTATION }
quelle
Die obigen Antworten haben bei mir nicht funktioniert, aber ich habe mich an eine gewandt, die hier funktioniert hat: https://blog.codecentric.de/de/2017/08/parsing-of-localdate-query-parameters-in-spring- boot / Das Gewinner-Snippet war die ControllerAdvice-Annotation, die den Vorteil hat, dass dieses Update auf alle Ihre Controller angewendet wird:
@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 ); } } ); } }
quelle
Sie können der Konfiguration hinzufügen, dass diese Lösung sowohl mit optionalen als auch mit nicht optionalen Parametern funktioniert.
@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); } }; }
quelle
Für die globale Konfiguration:
public class LocalDateTimePropertyEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { setValue(LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME)); } }
Und dann
@ControllerAdvice public class InitBinderHandler { @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(OffsetDateTime.class, new OffsetDateTimePropertyEditor()); } }
quelle
LocalDateTimePropertyEditor
seinOffsetDateTimePropertyEditor
oder umgekehrt?