如何在Spring中使用LocalDateTime RequestParam?我得到;无法将字符串转换为LocalDateTime;
我使用Spring Boot,在Maven中包括了如何在Spring中使用LocalDateTime RequestParam?我得到;无法将字符串转换为LocalDateTime;,spring,spring-boot,spring-mvc,java-time,jsr310,Spring,Spring Boot,Spring Mvc,Java Time,Jsr310,我使用Spring Boot,在Maven中包括了jackson-datatype-jsr310: <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.7.3</version> </depe
jackson-datatype-jsr310
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.7.3</version>
</dependency>
我得到以下错误:
{
"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
足以获取您在=符号后提供的日期,但是,它作为字符串进入方法。这就是它抛出cast异常的原因
有几种方法可以实现这一点:
自己解析日期,将值作为字符串抓取
@GetMapping(“/test”)
公共页面获取(@RequestParam(value=“start”,required=false)字符串开始){
//使用所需格式创建DateTimeFormatter:
DateTimeFormatter dateTimeFormat=
新的DateTimeFormatter(DateTimeFormatter.BASIC_ISO_DATE);
//接下来从@RequestParam解析日期,将TO类型指定为
临时查询:
LocalDateTime日期=dateTimeFormat.parse(开始,LocalDateTime::from);
//做你剩下的代码。。。
}
利用Spring自动解析和预期日期格式的能力:
@GetMapping(“/test”)
public void processDateTime(@RequestParam(“start”)
@DateTimeFormat(iso=DateTimeFormat.iso.DATE\u时间)
LocalDateTime(日期){
//剩下的代码(Spring已经解析了日期)。
}
我遇到了同样的问题并找到了解决方案(没有使用注释)
…您必须至少向中的[LocalDateTime]转换器正确注册一个字符串
您的上下文,以便Spring可以使用它为
每次输入一个字符串并期望得到一个[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);
}
}
最后,您将在ConversionService中使用@Autowire:
@Component
public class SomeAmazingConversionService extends GenericConversionService {
public SomeAmazingConversionService() {
addConverter(new StringToLocalDateTimeConverter());
}
}
@Autowired
private SomeAmazingConversionService someAmazingConversionService;
您可以在此阅读更多关于spring转换(和格式)的信息。事先警告一下,它有大量的广告,但我肯定发现它是一个有用的网站,是一个很好的主题介绍 你做的一切都是正确的:)。这是一个能准确显示您正在做什么的示例。只需使用@DateTimeFormat
注释RequestParam即可。控制器中不需要特殊的通用转换服务
或手动转换。这篇博文写的就是这个
@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\u-TIME)LocalDateTime start
我找到了解决方法
Spring/Spring Boot仅支持BODY参数中的日期/时间格式
以下配置类在查询字符串(请求参数)中添加了对日期/日期时间的支持:
分别为:
// 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
注释),它也可以工作:
以下内容适用于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);
}
}
测试类:
@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));
}
}
上面的答案对我不起作用,但我在这里错了:获胜的片段是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
公共格式化程序localDateFormatter(){
返回新格式化程序(){
@凌驾
公共LocalDate解析(字符串文本、区域设置){
返回LocalDate.parse(text,DateTimeFormatter.ISO_DATE);
}
@凌驾
公共字符串打印(LocalDate对象、Locale){
返回日期timeformatter.ISO_DATE.format(对象);
}
};
}
@豆子
公共格式化程序localDateTimeFormatter(){
返回新格式化程序(){
@凌驾
公共LocalDateTime解析(字符串文本、区域设置){
返回LocalDateTime.parse(text,DateTimeFormatter.ISO_DATE_TIME);
}
@凌驾
公共字符串打印(LocalDateTime对象、区域设置){
返回日期timeformatter.ISO_DATE_TIME.format(对象);
}
};
}
对于全局配置:
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());
}
}
SpringBoot 2.X.X更新
如果使用依赖版本2.0.0.RELEASE
或更高版本,则不再需要明确包含jackson-datatype-jsr310
依赖项,该依赖项已通过spring boot starter web
提供
这已解决为弹簧启动问题,仍然有效且相关:
@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)));
}
}
import org.springframework.core.convert.converter.converter;
导入org.springframework.stereotype.Component;
导入ru.diasoft.micro.msamidleoffice.ftcaa.customerprofile.config.JacksonConfig;
导入java.time.DateTimeException;
导入java.time.LocalDateTime;
导入java.time.format.DateTimeFormatter;
导入java.time.format.DateTimeParseException;
导入java.util.array;
导入java.util.List;
导入java.util.stream.collector;
@组成部分
公共类LocalDateTimeConverter实现转换器{
支持的私有静态最终列表_格式=Arrays.asList(“yyyy-MM-dd'T'HH:MM:ss.SSS'Z'”,[另一个日期时间格式…]);
私有静态最终列表日期\时间\格式化程序=支持的\格式
@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 );
}
} );
}
}
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());
}
}
@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)));
}
}