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

2024-02-05

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

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

@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 配置如下:

@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;
}

这确保系统接受LocalDate以 yyyy-MM-dd 格式并按预期反序列化它 - 至少当它是@RequestBody。因此,如果以下是 POST 的请求正文

{
"date": 2017-01-01
}

系统将请求体反序列化为EntityPost正如预期的那样。

但是,该配置不适用于反序列化@RequestParam。结果,这失败了:

// fail!
/entity?date=2017-01-01

相反,系统似乎需要 MM/dd/yy 格式。结果,成功了:

// success!
/entity?date=01/01/17

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

@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以同样的方式?

以供参考:

我正在使用春天4.3.2.发布

我正在使用杰克逊2.6.5


根据评论中的 @Andreas,Spring 框架使用 Jackson 进行反序列化@RequestBody但 Spring 本身反序列化@RequestParam。这就是两者差异的根源。

This answer https://stackoverflow.com/questions/40644368/setting-default-datetimeformat-annotation-in-spring显示如何使用@ControllerAdvice and @InitBinder自定义反序列化@RequestParam。我最终使用的代码如下:

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()));
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring 反序列化 @RequestBody 中的 LocalDate 与 @RequestParam 中的 LocalDate 不同 - 为什么,它们可以相同吗? 的相关文章

  • 如何准确判断 double 是否为整数? [复制]

    这个问题在这里已经有答案了 具体来说 在 Java 中 我如何确定double是一个整数 为了澄清 我想知道如何确定 double 实际上不包含任何分数或小数 我主要关心的是浮点数的性质 我想到的方法 以及我通过谷歌找到的方法 基本上遵循以
  • 获取Android库中的上下文

    我正在编写一个 Android 应用程序 它的一些功能封装在内部库中 但是 要使此功能发挥作用 库需要一个应用程序上下文的实例 为图书馆提供这种上下文的最佳方式是什么 我看到了一些选择 但没有一个有吸引力 Have my library c
  • 将 json 反序列化为对象:包装类解决方法

    这是我的 json accessType Grant spaces spaceId 5c209ba0 e24d 450d 8f23 44a99e6ae415 privilegeId db7cd037 6503 4dbf 8566 2cca4
  • Java Junit 测试 HTTP POST 请求

    我需要测试以下方法而不改变方法本身 该方法向服务器发出 POST 方法 但我需要制作一个独立于服务器的测试用例 在将其重定向到本地文件之前 我测试了类似的方法 但为此我将协议指定为文件 主机名指定为 localhost 端口指定为 1 我的
  • 但是创建静态实用方法不应该被过度使用吗?如何避免呢? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 随着时间的推移 java项目中引入了许多实用方法来完成更复杂和简单的任务 当使用静态方法时 我们在代码中引入了紧密耦合 这使得我们的代
  • 如何在Netbeans中设置JList的ListModel?

    我在 Netbeans IDE 的帮助下设计了一个 Swing GUI 该 GUI 包含一个 JList 默认情况下 它使用 QAbstractListModel 将其作为 JList 构造函数中的参数传递以创建该 JList 我想在 Ne
  • 如何在 Eclipse 中获得完全限定的类名?

    有没有一种快速方法可以在 Eclipse 中单击 Java 类并获取其完全限定名称 或将其复制到剪贴板 2016年6月29日编辑 正如 Jeff 所指出的 您只需要执行以下第二步 1 Double click on the class na
  • 避免 @Secured 注释的重复值

    我正在尝试使用以下方法来保护我的服务方法 Secured如下 public interface IUserService Secured ROLE ROLE1 ROLE ROLE2 ResponseEntity saveUser Creat
  • 在Java中如何将字节数组转换为十六进制?

    我有一个字节数组 我希望该数组的每个字节字符串转换为其相应的十六进制值 Java中有没有将字节数组转换为十六进制的函数 byte bytes 1 0 1 2 3 StringBuilder sb new StringBuilder for
  • RxJava android mvp 单元测试 NullPointerException

    我是 mvp 单元测试的新手 我想对演示者进行一个非常基本的测试 它负责登录 我只想断言 view onLoginSuccess 这是演示者代码 public LoginPresenter LoginViewContract loginVi
  • 错误膨胀类 android.support.design.widget.NavigationView [启动时崩溃]

    该应用程序应该有一个导航抽屉 可以从左侧拉出并显示各种活动 但是一旦将导航栏添加到 XML Activity homescreen 文档中 应用程序一启动就会崩溃 主屏幕 java package com t99sdevelopment c
  • Java HashSet 是线程安全的只读吗?

    如果我通过 Collections unmodifyingSet 运行 HashSet 实例后 它是线程安全的吗 我问这个是因为 Set 文档声明它不是 但我只是执行读取操作 来自 Javadoc 请注意 此实现不是同步的 如果多个线程同时
  • JPA Web 应用程序管理策略

    我们目前正在开发一个 J2EE Web 应用程序 使用 JPA 作为我们的数据访问层 我们目前正在研究几种不同的策略来在我们的应用程序中利用缓存 Create an EntityManager per request 在请求范围内获取缓存
  • 无法连接到docker中的elasticsearch容器

    我正在尝试使用 docker 的官方 elasticsearch 镜像 我遵循了本指南 https www elastic co guide en elasticsearch reference current docker html但是当
  • java.lang.UnsatisfiedLinkError - android studio gradle 中的 NDK?

    文件夹结构 app main java jni Android mk Application mk hello jni c res 在构建 gradle apply plugin com android application androi
  • 如何在 Spring Mvc 项目中设置上下文根

    我在 Tomcat 服务器中使用 Spring MVC 项目 每次运行应用程序时 服务器上下文根都会更改 如何设置固定上下文根 我的项目名称是 DemoApplication 首先部署此上下文根 路径是 http localhost 808
  • 为什么 java.util.Arraylist#clear 按照 OpenJDK 中的方式实现?

    http grepcode com file repository grepcode com java root jdk openjdk 6 b14 java util ArrayList java 473 http grepcode co
  • 为什么不能在 if 语句中声明变量?

    以下 Java 代码无法编译 int a 0 if a 1 int b 0 if a 1 b 1 为什么 不能有任何代码路径导致程序将 1 分配给b无需先声明 我突然想到b的变量范围可能仅限于第一个if声明 但后来我不明白为什么 如果我实在
  • 在java中执行匿名pl/sql块并获取结果集

    我想执行匿名 PL SQL 并需要获取结果集对象 我得到了可以通过在 PL SQL 块内使用游标来完成的代码 但 PL SQL 块本身将以文本形式来自数据库 所以我无法编辑该 PL SQL 块 并且它只会返回两个值 其列名始终相同 它将返回
  • 检查按钮是否可用?如果没有,请等待 5 秒钟,然后再次检查?

    基本上我想看看此刻是否可以单击按钮 如果没有我想再试一次 所以我需要某种 goto 函数来返回到代码的前一行 尽管我怀疑我写得非常糟糕 但它本来可以做得更容易 try driver findElement By xpath button i

随机推荐