在致远OA平台进行表单二次开发时,自定义函数是实现复杂业务逻辑的利器。但很多开发者在处理明细表数据分类拼接这类常见需求时,往往会陷入一些性能陷阱和代码坏味道。本文将聚焦Groovy脚本中循环与正则匹配的高频错误模式,通过对比分析给出工业级解决方案。
正则表达式是字符串处理的瑞士军刀,但在循环体内不当使用会成为性能杀手。我们来看一个典型的反模式:
groovy复制def work = param[0]
def name = param[1]
int i=-1
String res = ""
if(null != work) {
for(t in work) {
i +=1
def m = t ==~ /白班/ // 每次循环都重新编译正则
if(!m) continue
if(res=="") {
res += name[i]
continue
}
res += '、' +name[i]
}
}
return res
这段代码存在三个明显问题:
==~操作符每次都会重新编译正则表达式,在循环中造成不必要的开销+=进行字符串连接会频繁创建新对象i计数器容易出错且不优雅优化方案:
groovy复制def (workList, nameList) = [param[0], param[1]].collect{ it ?: [] }
def pattern = ~/白班/ // 预编译正则
workList.indices
.findAll { workList[it] =~ pattern }
.collect { nameList[it] }
.join('、')
关键改进点:
~操作符预编译正则表达式join替代手动字符串拼接?: [])表单数据处理中最容易忽略的就是各种边界情况。以下是需要特别注意的防御性编程要点:
必须处理的边界条件:
健壮性增强版实现:
groovy复制def safeGetNames(List workList, List nameList, String shiftType) {
// 参数校验
if(!workList || !nameList) return ''
if(workList.size() != nameList.size()) return ''
try {
def pattern = ~/${shiftType}/ // 动态正则需注意注入风险
return workList.indices
.findAll { workList[it]?.toString() =~ pattern }
.collect { nameList[it]?.toString()?.trim() }
.findAll { it }
.join('、') ?: '无相关人员'
} catch(e) {
return '分类匹配异常'
}
}
这个版本增加了:
?.toString())findAll { it })Groovy强大的函数式特性可以大幅提升代码可读性和可维护性。以下是几种常见场景的优化对比:
传统写法:
groovy复制def dayCount = 0
def nightCount = 0
for(shift in shifts) {
if(shift == '白班') {
dayCount++
} else if(shift == '夜班') {
nightCount++
}
}
函数式写法:
groovy复制def counts = shifts.countBy {
it.contains('班') ? it : '其他'
}
传统写法:
groovy复制def result = []
for(item in items) {
if(item.age > 18 && item.gender == '男' && item.score > 60) {
result.add(item.name)
}
}
函数式写法:
groovy复制def result = items.findAll {
it.age > 18 && it.gender == '男' && it.score > 60
}.collect { it.name }
传统写法:
groovy复制def formatted = []
for(num in numbers) {
formatted.add(String.format("%.2f", num))
}
函数式写法:
groovy复制def formatted = numbers.collect {
"%.2f".format(it)
}
致远OA的明细表数据处理有一些特有的模式和技巧:
多字段关联处理:
groovy复制def processDetails(List details) {
details.collate(3) { rows -> // 假设每3行为一组
[
morning: rows[0]?.name,
afternoon: rows[1]?.name,
night: rows[2]?.name
]
}
}
带权重的分类汇总:
groovy复制def summarizeShifts(List shifts) {
shifts.groupBy { it.type }
.collectEntries { type, items ->
[type, items.sum { it.hours }]
}
}
性能敏感场景的优化:
对于大型明细表(1000+行),建议:
inject代替多次collectgroovy复制// 高性能版字符串拼接
largeList.inject(new StringBuilder()) { sb, item ->
if(sb.length() > 0) sb.append('、')
sb.append(item)
}.toString()
在OA表单环境中调试Groovy脚本有其特殊性,以下是几个实用技巧:
日志输出技巧:
groovy复制// 临时调试输出
System.out.println("Debug: ${variable.dump()}")
// 结构化输出
import groovy.json.JsonOutput
def log(Object obj) {
System.out.println(JsonOutput.prettyPrint(JsonOutput.toJson(obj)))
}
异常处理模式:
groovy复制try {
// 业务逻辑
} catch(NullPointerException e) {
return "错误:空指针异常"
} catch(PatternSyntaxException e) {
return "正则表达式语法错误"
} catch(Exception e) {
return "系统异常:${e.message.take(50)}..."
} finally {
// 清理资源
}
防御性编程检查表:
写出能经受时间考验的表单脚本需要遵循以下原则:
代码组织建议:
可配置化实现:
groovy复制class ShiftConfig {
static final PATTERNS = [
'day': ~/白班/,
'night': ~/夜班/,
'late': ~/深夜班/
]
}
def classifyShifts(List shifts) {
ShiftConfig.PATTERNS.collectEntries { type, pattern ->
[type, shifts.findAll { it =~ pattern }]
}
}
文档化示例:
groovy复制/**
* 班次人员分类统计
* @param shifts 班次列表 ['白班','夜班',...]
* @param names 对应人员名单 ['张三','李四',...]
* @param shiftType 班次类型正则 /白班|夜班/
* @return 匹配人员名单,用顿号分隔
* @throws IllegalArgumentException 参数不合法时抛出
*/
def groupStaff(List shifts, List names, Pattern shiftType) {
// 实现略
}
在致远OA表单开发中,一个看似简单的字符串处理函数可能隐藏着诸多陷阱。通过预编译正则、采用函数式编程、完善边界条件处理等手法,不仅能提升代码性能,还能大幅降低维护成本。记住:好的表单脚本应该像业务文档一样清晰,像数学公式一样精确。