代码之家  ›  专栏  ›  技术社区  ›  indusBull

Play+Scala->验证IP Json数据

  •  0
  • indusBull  · 技术社区  · 7 年前

    我试图在Play Controller的POST请求中验证JSON负载。我对玩Scala world很陌生。

    下面的代码是我到目前为止得到的。这在没有任何输入验证的情况下运行良好。现在我试图在IPRangeStr类的IP地址字段中添加验证,并遇到问题。我无法确定对包含枚举的json列表的验证。

    谢谢

    object listTypes extends Enumeration {
      type listTypes = Value
      val TypeA= Value("TypeA")
      val TypeB = Value("TypeB")
      val Unknown = Value("Unknown")
    
      def withNameWithDefault(name: String): Value =
        values.find(_.toString.toLowerCase == name.toLowerCase()).getOrElse(Unknown)
    }
    
    case class IPRangeStr(firstIP: String, lastIP: String, listType: listTypes, action: String)
    
    
    @Singleton
    class DataController @Inject()(cc: ControllerComponents, actorSvc: IPDataActorService)(implicit exec: ExecutionContext) extends AbstractController(cc) {
    
      implicit val listTypeEnumFormat = new Format[listTypes.listTypes] {
        def reads(json: JsValue) = JsSuccess(listTypes.withNameWithDefault(json.as[String]))
        def writes(listEnum: listTypes.listTypes) = JsString(listEnum.toString)
      }
    
      implicit val ipRangeStrReads: Reads[IPRangeStr] = Json.format[IPRangeStr]
      implicit val ipRangeStrWrites = Json.writes[IPRangeStr]
    
      def process = Action.async(parse.json[List[IPRangeStr]]) { implicit request =>
       if(validationSuccess){    
            // process if validation successfull 
            Ok 
          } else {
            BadRequest // validation error
          }
        } recoverWith {
          case e: Exception  =>
            Future(InternalServerError)
        }
      }
    }
    

    #编辑-1 我基于@cchantep ans的最终解决方案

    val validIPPattern: String = "(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])"
    
    def isValidIP(ip:String) = ip.matches(validIPPattern)
    
    implicit val ipRangeStrReads: Reads[IPRangeStr] =
        Json.format[IPRangeStr].filter { ipR =>
          isValidIP(ipR.firstIP) && isValidIP(ipR.lastIP)  //true  or false, according validation of ipR
    }     
    
    implicit val ipRangeStrWrites = Json.writes[IPRangeStr]
    

    使用Json.format时,不需要再次调用 同一类型的Json.write,因为OFormat可以读写。

    如果删除写操作,则在将对象转换为Json字符串时,控制器中会出现异常。

    尝试为此类型实现隐式写入或格式。

    我宁愿使用enumNameReads和enumNameWrites。

    这是很好的速记。最后,我使用了以前的解决方案,在转换为枚举之前将json字符串转换为小写。

    建议用首字母大写的字体命名,不要用最后的“s” 复数(例如ListType)。

    我完全同意这一点。不幸的是,这是遗留代码的一部分,我现在不想重构。

    1 回复  |  直到 7 年前
        1
  •  1
  •   cchantep    7 年前

    作为一元类型,函数 .filter 可用于 Reads .

    implicit val ipRangeStrReads: Reads[IPRangeStr] =
      Json.format[IPRangeStr].filter { ipR =>
        true // or false, according validation of ipR
      }
    

    使用时 Json.format ,不需要再次调用 Json.write 对于同一类型 OFormat 能够读写。

    我宁愿用 enumNameReads enumNameWrites .

    implicit val r = Reads.enumNameReads(listTypes)
    implicit val w = Writes.enumNameWrites[listTypes.type]
    

    建议使用首字母大写的字体命名,复数形式不使用最后的“s”(例如。 ListType ).