news 2026/7/10 22:24:30

使用LocalDate和LocalDateTime接收日期时间

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用LocalDate和LocalDateTime接收日期时间

Java8推出了新的日期时间API,位于java.time包下。在使用SpringBoot搭建前后端分离的项目,提供Restful风格的Http接口时,肯定会遇到提供日期时间查询的需求。因为Spring目前暂不支持自动转换为LocalDateLocalDataTime,所以需要进行配置,以支持使用LocalDateLocalDataTime来接收日期时间字段。

项目演示

创建名为14-timemaven项目pom文件如下

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-parent</artifactId> <version>2.1.6.RELEASE</version> </parent> <artifactId>14-time</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> <build> <plugins> <!-- 指定jdk --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>

1.编写App

package com.zccoder.demo.time; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 启动类 * * @author zc 2019-08-30 */ @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }

2.编写RequestBean

package com.zccoder.demo.time.domain; import javax.validation.constraints.NotNull; import java.io.Serializable; import java.time.LocalDate; import java.time.LocalDateTime; /** * 请求对象 * * @author zc 2019-08-30 */ public class RequestBean implements Serializable { @NotNull private LocalDate startDate; @NotNull private LocalDateTime startTime; @Override public String toString() { return "RequestBean{" + "startDate=" + startDate + ", startTime=" + startTime + '}'; } public LocalDate getStartDate() { return startDate; } public void setStartDate(LocalDate startDate) { this.startDate = startDate; } public LocalDateTime getStartTime() { return startTime; } public void setStartTime(LocalDateTime startTime) { this.startTime = startTime; } }

3.编写ResponseBean

package com.zccoder.demo.time.domain; import java.io.Serializable; import java.time.LocalDate; import java.time.LocalDateTime; /** * 响应对象 * * @author zc 2019-08-30 */ public class ResponseBean implements Serializable { private LocalDate resultDate; private LocalDateTime resultTime; @Override public String toString() { return "ResponseBean{" + "resultDate=" + resultDate + ", resultTime=" + resultTime + '}'; } public LocalDate getResultDate() { return resultDate; } public void setResultDate(LocalDate resultDate) { this.resultDate = resultDate; } public LocalDateTime getResultTime() { return resultTime; } public void setResultTime(LocalDateTime resultTime) { this.resultTime = resultTime; } }

4.编写TimeController

package com.zccoder.demo.time.controller; import com.zccoder.demo.time.domain.RequestBean; import com.zccoder.demo.time.domain.ResponseBean; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; /** * 时间控制层 * * @author zc 2019-08-30 */ @Validated @RestController @RequestMapping("/time") public class TimeController { /** * 增加一天 * * @param requestBean 请求对象 * @return 响应对象 */ @GetMapping public ResponseBean plusOneDay(@Valid RequestBean requestBean) { ResponseBean responseBean = new ResponseBean(); responseBean.setResultDate(requestBean.getStartDate().plusDays(1)); responseBean.setResultTime(requestBean.getStartTime().plusDays(1)); return responseBean; } }

5.编写AppTestSupport

package com.zccoder.demo.time; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; /** * 单元测试基类 * * @author zc 2019-08-30 */ @RunWith(SpringRunner.class) @SpringBootTest public abstract class AppTestSupport { @Autowired private WebApplicationContext webApplicationContext; @Autowired protected ObjectMapper objectMapper; protected MockMvc mockMvc; @Before public void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } }

6.编写TimeControllerTest

