对于解析日期,我根本不建议使用基于正则表达式的验证器。相反,您可以 - 例如 - 使用带有查询字符串绑定器的自定义案例类,它将对传入参数进行类型安全的解析:
package models
import java.time.LocalDate
import java.time.format.{DateTimeFormatter, DateTimeParseException}
import play.api.mvc.QueryStringBindable
case class BirthDate(date: LocalDate)
object BirthDate {
private val dateFormatter: DateTimeFormatter = DateTimeFormatter.ISO_DATE // or whatever date format you're using
implicit val queryStringBindable = new QueryStringBindable[BirthDate] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, BirthDate]] = {
params.get(key).flatMap(_.headOption).map { value =>
try {
Right(BirthDate(LocalDate.parse(value, dateFormatter)))
} catch {
case _: DateTimeParseException => Left(s"$value cannot be parsed as a date!")
}
}
}
override def unbind(key: String, value: BirthDate): String = {
s"$key=${value.date.format(dateFormatter)}"
}
}
}
现在,如果您更改您的路线配置,因此birthDate
是 type 的参数Option[BirthDate]
,您将获得您想要的行为。
如果您坚持使用正则表达式,您可以使用基于正则表达式的解析器来代替日期格式化程序并使用BirthDate
wrap aString
而不是 a LocalDate
,但是对于所呈现的用例,我真的看不出这样做的好处是什么.
编辑:为了完整起见,基于正则表达式的变体:
case class BirthDate(date: String)
object BirthDate {
private val regex = "([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))".r
implicit val queryStringBindable = new QueryStringBindable[BirthDate] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, BirthDate]] = {
params.get(key).flatMap(_.headOption).map { value =>
regex.findFirstIn(value).map(BirthDate.apply).toRight(s"$value cannot be parsed as a date!")
}
}
override def unbind(key: String, value: BirthDate): String = {
s"$key=${value.date}"
}
}
}