14 KiB
提示词:日期格式化功能实现
引用真源
需求描述
根据需求文档,实现日期格式化功能,支持用户设置日期格式偏好,根据用户日期格式偏好显示日期。核心需求包括:
-
日期格式化功能:
- 支持常用日期格式(ISO 8601、欧洲、美国、中国等)
- 支持日期时间格式化(短格式、长格式)
- 支持长短日期格式
- 使用 java.time.format.DateTimeFormatter 进行格式化
- 支持多语言日期显示(星期几、月份名称的本地化)
-
时区转换功能:
- 结合时区转换功能,支持跨时区日期格式化
- 自动将 UTC 时间转换为用户时区
- 支持用户时区偏好
- 支持系统默认时区
- 时区转换准确无误
-
多语言支持功能:
- 支持多语言日期显示
- 支持星期几的本地化(中文:星期一;英文:Monday)
- 支持月份名称的本地化(中文:一月;英文:January)
- 支持常用语言(中文、英文等)
- 根据用户语言偏好自动选择语言
-
用户日期格式偏好管理:
- 获取当前用户日期格式偏好
- 切换用户日期格式偏好
- 获取系统默认日期格式
- 获取常用日期格式列表
- 支持用户日期格式偏好覆盖系统默认设置
-
自动日期格式化:
- 在 Service 层自动进行日期格式化
- 使用 AOP 切面拦截 Service 方法返回值
- 自动识别 Date、LocalDate、LocalDateTime 类型字段
- 根据用户日期格式偏好自动格式化
- 结合时区转换功能,先进行时区转换,再进行日期格式化
- 格式化逻辑统一,避免重复代码
-
缓存管理:
- 用户日期格式偏好使用 Redis 缓存,TTL = 24 小时
- 系统默认日期格式使用 Redis 缓存,TTL = 24 小时
- DateTimeFormatter 实例使用 ConcurrentHashMap 缓存,永久缓存
- 用户切换日期格式时清除缓存
- 系统默认日期格式更新时清除缓存
设计方案
根据设计文档,采用以下技术方案:
-
日期格式化技术:java.time.format.DateTimeFormatter
- 使用 DateTimeFormatter 的模式字符串定义日期格式(例如:
yyyy-MM-dd) - 使用 ofPattern() 方法创建格式化器
- 使用 withLocale() 方法设置语言环境
- 使用 ConcurrentHashMap 缓存 DateTimeFormatter 实例,提高性能
- 支持自定义日期格式模式
- 使用 DateTimeFormatter 的模式字符串定义日期格式(例如:
-
缓存技术:Redis
- 使用现有的 CacheUtils 工具类
- 性能优秀,响应时间 < 1ms
- 支持分布式部署
-
数据库技术:MySQL 8.3.0
- 修改 sys_user 表添加 date_format 和 date_format_pattern 字段
- 使用 sys_config 表存储系统默认日期格式配置
- 使用 sys_config 表存储常用日期格式配置
-
框架技术:Spring Boot 3.5.7 + 若依框架
- 使用 Spring Security 认证机制
- 使用若依的权限控制机制(@PreAuthorize)
- 使用若依的日志记录机制(@Log)
- 使用若依的异常处理机制(GlobalExceptionHandler)
-
架构设计:
- 前端层(Vue 3)→ Controller 层 → Service 层 → Mapper 层 → 数据库层(MySQL)→ 缓存层(Redis)
- 时区转换在 Service 层进行,使用 TimeZoneConvertAspect 切面拦截
- 日期格式化在 Service 层进行,使用 DateFormatAspect 切面拦截
- 切面执行顺序:TimeZoneConvertAspect 先于 DateFormatAspect
输出格式要求
1. 必须包含以下文件
Controller 层
-
SysUserController.java(路径:
datai-admin/src/main/java/com/datai/web/controller/system/SysUserController.java)- 接口:
- GET /system/user/dateFormat - 获取当前用户日期格式偏好
- POST /system/user/switchDateFormat - 切换用户日期格式偏好
- 使用 @RestController、@RequestMapping、@PreAuthorize 注解
- 使用 @Log 注解(com.datai.common.annotation.Log)记录操作日志
- 使用 @Operation 注解(io.swagger.v3.oas.annotations.Operation)添加 Swagger 文档
- 接口:
-
SysConfigController.java(路径:
datai-admin/src/main/java/com/datai/web/controller/system/SysConfigController.java)- 接口:
- GET /system/dateFormat/default - 获取系统默认日期格式
- GET /system/dateFormat/list - 获取常用日期格式列表
- 使用 @RestController、@RequestMapping、@PreAuthorize 注解
- 使用 @Log 注解(com.datai.common.annotation.Log)记录操作日志
- 使用 @Operation 注解(io.swagger.v3.oas.annotations.Operation)添加 Swagger 文档
- 接口:
Service 层
-
ISysUserService.java(路径:
datai-system/src/main/java/com/datai/system/service/ISysUserService.java)- 方法:
- String getUserDateFormat(Long userId)
- void updateUserDateFormat(Long userId, String dateFormat, String dateFormatPattern)
- 方法:
-
SysUserServiceImpl.java(路径:
datai-system/src/main/java/com/datai/system/service/impl/SysUserServiceImpl.java)- 实现 ISysUserService 接口
- 使用 @Service 注解
- 集成 Redis 缓存
- 实现用户日期格式偏好管理逻辑
Utils 层
- DateFormatUtils.java(路径:
datai-common/src/main/java/com/datai/common/utils/DateFormatUtils.java)- 方法:
- String formatDate(LocalDate date, String pattern)
- String formatDateTime(LocalDateTime dateTime, String pattern)
- String formatDate(LocalDate date, String pattern, Locale locale)
- String formatDateTime(LocalDateTime dateTime, String pattern, Locale locale)
- String format(Date date, String pattern)
- String format(Date date, String pattern, Locale locale)
- LocalDate parseDate(String dateStr, String pattern)
- LocalDateTime parseDateTime(String dateTimeStr, String pattern)
- String getUserDateFormat(Long userId)
- String getSystemDefaultDateFormat()
- String getSystemDefaultDateTimeFormat()
- 使用 java.time.format.DateTimeFormatter
- 使用 java.text.SimpleDateFormat(兼容 Date 类型)
- 使用 ConcurrentHashMap 缓存 DateTimeFormatter 实例
- 处理 null 值和无效日期格式
- 方法:
Aspect 层
- DateFormatAspect.java(路径:
datai-framework/src/main/java/com/datai/framework/aspectj/DateFormatAspect.java)- 使用 @Aspect、@Component 注解
- 使用 @Around 切面拦截 Service 方法返回值
- 自动格式化日期字段(包括 Date、LocalDate、LocalDateTime 类型)
- 提供 @DateFormat 注解标记需要格式化的 Service 方法
- 递归处理嵌套对象的日期字段
- 避免循环引用导致的无限递归
- 结合时区转换功能,先进行时区转换,再进行日期格式化
- 使用 @Order 注解控制切面执行顺序(确保 TimeZoneConvertAspect 先于 DateFormatAspect)
注解
- @DateFormat.java(路径:
datai-common/src/main/java/com/datai/common/annotation/DateFormat.java)- 标记需要格式化的方法
- 支持自定义日期格式配置
- 支持多语言配置
常量
- DateConstants.java(路径:
datai-common/src/main/java/com/datai/common/constant/DateConstants.java)- 定义常用日期格式常量(ISO 8601、欧洲、美国、中国)
- 定义日期格式模式映射
- 提供获取日期格式的方法
修改现有文件
-
SysUser.java(路径:
datai-common/src/main/java/com/datai/common/core/domain/entity/SysUser.java)- 添加 dateFormat 字段
- 添加 dateFormatPattern 字段
- 添加 getter 和 setter 方法
-
CacheConstants.java(路径:
datai-common/src/main/java/com/datai/common/constant/CacheConstants.java)- 添加用户日期格式缓存常量(SYS_DATE_FORMAT_KEY)
- 添加系统默认日期格式缓存常量(SYS_DEFAULT_DATE_FORMAT_KEY)
2. 必须包含单元测试
-
DateFormatUtilsTest.java(路径:
datai-common/src/test/java/com/datai/common/utils/DateFormatUtilsTest.java)- 测试日期格式化功能
- 测试日期时间格式化功能
- 测试多语言日期显示功能
- 测试 null 值处理
- 测试无效日期格式处理
- 测试自定义日期格式
- 测试 Locale 处理
-
DateFormatAspectTest.java(路径:
datai-framework/src/test/java/com/datai/framework/aspectj/DateFormatAspectTest.java)- 测试 AOP 切面功能
- 测试 Date 字段格式化
- 测试 LocalDate 字段格式化
- 测试 LocalDateTime 字段格式化
- 测试嵌套对象格式化
- 测试循环引用处理
- 测试多语言格式化
3. 必须包含常量定义
- DateConstants.java(路径:
datai-common/src/main/java/com/datai/common/constant/DateConstants.java)- 定义常用日期格式常量(DATE_FORMAT_ISO8601、DATE_FORMAT_EUROPE、DATE_FORMAT_USA、DATE_FORMAT_CHINA)
- 定义日期时间格式常量(DATETIME_FORMAT_SHORT、DATETIME_FORMAT_LONG)
- 定义日期格式映射(DATE_FORMATS)
- 提供获取日期格式的方法(getDateFormat)
代码规范要求
1. 命名规范
- 类名:使用大驼峰命名(例如:DateFormatUtils、DateConstants)
- 方法名:使用小驼峰命名(例如:formatDate、getUserDateFormat)
- 变量名:使用小驼峰命名(例如:dateFormat、locale)
- 常量名:使用全大写下划线命名(例如:DATE_FORMAT_ISO8601、DEFAULT_DATE_FORMAT)
2. 注释规范
- 类注释:使用 JavaDoc 格式,包含类描述、作者、日期
- 方法注释:使用 JavaDoc 格式,包含方法描述、参数说明、返回值说明
- 字段注释:使用单行注释,说明字段用途
- 复杂逻辑注释:使用多行注释,说明逻辑思路
3. 异常处理
- 使用若依的异常处理机制(GlobalExceptionHandler)
- 自定义异常使用 ServiceException(com.datai.common.exception.ServiceException)
- 异常信息使用国际化消息(MessageUtils.message)
- 记录异常日志(log.error)
4. 日志记录
- 使用若依的日志记录机制(@Log 注解)
- 记录关键操作(切换日期格式)
- 日志信息使用国际化消息(MessageUtils.message)
- @Log 注解参数:
- title:模块名称
- businessType:业务类型(BusinessType.INSERT、BusinessType.UPDATE、BusinessType.DELETE、BusinessType.OTHER)
- operatorType:操作人类别(OperatorType.MANAGE、OperatorType.OTHER)
- isSaveRequestData:是否保存请求的参数(默认 true)
- isSaveResponseData:是否保存响应的参数(默认 true)
- excludeParamNames:排除指定的请求参数
5. 权限控制
- 使用若依的权限控制机制(@PreAuthorize)
- 接口权限使用若依的权限标识(system:config:query 等)
- 用户日期格式偏好接口不需要权限(需要登录)
6. 缓存使用
- 使用 CacheUtils 工具类进行缓存操作(com.datai.common.utils.CacheUtils)
- 缓存键使用 CacheConstants 中定义的常量
- 缓存方法:
- put(cacheName, key, value) - 缓存数据
- put(cacheName, key, value, timeout, unit) - 缓存数据并设置过期时间
- get(cacheName, key) - 获取缓存数据
- get(cacheName, key, type) - 根据类型获取缓存数据
- remove(cacheName, key) - 移除缓存数据
- clear(cacheName) - 清除所有缓存数据
- 缓存更新时清除相关缓存
- 缓存时间根据业务需求设置(用户日期格式 24 小时、系统默认日期格式 24 小时)
7. 数据库操作
- 使用 MyBatis 进行数据库操作
- Mapper 接口不使用 @Mapper 注解
- Mapper 接口不继承 BaseMapper
- Mapper 接口定义标准的 MyBatis 方法
- 自定义 SQL 在 Mapper.xml 中定义
- 使用 resultMap 映射结果
- 使用 parameterType 定义参数类型
8. 切面顺序控制
- 使用 @Order 注解控制切面执行顺序
- 确保 TimeZoneConvertAspect 先于 DateFormatAspect
- DateFormatAspect 的 Order 值应该大于 TimeZoneConvertAspect 的 Order 值
测试要求
1. 单元测试
- 测试覆盖率 ≥ 80%
- 测试所有公共方法
- 测试边界条件(null 值、空值、无效值)
- 测试异常情况(无效日期格式、Locale 不支持)
- 使用 JUnit 5 进行测试
- 使用 Mockito 进行 Mock
2. 集成测试
- 测试用户日期格式偏好接口
- 测试系统默认日期格式接口
- 测试常用日期格式列表接口
- 测试 AOP 切面功能
- 测试缓存功能
- 测试多语言日期显示功能
- 测试时区转换 + 日期格式化集成功能
3. 手动测试
- 测试不同日期格式的格式化
- 测试多语言日期显示
- 测试时区转换 + 日期格式化
- 测试用户日期格式偏好切换
- 测试缓存功能
- 测试嵌套对象格式化
注意事项
- 数据类型:日期数据使用 Date、LocalDate、LocalDateTime 类型
- 时区转换:结合时区转换功能,先进行时区转换,再进行日期格式化
- 多语言支持:使用 Locale 进行本地化,支持多语言日期显示
- 缓存一致性:分布式环境下保证缓存一致性
- 循环引用:AOP 切面处理嵌套对象时,避免循环引用导致的无限递归
- 切面顺序:使用 @Order 注解控制切面执行顺序,确保 TimeZoneConvertAspect 先于 DateFormatAspect
- 性能优化:使用 ConcurrentHashMap 缓存 DateTimeFormatter 实例,提高格式化性能
- 代码复用:日期格式化逻辑统一在 AOP 切面中,避免重复代码
- 国际化支持:日期格式化支持国际化,自动处理不同地区的日期格式
- 错误处理:日期格式化失败时,返回友好的错误提示
- 日志记录:记录关键操作日志,便于审计和问题排查
- 时区转换复用:复用已实现的 TimeZoneConvertAspect,避免重复开发
- 国际化复用:复用已实现的国际化功能,避免重复开发
- DateTimeFormatter 缓存:使用 ConcurrentHashMap 缓存 DateTimeFormatter 实例,避免重复创建
- SimpleDateFormat 使用:SimpleDateFormat 不是线程安全的,每次使用时创建新实例