package com.zccoder.demo.time.controller; import com.fasterxml.jackson.core.type.TypeReference; import com.zccoder.demo.time.AppTestSupport; import com.zccoder.demo.time.domain.ResponseBean; import org.junit.Test; import org.springframework.http.MediaType; import org.springframework.util.LinkedMultiValueMap; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * 时间控制层测试类 * * @author zc 2019-08-30 */ public class TimeControllerTest extends AppTestSupport { /** * 增加一天 */ @Test public void plusOneDay() throws Exception { // 构建请求参数 LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(4); params.add("startDate", "2019-08-30"); params.add("startTime", "2019-08-30 22:36:20"); // 执行调用请求 String response = mockMvc.perform(get("/time") .contentType(MediaType.APPLICATION_JSON_UTF8) .params(params)) .andExpect(status().isOk()) .andReturn() .getResponse() .getContentAsString(); TypeReference<ResponseBean> typeReference = new TypeReference<ResponseBean>() { }; ResponseBean responseBean = objectMapper.readValue(response, typeReference); System.out.println(responseBean); } }

执行TimeControllerTestplusOneDay()测试方法,由于Spring目前暂不支持自动转换为LocalDateLocalDataTime,测试失败。

我们通过查看控制台日志,发现如下输出

Field error in object 'requestBean' on field 'startDate': rejected value [2019-08-30]; codes [typeMismatch.requestBean.startDate,typeMismatch.startDate,typeMismatch.java.time.LocalDate,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [requestBean.startDate,startDate]; arguments []; default message [startDate]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDate' for property 'startDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDate] for value '2019-08-30'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2019-08-30]] Field error in object 'requestBean' on field 'startTime': rejected value [2019-08-30 22:36:20]; codes [typeMismatch.requestBean.startTime,typeMismatch.startTime,typeMismatch.java.time.LocalDateTime,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [requestBean.startTime,startTime]; arguments []; default message [startTime]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDateTime' for property 'startTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime] for value '2019-08-30 22:36:20'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2019-08-30 22:36:20]]]

通过分析日志,找到原因是缺少转换字段类型为LocalDateLocalDataTimeorg.springframework.format.Formatter

配置Formatter

1.编写LocalDateFormatter

package com.zccoder.demo.time.config; import org.springframework.format.Formatter; import java.text.ParseException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Locale; /** * 日期格式化 * * @author zc 2019-08-30 */ public class LocalDateFormatter implements Formatter<LocalDate> { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @Override public LocalDate parse(String text, Locale locale) throws ParseException { return LocalDate.parse(text, formatter); } @Override public String print(LocalDate localDate, Locale locale) { return formatter.format(localDate); } }

2.编写LocalDateTimeFormatter

package com.zccoder.demo.time.config; import org.springframework.format.Formatter; import java.text.ParseException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; /** * 日期时间格式化 * * @author zc 2019-08-30 */ public class LocalDateTimeFormatter implements Formatter<LocalDateTime> { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override public LocalDateTime parse(String text, Locale locale) throws ParseException { return LocalDateTime.parse(text, formatter); } @Override public String print(LocalDateTime localDateTime, Locale locale) { return formatter.format(localDateTime); } }

3.编写MvcConfig

package com.zccoder.demo.time.config; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.time.LocalDate; import java.time.LocalDateTime; /** * MVC配置类 * * @author zc 2019-08-30 */ @Configuration public class MvcConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addFormatterForFieldType(LocalDate.class, new LocalDateFormatter()); registry.addFormatterForFieldType(LocalDateTime.class, new LocalDateTimeFormatter()); } }

4.再次执行TimeControllerTestplusOneDay()测试方法,测试通过。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/10 22:24:15

5分钟打造你的专属知识中心:Obsidian Homepage完全指南

5分钟打造你的专属知识中心&#xff1a;Obsidian Homepage完全指南 【免费下载链接】obsidian-homepage Obsidian homepage - Minimal and aesthetic template (with my unique features) 项目地址: https://gitcode.com/gh_mirrors/obs/obsidian-homepage 你是否厌倦了…

作者头像 李华
网站建设 2026/7/10 22:22:49

Go error 处理:errors.Is/As 与错误包装

Go error 处理:errors.Is/As 与错误包装 Go 的错误处理一直被吐槽啰嗦,但真正让人头疼的不是 if err ! nil 写得多,而是错误传到上层就"失真"了。你在最底层返回了 sql.ErrNoRows,一路 return err 传上来,到 handler 里想判断"是不是记录不存在",结果发现要…

作者头像 李华
网站建设 2026/7/10 22:17:46

2. 文字处理

2. 文字处理文字处理概述文档编辑新建文档打开文档保存文档文件打印与打印预览文档关闭与文档保护小结界面认识上半区域标题栏、窗口控制按钮、快速访问工具栏功能选项卡和组中间区域下半区域小结文字排版与应用文字编辑文本的录入文本的选择文本的复制与移动文本的删除文本的撤…

作者头像 李华