Grails域类和特殊表示要求

在Grails中,出于演示目的,我们经常直接将域对象用作支持模型 ,并且仅在特殊情况下,我们才创建值持有者对象或DTO。

初级Grails开发人员知道如何在GSP中非常容易地显示各个实体属性,例如虚构的域类的名称……

<g:each in=”${breedingGoals}” var=”breedingGoal”>
  ${breedingGoal.name}
</g:each>

要么

<g:select from="${breedingGoals}"
  optionKey="code" 
  optionValue="name" />

繁殖目标名称

但是有时当新的展示要求出现时,却需要展示更多的或组合的信息时就会感到困难 。 人为设计特殊构造,例如:

def list() {
  def breedingGoals = BreedingGoal.list()
  breedingGoals.each {
    it.name = it.name + " ("+ it.code + ")"
  }
  render view: “viewName”, model: [breedingGoals: breedingGoals]
}

不仅更多的显示名称,但还有其他方面-例如,它的代码。 那就是事情变得多毛的!

繁殖目标名称和代码

似乎是在浏览器中获取新的正确输出的明智方法。 但事实并非如此。

在这种情况下,实际上会更新实体,并在几次迭代后将数据库置于非常混乱的状态。 在这一点上,经验丰富的开发人员告诉新手开发人员不要继续前进。

如果您是后者的一员,请先阅读GORM的一些持久性基础知识以获取一些背景知识 ,然后再按我个人的喜好返回此处获取可以使用的一些准则。

我的主要经验法则是:

不要用自身的(表示形式)替换数据。

这不是一个完整的列表,只是让您考虑一些选择,以我们前面提到的BreedingGoal用例为例。

如果信息包含在对象本身内

并且您有了对象,只需当场对其进行格式化。

<g:each in=”${breedingGoals}” var=”breedingGoal”>
  ${breedingGoal.name} (${breedingGoal.code})
</g:each>

GSP对于演示目的特别有用。 我总是会首先尝试。

有些人仍然对各种Grails标记感到困惑,这些标记似乎接受要迭代的域类的“仅1个属性”,例如select

<g:select from="${breedingGoals}"
  optionKey="code" 
  optionValue="name + (code)? Arh! Now what?" />

幸运的是,有时标签作者对此有所考虑! 对于select, optionValue可以使用闭包来应用转换:

<g:select from="${breedingGoals}"
  optionKey="code" 
  optionValue="${{ it.name + ' (' + it.code + ')' }}"  />

如果更多地方需要此新格式的信息

要保持干燥,您可以将其放入对象本身。 在您的域类中,添加一个getter

String getNamePresentation() {
  name + " ("+ code + ")"
}

可以将其称为对象本身的属性。

<g:each in=”${breedingGoals}” var=”breedingGoal”>
  ${breedingGoal.namePresentation}
</g:each>

如果信息不在对象本身中,但是需要使用其他逻辑进行检索/计算

您可以使用标签库

class BreedingGoalTagLib {

  def translationService

  def formatBreedingGoal = { attrs ->
    out << translationService.translate(attrs.code, user.lang)
  }
}

在此示例中,某种translationService用于获取要显示的实际信息。

<g:each in=”${breedingGoals}” var=”breedingGoal”>
  <g:formatBreedingGoal code=${breedingGoal.code} />
</g:each>

从GSP调用TagLib非常容易,并且可以完全访问协作服务和Grails环境。

如果不需要其他计算,只需要特殊(HTML)格式

获取内容并将其委托给模板:

class BreedingGoalTagLib {

  def displayBreedingGoal = { attrs ->
    out << render(template: '/layouts/breedingGoal', 
      bean: attrs.breedingGoal)
  }
}

特定模板可能包含一些用于特殊标记HTML:

<strong>${it.name}</strong> (${it.code})

或者您需要一次初始化一堆东西,或者您并不是真正针对GSP显示

您可以创建一个(瞬态)属性,并在初始化时填充它。

调整域类,使新的“ presentation”属性处于瞬态状态 (这样它就不会持久化到数据库中)并在某个时候对其进行初始化。

class BreedingGoal {

  String code
  String name
  String namePresentation

  static transients = ['namePresentation']
}
class SomeInitializationService {

  // in some method...
  def breedingGoal = findBreedingGoal(...
  breedingGoal.namePresentation = 
    translationService.translate(breedingGoal.code, user.lang)

  return breedingGoal

}

友善的建议: 不要为了过渡目的而用过渡字段过多地填充域类。 如果您的域类包含50%带有奇怪代码的属性,而您需要另一半具有关联的“表示”字段,则最好使用专门的值或DTO对象。

结论

您会看到各种各样的演示选项,并且取决于信息的来源和去向,某些方法比其他方法更适合。 不要害怕在必要时选择一种方法并重构为另一种方法,但是我会坚持使用GSP中最简单的选项,并尽量不要为了演示目的而过多地处理核心数据!

翻译自: https://www.javacodegeeks.com/2014/12/grails-domain-classes-and-special-presentation-requirements.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值