当前位置: 首页 > news >正文

使用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()测试方法,测试通过。

http://www.cnnetsun.cn/news/3272658.html

相关文章:

  • elasticsearch学习笔记(三十五)——Elasticsearch 索引管理
  • 5分钟打造你的专属知识中心:Obsidian Homepage完全指南
  • Go error 处理:errors.Is/As 与错误包装
  • 【小白也能轻松玩转龙虾】虾壳云一键部署一站式操作,下载解压启用 OpenClaw v2.7.9(附最新安装包)
  • 设计师怎么把 GPT-Image 当作灵感草图工具?从创意到提案的实战流转指南
  • 2. 文字处理
  • Linux diffstat 命令详解
  • Oracle
  • 3分钟搞定B站缓存视频转换:m4s-converter完全指南
  • 智能时代官网Geo内容优化策略:构建AI可信赖的信息枢纽
  • 意念控制机器人:从脑机接口到远程意念指令的无限可能
  • Git 同步 Obsidian 和 Nutstore Sync 怎么选?两种方案的区别、适用场景和选择建议
  • 解密微信QQ防撤回:告别消息消失的终极方案
  • 海康摄像头RTSP流问题 method DESCRIBE failed: 401 Unauthorized
  • Alacritty配置优化:Catppuccin主题与其他工具的集成方案
  • Appium自动化测试入门:从环境搭建到第一个脚本编写
  • 如何为阿里云 Elasticsearch 创建推理端点,连接器,Workflow 并写入数据
  • OpenAI 推出 GPT-Live:告别回合制,AI 语音交互体验大升级!
  • ITIL 4 DPI认证信息整理
  • RimSort终极指南:告别《边缘世界》模组冲突的5个高效技巧
  • Typora绘制-用户旅程图
  • 私有化部署RustDesk中继服务器
  • 微软 Project Solara 展示 AI 工牌与智控中枢,卡片式 AI 硬件成手机外设新趋势
  • Reactive Resume深度调试指南:从模板渲染到容器部署的5大技术挑战
  • 前OpenAI安全副总裁翁荔新博客:AI自进化或先从Harness开始,揭示现实路径与瓶颈
  • Oracle EBS 12.2 审计追踪
  • EN 18031标准落地经验:联网无线电设备网络安全合规的关键节点与常见误区
  • AI 指标异动分析:先判断是业务事件还是数据 bug
  • ModelScope命令行工具终极实战:从零到精通的AI模型管理指南
  • MySQL学习第四天