봄철 LocalDateTime RequestParam 사용방법"String을 LocalDateTime으로 변환하지 못했습니다"라고 표시됩니다.
Spring Boot도 포함되어 .jackson-datatype-jsr310Maven 함 ma :
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.7.3</version>
</dependency>
Java 8 Date/Time 타입의 Request Param을 사용하려고 하면
@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파라미터에도 적용됩니다.
@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).
}
모든 작업을 올바르게 수행했습니다.:). 다음은 정확히 무엇을 하고 있는지를 보여주는 예입니다.Request Param에 주석을 달기만 하면 됩니다.@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
}
}
포맷에 문제가 있었나 봐요.내 설정에서는 모든 것이 잘 작동한다.
여기서 해결 방법을 찾았어요.
스프링/스프링 부트는 BODY 파라미터의 날짜/날짜 형식만 지원합니다.
다음 컨피규레이션클래스는 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);
}
}
합니다(「」).@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) {
// ...
, 이 할 수 있습니다.@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime start
SpringBoot 2.X.X 이후
종속성 버전을 사용하는 경우2.0.0.RELEASE이상은 더 할 필요가 .jackson-datatype-jsr310.spring-boot-starter-web~를 참조해 주세요.
이는 Spring Boot 문제 #9297로 해결되었으며 답변은 여전히 유효하며 관련이 있습니다.
<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
}
같은 문제에 부딪혀, 여기서 해결책을 찾았습니다(주석 사용 안 함).
...적어도 컨텍스트에서 문자열을 [LocalDateTime]컨버터에 적절하게 등록해야 합니다.그러면 Spring은 String을 입력으로 제공하고 [LocalDateTime]을 기대할 때마다 이 작업을 자동으로 수행할 수 있습니다.(대부분의 변환기는 이미 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 class="com.mycompany.mypackage.StringToLocalDateTimeConverter"/>
주석 포함
Conversion Service에 추가합니다.
@Component
public class SomeAmazingConversionService extends GenericConversionService {
public SomeAmazingConversionService() {
addConverter(new StringToLocalDateTimeConverter());
}
}
마지막으로 Conversion Service에서 @Autowire:
@Autowired
private SomeAmazingConversionService someAmazingConversionService;
스프링(및 포맷)을 사용한 변환에 대한 자세한 내용은 이 사이트를 참조하십시오.광고도 많이 게재되어 있습니다만, 확실히 도움이 되는 사이트이며, 토픽의 소개가 잘 되어 있는 것을 알 수 있었습니다.
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 );
}
} );
}
}
설정에 추가할 수 있습니다.이 솔루션은 옵션 파라미터와 비옵션 파라미터로 동작합니다.
@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);
}
};
}
파라미터 컨버터를 사용하는 다른 일반적인 솔루션은 다음과 같습니다.
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)));
}
}
은 datetime으로 할 수 .application properties를 들어 를를: :
spring.mvc.format.date=yyy-MM-dd
spring.mvc.format.date-time=yy-MM-dd HH:mm:ss
spring.mvc.format 입니다.시간=HH:mm:ss
mavern: org.springframework를 체크합니다.부트: spring-boot-autoconfigure: 2.5.3
글로벌 설정의 경우:
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());
}
}
이와 관련하여 비슷한 문제가 있었습니다.
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());
}
}
);
이것으로 문제가 해결되었다.
이 동작은 스웨거 오픈과 함께 작업하는 동안 발생했습니다.API 끝점...
오픈API 정의는 비슷해 보였습니다.
paths:
/endpoint:
get:
summary: short summary
operationId: endpointFunction
parameters:
- name: timestamp
in: query
description: 'Given timestamp'
required: false
schema:
type: string
format: date-time
example: "2023-01-05T13:11:40.020747+01:00"
responses:
200:
description: 'Ok'
404:
description: 'Not Ok'
content: {}
500:
description: 'Failure'
content: { }
Maven을 사용하여 정의를 컴파일하면 다음과 같습니다.
public interface EndpointApiDelegate {
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
/**
* GET /endpoint : short summary
*
* @param timestamp Given timestamp (optional)
* @return Ok (status code 200)
* or Not ok (status code 404)
* or Interner Fehler (status code 500)
* @see EndpointApi#endpointFunction
*/
default ResponseEntity<Void> endpointFunction(OffsetDateTime timestamp) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
이제 직접 데이터를 전송하려고 합니다.
- 브라우저의 URL
- http 파일(.http)
- 집배원 등
### Sample FAILING call in .http-file
GET http://localhost:{{port}}/endpoint?timestamp=22023-01-05T13:11:40.020747+01:00
지정된 예(2023-01-05T13:11:40.020747+01:00)를 사용하면 실패합니다.
"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 ... .. .
추리
쿼리 매개 변수는 다른 문자 집합으로 구문 분석됩니다(올바른 단어인지 확실하지 않지만 동작에 적합합니다).따라서 '+' 문자를 읽을 수 없습니다.
결의안
### Sample WORKING call in .http-file
GET http://localhost:{{port}}/endpoint?timestamp=2023-01-03T11%3A29%3A47.526612%2B01%3A00
주의
만약 그 해결책이 비현실적으로 느껴진다면...
.....그렇다면: 당신이 옳아요!!!
날짜 시간 전달(이 경우)은 잘못된 엔드포인트 설계 결정입니다.
Swagger OpenApi는 OpenApi 정의에서 int(최소 및 최대)와 문자열(regex-pattern)을 직접 검사합니다.
여전히 날짜 시간은 최소/최대 값이 상대적인 '매일 경과 시간'에 따라 달라질 수 있으므로 특별한 함정을 제공합니다.따라서 자동화된 최소/최대 값은 아직 구현되지 않은 것으로 예상됩니다.
더 좋은 해결책이 있을까요?네! :)
대신 POST 요청을 사용하여 URL-RequestParameter 대신 RequestBody에서 APPLICATION JSON을 정의합니다.
components:
schemas:
TimestampEntity:
type: object
properties:
timestamp:
description: 'timestamp'
type: string
format: date-time
example: "2023-01-05T13:11:40.020747+01:00"
paths:
/endpoint:
post:
summary: short summary
operationId: endpointFunction
# parameters:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TimestampEntity'
responses:
200:
description: 'Ok'
404:
description: 'Not Ok'
content: {}
500:
description: 'Failure'
content: { }
그 취지는 다음과 같습니다.
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
/**
* POST /endpoint : short summary
*
* @param timestampEntity
(optional)
* @return Ok (status code 200)
* or Not Ok (status code 404)
* or Failure (status code 500)
* @see EndpointApi#endpointFunction
*/
default ResponseEntity<Void> endpointFunction(TimestampEntity timestampEntity) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
생성된 Timestamp.class 사용:
public class TimestampEntity {
@JsonProperty("timestamp")
private OffsetDateTime timestamp;
public TimestampEntity timestamp(OffsetDateTime timestamp) {
this.timestamp = timestamp;
return this;
}
... .. .
이제 값(2023-01-05T13:11:40.020747+01:00)이 적절하게 해석됩니다.
이것으로 URL charset-scuffle에 얽히는 것은 끝입니다;-)
저 같은 경우에는
'@설정
//@EnableWebMvc - 이 코멘트를 해제하면 LocalDateTime은 배열이 됩니다.
퍼블릭 클래스 WebConfig가 WebMvcConfigr {...}을(를) 구현합니다.}`
언급URL : https://stackoverflow.com/questions/40274353/how-to-use-localdatetime-requestparam-in-spring-i-get-failed-to-convert-string
'programing' 카테고리의 다른 글
| 스프링: 특정 인터페이스 및 유형의 모든 Bean을 가져옵니다. (0) | 2023.03.04 |
|---|---|
| Mongodb find() 쿼리 : 원하는 값만 반환(중복 없음) (0) | 2023.03.04 |
| jq를 사용하여 명명된 키를 사용하여 개체 배열을 개체로 변환합니다. (0) | 2023.03.04 |
| 다차원 Javascript 배열을 JSON으로 변환하시겠습니까? (0) | 2023.03.04 |
| 공용 폴더의 ReactJ 및 이미지 (0) | 2023.03.04 |