Spring Boot如何接收阿拉伯数字格式的日期查询参数?
Spring Boot 解析阿拉伯数字格式日期查询参数
问题场景
需要在Spring Boot应用中接收阿拉伯-Indic数字格式的日期作为查询参数(例如٢٠٢١-٠٧-٢٠对应英文日期2021-07-20),已实现单独解析该格式的代码,但使用@DateTimeFormat(pattern = "yyyy-MM-dd")绑定LocalDate参数时,会抛出类型转换错误:
org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'dateRange' on field 'fromDate': rejected value [٢٠٢١-٠٧-٢٠]; codes [typeMismatch.dateRange.fromDate,typeMismatch.fromDate,typeMismatch.java.time.LocalDate,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [dateRange.fromDate,fromDate]; arguments []; default message [fromDate]]; default message [Failed to convert value of type 'java.lang.String[]' to required type 'java.time.LocalDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.format.annotation.DateTimeFormat java.time.LocalDate] for value '٢٠٢١-٠٧-٢٠'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [٢٠٢١-٠٧-٢٠]]
解决方案
通过自定义LocalDate转换器并注册到Spring的转换体系中,替换默认的日期解析逻辑,同时兼容阿拉伯数字格式和普通数字格式的日期。
1. 实现自定义日期转换器
创建Converter<String, LocalDate>实现类,集成阿拉伯数字日期解析逻辑,同时保留默认ISO格式的兼容:
import org.springframework.core.convert.converter.Converter; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DecimalStyle; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; public class ArabicLocalDateConverter implements Converter<String, LocalDate> { private final DateTimeFormatter arabicDateFormatter; private final DateTimeFormatter defaultDateFormatter; public ArabicLocalDateConverter() { // 初始化阿拉伯-Indic数字格式的日期解析器 DecimalStyle defaultDecimalStyle = DateTimeFormatter.ISO_LOCAL_DATE.getDecimalStyle(); this.arabicDateFormatter = DateTimeFormatter.ISO_LOCAL_DATE .withDecimalStyle(defaultDecimalStyle.withZeroDigit('\u0660')); // 保留默认ISO日期格式解析,兼容普通数字日期 this.defaultDateFormatter = DateTimeFormatter.ISO_LOCAL_DATE; } @Override public LocalDate convert(String source) { try { // 解码URL编码的日期字符串(处理前端传递的编码参数) String decodedSource = URLDecoder.decode(source, StandardCharsets.UTF_8); // 优先尝试阿拉伯数字格式解析 return LocalDate.parse(decodedSource, arabicDateFormatter); } catch (Exception arabicParseEx) { // 阿拉伯格式解析失败,尝试默认ISO格式 try { return LocalDate.parse(source, defaultDateFormatter); } catch (Exception defaultParseEx) { throw new IllegalArgumentException("无法解析日期参数:" + source, defaultParseEx); } } } }
2. 注册自定义转换器
通过WebMvcConfigurer配置类,将自定义转换器添加到Spring的格式化注册表中:
import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { // 注册自定义LocalDate转换器,覆盖默认转换逻辑 registry.addConverter(new ArabicLocalDateConverter()); } }
3. 调整参数绑定方式
在接口参数中直接使用LocalDate类型,无需再添加@DateTimeFormat注解,转换器会自动处理两种格式的日期:
// 示例Controller方法 @GetMapping("/query") public ResponseEntity<String> queryByDateRange(@RequestParam LocalDate fromDate) { // 业务逻辑处理 return ResponseEntity.ok("解析后的日期:" + fromDate); }
原理说明
Spring默认的LocalDate转换器依赖系统默认的DecimalStyle,仅支持ASCII数字(0-9)。自定义转换器通过指定阿拉伯-Indic数字的零字符(\u0660),修改DateTimeFormatter的数字解析规则,从而支持阿拉伯数字格式的日期解析,同时兼容原有普通日期格式。
内容的提问来源于stack exchange,提问作者Mohamd Ali
相关产品推荐
相关产品推荐

