2013-12-14 66 views
7

在我的Play应用程序我有一个配置是这样的:类型安全配置:如何配置项目迭代

social { 
    twitter { 
     url="https://twitter.com" 
     logo="images/twitter.png" 
    } 
    facebook { 
     url="https://www.facebook.com" 
     logo="images/facebook.png" 
    } 
} 

何做我遍历所有的social项获得每个条目urllogo

<table border="0" cellspacing="0" cellpadding="2"><tr> 
    @configuration.getConfig("social").map { config => 
     @for(item <- config.entrySet) { 
      <td><a href="item.getString("url")"> 
      <img src="@routes.Assets.at("item.getString("logo")").absoluteURL()" width="24" height="24"/></a></td> 
     } 
    } 
</table> 

当然,item.getString在这里摘录以上不工作...它只是显示了我想要的目的。

最终目标是能够添加任何进一步的社交网址,而无需修改页面模板。

回答

10

如果您更改配置到:

"social" : [ 
    { 
     name="twitter" 
     url="https://twitter.com", 
     logo="images/twitter.png" 
    }, 
    { 
     name="facebook" 
     url="https://www.facebook.com", 
     logo="images/facebook.png" 
    } 
] 

你可以做这样的:

@(message: String)(implicit request: RequestHeader) 
@import play.api.Play.current 

<table border="0" cellspacing="0" cellpadding="2"><tr> 
    @current.configuration.getConfigList("social").get.map { config => 
      <td><a href="@config.getString("url")"> 
      <img src="@routes.Assets.at(config.getString("logo").get).absoluteURL()" width="24" height="24"/></a></td> 
     } 
</table> 
+0

Tx,这正是我正在寻找的:-) – j3d

4

对于后人,还有一种方法一样,你不得不遍历嵌套配置。我更喜欢这种格式的数组,我宁愿让我的配置比代码更清洁。

import collection.JavaConversions._ 
val socialConfig = ConfigFactory.load.getConfig("social") 
socialConfig.root.map { case (name: String, configObject: ConfigObject) => 
    val config = configObject.toConfig 
    println(config.getString("url")) 
    println(config.getString("logo")) 
} 

我确定OP可以将其转换为Twirl模板。这是尽可能干净,因为我可以得到它。

4

如果你您使用的是Java,这可能是一个解决办法:

ConfigList socials = ConfigFactory().load.getList("social") 

for (ConfigValue cv : socials) { 
    Config c = ((ConfigObject)cv).toConfig(); 
    System.out.println(c.getString("url")); 
    System.out.println(c.getString("logo")); 
} 
0

socialConfig.root.map不起作用。

这是我的溶液 -

private val firstSegmentRE = """^(\w+)[\.*].*$""".r 

// convert "aaa.bbb.ccc" to "aaa" 
private def parseFirstSegment(fullPath: String) : Option[String] = { 
    if (fullPath.contains(".")) 
    fullPath match { 
     case firstSegmentRE(segment) => Some(segment) 
     case _ => None 
    } 
    else 
    Some(fullPath) 
} 

// for all keys in white list get a map of key -> config 
protected def subConfigMap(config: Config, whiteList: List[String], 
configName: String) : ErrorOr[Map[String, Config]] = { 
    // This will traverse the whole config and flatten down to the leaves.. 
    val leafKeys : List[String] = 
    config.entrySet() 
     .asScala 
     .map(e => e.getKey) 
     .toList 
    // Remove all after the first dot 
    val nextLevelKeys : List[String] = 
    leafKeys.map(parseFirstSegment) 
     .collect { 
     case Some(firstSegment) => firstSegment 
     } 
     .distinct 
    val keysToSearch = nextLevelKeys.filter(whiteList.contains) 
    // we have a list of valid first level children 
    // parse out subconfigs and convert to map 
    keysToSearch.traverseErrorOr(key => 
    extractSubConfig(config, key, configName).map((key, _)) 
) 
    .map(_.toMap) 
} 

凡extractSubConfig是产生的误差的方法/配置(一个scalaz析取)和traverseErrorOr是遍历列表,并且任一过程的所有元素或失败的方法和如果在任何时候失败,则返回失败的析取。这种方法可以在没有scalaz的情况下完成,只需发布​​一个答案来帮助人们,如果他们想要的话。

+0

您不必使用白名单..这是我的业务需要 –