Spring Bootを使用し、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でパラメータの@DateTimeFormat
を介して文字列をJava日付/時間クラスにさらに解析することができますまあ。
@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...
}
@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).
}
あなたはすべて正しかった:)。 ここ は、あなたが何をしているかを正確に示す例です。 JustRequestParamに@DateTimeFormat
の注釈を付けます。コントローラで特別なGenericConversionService
または手動変換を行う必要はありません。 これ ブログ投稿でそれについて書いています。
@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
私は回避策を見つけました こちら 。
Spring/Spring Bootは、BODYパラメーターで日付/日付時刻形式のみをサポートします。
この構成クラスは、QUERY STRINGの日付/日付時刻のサポートを追加します。
@Configuration
public class DateTimeFormatConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
複数のリクエストパラメータを何らかのクラスにバインドした場合でも動作します(この場合、@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) {
// ...
私は同じ問題に遭遇し、私の解決策を見つけました here (注釈を使用せずに)
...少なくとも文字列をコンテキストの[LocalDateTime] Converterに適切に登録する必要があります。これにより、入力として文字列を指定し、[LocalDateTime]を期待するたびにSpringが自動的にこれを行うことができます。 (多数のコンバーターは既にSpringによって実装されており、core.convert.supportパッケージに含まれていますが、[LocalDateTime]変換を必要とするものはありません)
したがって、あなたの場合、これを行うでしょう:
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 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クラス:
@Value
public class RequestParameter {
@DateTimeFormat(iso = DATE_TIME)
LocalDateTime created;
@DateTimeFormat(iso = DATE)
LocalDate createdDate;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PostBody {
LocalDate date;
}
テストクラス:
@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 );
}
} );
}
}