首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Spring反序列化@RequestBody中的LocalDate与@RequestParam中的一个反序列化不同--为什么,它们可以是相同的?

Spring反序列化@RequestBody中的LocalDate与@RequestParam中的一个反序列化不同--为什么,它们可以是相同的?
EN

Stack Overflow用户
提问于 2017-04-28 15:54:23
回答 3查看 15.9K关注 0票数 10

问: Spring似乎对LocalDate使用了不同的反序列化方法,这取决于它是出现在@RequestBody中还是在请求@ReqestParam中--这是正确的吗?如果是的话,有没有方法将它们配置为在整个应用程序中都是相同的?

背景:在我的@RestController中,我有两种方法--一种是GET,另一种是帖子。GET需要一个LocalDate类型的请求参数("date");POST需要一个JSON对象,其中一个键("date")为LocalDate类型。他们的签名类似于以下内容:

代码语言:javascript
运行
复制
@RequestMapping(value = "/entity", method = RequestMethod.GET)
public EntityResponse get(
       Principal principal,
       @RequestParam(name = "date", required = false) LocalDate date) 

@RequestMapping(value = "/entity", method = RequestMethod.POST)
public EntityResponse post(
       Principal principal,
       @RequestBody EntityPost entityPost)

public class EntityPost {
       public LocalDate date;
}

我已经将我的ObjectMapper配置如下:

代码语言:javascript
运行
复制
@Bean
public ObjectMapper objectMapper() {

   ObjectMapper objectMapper = new ObjectMapper();
   objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
   objectMapper.registerModule(new JavaTimeModule());
   objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

   return objectMapper;
}

这确保系统以yyyy格式接受LocalDate,并按预期反序列化它--至少当它是@RequestBody的一部分时是如此。因此,如果下面是请求发布的主体

代码语言:javascript
运行
复制
{
"date": 2017-01-01
}

系统按预期将请求体反序列化为EntityPost

但是,该配置不适用于@RequestParam的反序列化。因此,这是失败的:

代码语言:javascript
运行
复制
// fail!
/entity?date=2017-01-01

相反,系统似乎期望使用MM/dd/yy格式。因此,这是成功的:

代码语言:javascript
运行
复制
// success!
/entity?date=01/01/17

我知道我可以使用@DateTimeFormat注释逐个参数地更改这一点。我知道,如果我按以下方式更改GET方法的签名,它将接受第一种格式:

代码语言:javascript
运行
复制
@RequestMapping(value = "/entity", method = RequestMethod.GET)
public EntityResponse get(
       Principal principal,
       @RequestParam(name = "date", required = false) @DateTimeFormat(iso=DateTimeFormat.ISO.DATE) LocalDate date) 

但是,如果我不需要为LocalDate的每一次使用都包括一个注释,我会更喜欢。是否有任何方法在全局上设置这个值,以便系统以相同的方式反序列化每个@RequestParam类型的LocalDate

供参考:

我在使用Spring 4.3.2.RELEASE

我使用的是杰克逊2.6.5

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-05-01 20:39:29

Per @Andreas在注释中,Spring使用Jackson反序列化@RequestBody,但Spring本身反序列化@RequestParam。这就是两者差异的根源。

answer演示如何使用@ControllerAdvice@InitBinder自定义@RequestParam的反序列化。我最终使用的代码如下:

代码语言:javascript
运行
复制
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;

import java.beans.PropertyEditorSupport;
import java.text.Format;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.function.Function;

@ControllerAdvice
public class ControllerAdviceInitBinder {

    private static class Editor<T> extends PropertyEditorSupport {

        private final Function<String, T> parser;
        private final Format format;

        public Editor(Function<String, T> parser, Format format) {

            this.parser = parser;
            this.format = format;
        }

        public void setAsText(String text) {

            setValue(this.parser.apply(text));
        }

        public String getAsText() {

            return format.format((T) getValue());
        }
    }

    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {

        webDataBinder.registerCustomEditor(
                Instant.class,
                new Editor<>(
                        Instant::parse,
                        DateTimeFormatter.ISO_INSTANT.toFormat()));

        webDataBinder.registerCustomEditor(
                LocalDate.class,
                new Editor<>(
                        text -> LocalDate.parse(text, DateTimeFormatter.ISO_LOCAL_DATE),
                        DateTimeFormatter.ISO_LOCAL_DATE.toFormat()));

        webDataBinder.registerCustomEditor(
                LocalDateTime.class,
                new Editor<>(
                        text -> LocalDateTime.parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME),
                        DateTimeFormatter.ISO_LOCAL_DATE_TIME.toFormat()));

        webDataBinder.registerCustomEditor(
                LocalTime.class,
                new Editor<>(
                        text -> LocalTime.parse(text, DateTimeFormatter.ISO_LOCAL_TIME),
                        DateTimeFormatter.ISO_LOCAL_TIME.toFormat()));

        webDataBinder.registerCustomEditor(
                OffsetDateTime.class,
                new Editor<>(
                        text -> OffsetDateTime.parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME),
                        DateTimeFormatter.ISO_OFFSET_DATE_TIME.toFormat()));

        webDataBinder.registerCustomEditor(
                OffsetTime.class,
                new Editor<>(
                        text -> OffsetTime.parse(text, DateTimeFormatter.ISO_OFFSET_TIME),
                        DateTimeFormatter.ISO_OFFSET_TIME.toFormat()));

        webDataBinder.registerCustomEditor(
                ZonedDateTime.class,
                new Editor<>(
                        text -> ZonedDateTime.parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME),
                        DateTimeFormatter.ISO_ZONED_DATE_TIME.toFormat()));
    }
}
票数 6
EN

Stack Overflow用户

发布于 2018-03-22 08:51:40

为LocalDate创建一个格式化程序:

代码语言:javascript
运行
复制
public class LocalDateFormatter implements Formatter<LocalDate> {

    @Override
    public LocalDate parse(String text, Locale locale) throws ParseException {
        return LocalDate.parse(text, DateTimeFormatter.ISO_DATE);
    }

    @Override
    public String print(LocalDate object, Locale locale) {
        return DateTimeFormatter.ISO_DATE.format(object);
    }
}

Spring 5+:注册格式化程序:在@Configuration中实现WebMvcConfigurer并重写addFormatters

代码语言:javascript
运行
复制
@Override
public void addFormatters(FormatterRegistry registry) {
    registry.addFormatter(new LocalDateFormatter());
}

Spring:定义了一个覆盖默认格式化程序的@Primary @Bean

代码语言:javascript
运行
复制
@Bean
@Primary
public Formatter<LocalDate> localDateFormatter() {
    return new LocalDateFormatter();
}
票数 6
EN

Stack Overflow用户

发布于 2021-10-27 03:20:23

春季2.1.6

代码语言:javascript
运行
复制
 @Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
    return builder -> {
        DateTimeFormatter localDateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        builder.serializerByType(LocalDate.class, new LocalDateSerializer(localDateFormatter));
        builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(localDateFormatter));

        DateTimeFormatter localDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(localDateTimeFormatter));
        builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(localDateTimeFormatter));
    };
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43684306

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档