Scala 返回多个错误的验证
我正在使用较旧的Scala版本(2.0)进行一些验证,但是对于每个记录,我目前只得到1个错误,假设该记录有2个或更多错误——我希望接收该记录/项的所有错误Scala 返回多个错误的验证,scala,Scala,我正在使用较旧的Scala版本(2.0)进行一些验证,但是对于每个记录,我目前只得到1个错误,假设该记录有2个或更多错误——我希望接收该记录/项的所有错误 case class Response(request: JsValue, success: Boolean, column: Option[String] = None, message: String = "") 这里是验证器,它返回json对象中的所有错误 def validator(asJson: JsVal
case class Response(request: JsValue,
success: Boolean,
column: Option[String] = None,
message: String = "")
这里是验证器,它返回json对象中的所有错误
def validator(asJson: JsValue): Response = {
if (name == "")
return Response(asJson, false, Some("name"), "Name can't be blank")
if (age == -1 || age == "N/A")
return Response(asJson, false, Some("age"), "Age can't be blank")
if (DOB == -1 || DOB == "N/A" )
return Response(asJson, false, Some("DOB"), "DOB cannot be blank")
else
Response(asJson, true)
}
目前如果record1
没有姓名+年龄+出生日期-->我只得到“姓名不能为空”
如何获取(每个项目有多个错误,而不是每个项目只有一个错误):
Name不能为空,Age不能为空,DOB不能为空首先,在scala中没有
return
语句,最后一个语句被返回(事实上它存在,但不推荐使用)
其次,在您的代码中,我假设您希望传递几个if
语句。但是,如果在每个if
语句之后返回,则会在第一个条件为true时退出函数,并且永远不会转到代码的其余部分
如果要收集
响应的多个实例
,只需将它们收集到一个集合中,然后在函数末尾返回集合。集合可以是列表
,或序列
,或其他任何形式。首先,在scala中,您没有return
语句,最后一条语句被返回(事实上它存在,但不推荐使用)
其次,在您的代码中,我假设您希望传递几个if
语句。但是,如果在每个if
语句之后返回,则会在第一个条件为true时退出函数,并且永远不会转到代码的其余部分
如果要收集
响应的多个实例
,只需将它们收集到一个集合中,然后在函数末尾返回集合。集合可能是一个列表
,或序列
,或任何东西。这只是它如何工作的概述:
def validator(asJson: JsValue): Response = {
val errors = List(
if (name == "" ) Some("Name can't be blank") else None,
if (age == -1 || age == "N/A") Some("Age can't be blank") else None,
if (DOB == -1 || DOB == "N/A" ) Some("DOB cannot be blank") else None,
).flatten
if (errors.isEmpty) {
Response(asJson, true)
} else {
Response(asJson, false, errors.mkString(", "))
}
}
错误
值是通过对选项
值进行列表
创建的,每个验证检查一个值。flatten
方法提取所有Some
值的内容,并删除任何None
值。结果是错误字符串的列表
其余代码根据错误列表格式化响应
如果您使用的是Scala 2.13,则选项。当使测试更短、更清晰时:
Option.when(name == "")("Name can't be blank"),
Option.when(age == -1 || age == "N/A")("Age can't be blank"),
Option.when(DOB == -1 || DOB == "N/A")("DOB cannot be blank"),
这只是它如何工作的概述:
def validator(asJson: JsValue): Response = {
val errors = List(
if (name == "" ) Some("Name can't be blank") else None,
if (age == -1 || age == "N/A") Some("Age can't be blank") else None,
if (DOB == -1 || DOB == "N/A" ) Some("DOB cannot be blank") else None,
).flatten
if (errors.isEmpty) {
Response(asJson, true)
} else {
Response(asJson, false, errors.mkString(", "))
}
}
错误
值是通过对选项
值进行列表
创建的,每个验证检查一个值。flatten
方法提取所有Some
值的内容,并删除任何None
值。结果是错误字符串的列表
其余代码根据错误列表格式化响应
如果您使用的是Scala 2.13,则选项。当使测试更短、更清晰时:
Option.when(name == "")("Name can't be blank"),
Option.when(age == -1 || age == "N/A")("Age can't be blank"),
Option.when(DOB == -1 || DOB == "N/A")("DOB cannot be blank"),
是在某个点
中使用的替代方案
import play.api.libs.json._
import cats.data.ValidatedNec
import cats.implicits._
case class User(name: String, age: Int, dob: String)
case class UserDTO(name: Option[String], age: Option[Int], dob: Option[String])
implicit val userDtoFormat = Json.format[UserDTO]
val raw =
"""
|{
| "name": "Picard"
|}
|""".stripMargin
val userDto = Json.parse(raw).as[UserDTO]
def validateUser(userDto: UserDTO): ValidatedNec[String, User] = {
def validateName(user: UserDTO): ValidatedNec[String, String] =
user.name.map(_.validNec).getOrElse("Name is empty".invalidNec)
def validateAge(user: UserDTO): ValidatedNec[String, Int] =
user.age.map(_.validNec).getOrElse("Age is empty".invalidNec)
def validateDob(user: UserDTO): ValidatedNec[String, String] =
user.dob.map(_.validNec).getOrElse("DOB is empty".invalidNec)
(validateName(userDto), validateAge(userDto), validateDob(userDto)).mapN(User)
}
validateUser(userDto)
// res0: cats.data.ValidatedNec[String,User] = Invalid(Chain(Age is empty, DOB is empty))
请注意UserDTO
(“数据传输对象”)与User
之间的区别,前者为通过线路发送的任何有效负载建模,后者为业务逻辑所需的实际数据建模。我们将用户验证问题分离到它自己的方法validateUser
。现在我们可以处理有效用户或类似错误
validateUserDTO(userDto) match {
case Valid(user) =>
// do something with valid user
case Invalid(errors) =>
// do something with errors
}
是在某个点
中使用的替代方案
import play.api.libs.json._
import cats.data.ValidatedNec
import cats.implicits._
case class User(name: String, age: Int, dob: String)
case class UserDTO(name: Option[String], age: Option[Int], dob: Option[String])
implicit val userDtoFormat = Json.format[UserDTO]
val raw =
"""
|{
| "name": "Picard"
|}
|""".stripMargin
val userDto = Json.parse(raw).as[UserDTO]
def validateUser(userDto: UserDTO): ValidatedNec[String, User] = {
def validateName(user: UserDTO): ValidatedNec[String, String] =
user.name.map(_.validNec).getOrElse("Name is empty".invalidNec)
def validateAge(user: UserDTO): ValidatedNec[String, Int] =
user.age.map(_.validNec).getOrElse("Age is empty".invalidNec)
def validateDob(user: UserDTO): ValidatedNec[String, String] =
user.dob.map(_.validNec).getOrElse("DOB is empty".invalidNec)
(validateName(userDto), validateAge(userDto), validateDob(userDto)).mapN(User)
}
validateUser(userDto)
// res0: cats.data.ValidatedNec[String,User] = Invalid(Chain(Age is empty, DOB is empty))
请注意UserDTO
(“数据传输对象”)与User
之间的区别,前者为通过线路发送的任何有效负载建模,后者为业务逻辑所需的实际数据建模。我们将用户验证问题分离到它自己的方法validateUser
。现在我们可以处理有效用户或类似错误
validateUserDTO(userDto) match {
case Valid(user) =>
// do something with valid user
case Invalid(errors) =>
// do something with errors
}
在我的代码中,我有一个简单的验证器,它可以做到这一点:
抽象类验证程序[T,ERR>:Null]{
def验证(a:T):顺序[错误]
受保护的定义为(errorCase:Boolean,err:=>err)=if(errorCase)err else null
受保护的def检查(检查:ERR*)=checks.collectFirst{case x if x!=null=>x}.getOrElse(null)
受保护的def checkAll(checks:ERR*)=checks.filter(!=null)
}
//对某些类型执行检查
val passwordValidator=新验证程序[字符串,字符串]{
val universalPasswordInstruction=“密码至少需要有一个小写字母、大写字母、数字和其他符号。”
def validate(a:String)=checkAll(//这里我们检查所有案例
是(a.长度<10,“密码应大于10”),
check(//这里我们只检查第一个。
是(a.forall(u.isleter),s“Passowrd只有字母.$universalPasswordInstruction”),
是(a.forall(u.IsleterOrdigit),s“使用至少一个ascii字符,如“#”或“*”.$universalPasswordInstruction”),
),
是(a.contains(“poop”),“真的!”)
)
}
val userValidator=新验证器[(字符串,字符串),(Int,字符串)]{
覆盖def validate(a:(字符串,字符串)):Seq[(Int,字符串)]=checkAll(
是(a._1.length>0,(0,“用户名为空!”),
)++passwordValidator.validate(a._2.map)(x=>(1,x))
}
//使用
userValidator.validate(“SomeUserName”->“SomePassword”)匹配{
case Seq()=>//确定大小写
案例错误=>//处理它
}
也许没那么花哨,但对我来说很管用:)。代码很简单,而且很容易解释。这里的空值只是实现细节(它们不会显示在用户代码中,可以切换到选项)。在我的代码中,我有一个简单的验证器,它可以做到这一点:
抽象类验证程序[T,ERR>:Null]{
def验证(a:T):顺序[错误]
受保护的定义为(errorCase:Boolean,err:=>err)=if(errorCase)err else null
受保护的def检查(检查:ERR*)=checks.collectFirst{case x if x!=null=>x}.getOrElse(null)
受保护的def checkAll(checks:ERR*)=checks.filter(!=null)
}
//对某些类型执行检查
val passwordValida