我正在尝试在Groovy中编写一个通用程序,它将从配置文件中获取SQL以及其他参数并将它们放入文件中。
这是程序:
def config = new ConfigSlurper().parse(new File("config.properties").toURL())
Sql sql = Sql.newInstance(config.db.url, config.db.login, config.db.password, config.db.driver);
def fileToWrite = new File(config.copy.location)
def writer = fileToWrite.newWriter()
writer.write(config.file.headers)
sql.eachRow(config.sql){ res->
writer.write(config.file.rows)
}
在配置中,sql是这样的:
sql ="从mydb"
中选择*和
file.rows =" $ {res.column1} | $ {res.column2} | $ {res.column3} \ n"
当我跑它时,我得到了
[:] | [:] | [:]
[:] | [:] | [:]
[:] | [:] | [:]
在文件中。如果我替换
writer.write(config.file.rows)
到
writer.write("${res.column1}|${res.column2}|${res.column3}\n")
它输出实际结果。为获得结果,我需要做些什么?
答案 0 :(得分:4)
您可以通过使用Gstring的惰性求值以及更改委托来实现此目的。 首先通过使值成为调用Closures的结果来使Gstring变得懒惰:
file.rows="${->res.column1}|${->res.column2}|${-> res.column3}"
然后在评估更改闭包的委托之前:
config.file.rows.values.each {
if (Closure.class.isAssignableFrom(it.getClass())) {
it.resolveStrategy = Closure.DELEGATE_FIRST
it.delegate = this
}
}
委托必须在范围内具有变量res。这是一个完整的工作示例:
class Test {
Map res
void run() {
String configText = '''file.rows="${->res.column1}|${->res.column2}|${-> res.column3}"
sql="select * from mydb"'''
def slurper = new ConfigSlurper()
def config = slurper.parse(configText)
config.file.rows.values.each {
if (Closure.class.isAssignableFrom(it.getClass())) {
it.resolveStrategy = Closure.DELEGATE_FIRST
it.delegate = this
}
}
def results = [
[column1: 1, column2: 2, column3: 3],
[column1: 4, column2: 5, column3: 6],
]
results.each {
res = it
println config.file.rows.toString()
}
}
}
new Test().run()
答案 1 :(得分:0)
好消息是ConfigSlurper
能够按预期为您执行GString
变量替换。坏消息是它在调用parse()
方法之前进行了这种替换,早在您有一个res
变量替换到解析器之前。另一个坏消息是,如果被替换的变量没有在配置文件本身中定义,那么你必须通过binding
属性提前将它们提供给slurper。
因此,要获得您想要的效果,您必须通过eachRow
的每次传递来解析属性。这是否意味着你必须为每一行创建一个新的ConfigSlurper
重新读取一次文件?不。您 必须为每次传递创建新的ConfigObject
,但您可以重复使用ConfigSlurper
和文件文本,如下所示:
def slurper = new ConfigSlurper();
def configText = new File("scripts/config.properties").text
def config = slurper.parse(configText)
Sql sql = Sql.newInstance(config.db.url, config.db.login, config.db.password, config.db.driver);
def fileToWrite = new File(config.copy.location)
def writer = fileToWrite.newWriter()
writer.write(config.file.headers)
sql.eachRow(config.sql){ result ->
slurper.binding = [res:result]
def reconfig = slurper.parse(configText)
print(reconfig.file.rows)
}
请注意,我将Closure参数的名称从res
更改为result
。我这样做是为了强调slurper从绑定映射键中绘制名称res
,而不是从闭包参数名称。
如果你想减少浪费" reparsing"时间和精力,你可以将file.rows
属性分成它自己的单独文件。我仍然会在该文件中读取一次并重复使用"每行"解析。