- 浏览: 341417 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (198)
- HIBERNATE (8)
- JAVA (13)
- 数据库 (24)
- SPRING (1)
- LINUX (0)
- 需求管理 (3)
- 职业提升 (6)
- 团队建设 (1)
- 日常用到语句 (1)
- FLEX (6)
- 用户体验 (3)
- 设计模式 (6)
- weblogic (2)
- PowerDesigner (3)
- HTML (7)
- ANT (7)
- 工具. (1)
- bat (5)
- 存储过程 (1)
- strus2 (1)
- DWR (2)
- jfreechart (4)
- 上线测试优化 (17)
- JVM (9)
- 工具使用 (2)
- 算法 (3)
- 私事 (0)
- 数据库-Oracle session (1)
- 软件开发 (5)
- 产品 (2)
- 项目管理 (4)
- oracle语句 (1)
- IntelliJ IDEA (4)
- GRAILS (10)
- Groovy (1)
- JS (1)
- DUBBO (1)
- JAVA EXCEL (3)
- netty websocket (1)
- kafka (1)
- 秘钥体系 (2)
- golang (6)
- gradle (1)
- spring cloud (0)
最新评论
-
wujt:
...
Grails_数据库逆向工程插件 db-reverse-engineer -
yy8093:
我也遇到这个问题,不过并不觉得是个好的方法。。。。不过最后也确 ...
关于dubbo服务产生异常之:Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting s -
wujt:
# ----- Execute The Requested C ...
jconsole基础配置(原创) -
gaowei52306:
你好,请问remotedir="/home/dmwe ...
Ant FTP -
抢街饭:
ant生成日志 在命令行也能看见 怎么去做啊
ant生成日志
grails ajax分页标签实现
一、设计目标
1、采用ajax实现
2、要多少条数据,取多少条,不从数据库中一次性全部取出
3、实现指定页面跳转
4、用户可以指定选择每页显示几条数据
5、按那个字段排序
6、最好不要占用session
二、如何实现
2、传入参数:显示页码,共有多少条数据,每页显示几条数据,返回的页面
可选按那个字段排序
if(!params.total){
params.total=TestAjaxPage.count()///这个必须要,ajax请求时就不用在count总数了
}
params.view=params.view==null?"list":params.view
params.max = Math.min(params.max ? params.max as int : 2, 100)
params.linkTotal = Math.min(params.linkTotal ? params.linkTotal as int : 2, 100)
params.offset = Math.min(params.offset ? params.offset as int : 0, 100)
params.sort=params.sort==null?"dateCreated":params.sort
params.order=params.order==null?"desc":params.order
截个图:
talib code
import org.springframework.web.servlet.support.RequestContextUtils as RCU;
import org.codehaus.groovy.grails.commons.ConfigurationHolder
class AjaxPageTagLib {
def paginateAjax={attrs ->
def writer = out
params.offset = Math.min(params.offset ? params.offset as int : 0, 100)
params.sort=params.sort==null?"dateCreated":params.sort
params.order=params.order==null?"desc":params.order
def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")
def locale = RCU.getLocale(request)
def total = attrs.total.toInteger()
def offset = params.offset?.toInteger()
def max = params.max?.toInteger()
int pageSize=Math.round(Math.ceil(total / max))
def path=request.getContextPath()
def pageNow=offset/max+1
def selectMax=attrs.selectMax?.toInteger()
if(!selectMax){
selectMax=20
}
selectMax=selectMax>total?total:selectMax
////js输出
writer<<"""
<div id="ajaxPage">
"""
/////显示首页和上页
def firstText=messageSource.getMessage('paginate.first', null, messageSource.getMessage('default.paginate.first', null, 'First', locale), locale)
def prevText=messageSource.getMessage('paginate.prev', null, messageSource.getMessage('default.paginate.prev', null, 'Prev', locale), locale)
def nextText=messageSource.getMessage('paginate.next', null, messageSource.getMessage('default.paginate.next', null, 'Next', locale), locale)
def lastText=messageSource.getMessage('paginate.last', null, messageSource.getMessage('default.paginate.last', null, 'Last', locale), locale)
if(offset!=0){
def firstUrl="""offset=0&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="firstShow" title="${firstText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${firstUrl}'});
return false;" >
[${firstText}]
</span>
"""
int prev=offset-max
def prevUrl="""offset=${prev}&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="preShow" title="${prevText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${prevUrl}'});
return false;" >
[${prevText}]
</span>
"""
}
else{
writer<<"""<span id="firstNoShow" title="${firstText}">
[${firstText}]
</span>
"""
writer<<"""<span id="preNoShow" title="${prevText}">
[${prevText}]
</span>
"""
}
////数据信息输出
writer<<"""<span id="ajaxPageInfo">当前${pageNow}/${pageSize}页(共${total})</span>"""
//下一页和末页输出,
if(offset!=max*(pageSize-1)){
int next1=offset+max
def nextUrl="""offset=${next1}&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="nextShow" title="${nextText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${nextUrl}'});
return false;" >
[${nextText}]
</span>
"""
int last=max*(pageSize-1)
def lastUrl="""offset=${last}&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="lastShow" title="${lastText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${lastUrl}'});
return false;" >
[${lastText}]
</span>
"""
}
else{
writer<<"""<span id="nextNoShow" title="${nextText}">
[${nextText}]
</span>
"""
writer<<"""<span id="lastNoShow" title="${lastText}">
[${lastText}]
</span>
"""
}
///到指定页连接输出
def selectUrl="&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"
writer<<"""
<span id="ajaxSelectText">转到<select id="ajaxSelect" onchange="myUpdate('${attrs.update}','${path}/${params.controller}/${params.action}'
,'${selectUrl}','${max}')">
"""
for(int j=1;j<=pageSize;j++){
if(pageNow!=j){
writer<<""" <option value ="${j}">${j}/${pageSize}</option> """
}
else{
writer<<""" <option value ="${j}" selected="selected">${j}/${pageSize}</option> """
}
}
writer<<"</select>页</span>"
////每页显示几条数据
def maxUrl="&offset=0&sort=${params.sort}&order=${params.order}&total=${total}"
writer<<"""
<span id="ajaxMaxText"> 每页显示</span><select id="ajaxMax" onchange="myUpdate2('${attrs.update}','${path}/${params.controller}/${params.action}'
,'${maxUrl}')">
"""
for(int j=1;j<=selectMax;j++){
if(max!=j){
writer<<"""<option value ="${j}">${j}</option>"""
}
else{
writer<<"""<option value ="${j}" selected="selected">${j}</option>"""
}
}
writer<<"</select> </div>"
}
}
example code
if(!params.total){
params.total=CompanyFinance.count()////注意total参数
}
def hql="select id,title,dateCreated from CompanyFinance "
params.view=params.view==null?"list":params.view
params.max = Math.min(params.max ? params.max as int : 2, 100)
params.linkTotal = Math.min(params.linkTotal ? params.linkTotal as int : 2, 100)
params.offset = Math.min(params.offset ? params.offset as int : 0, 100)
params.sort=params.sort==null?"dateCreated":params.sort
params.order=params.order==null?"desc":params.order
params.selectMax="true"///暂时没用
def results = sessionFactory.currentSession.createQuery(hql+" order by ${params.sort} ${params.order}")
.setCacheable(false)
.setReadOnly(true)
.setFirstResult(params.offset)
.setMaxResults(params.max)
.list()
render view:params.view,model:[pageAjaxList:results,paginateAjaxTotal:params.total]<g:paginateAjax total="${paginateAjaxTotal}" update="update1"
selectMax="20" />
对了,还有js,css
function myUpdate(update1, url1, parameters1, max) {
var selectValue = document.getElementById("ajaxSelect").value
var offset = max * (selectValue - 1)
var newParams = "offset=" + offset + parameters1
new Ajax.Updater(update1, url1, {
asynchronous : true,
evalScripts : true,
parameters : newParams
});
return false;
}
function myUpdate2(update1, url1, parameters1) {
var max = document.getElementById("ajaxMax").value
var newParams = "max=" + max + parameters1
new Ajax.Updater(update1, url1, {
asynchronous : true,
evalScripts : true,
parameters : newParams
});
return false;
}
css:(css水平有限啊),table的css最好自己写,如果 用默认的main.css会报错
@CHARSET "UTF-8";
#firstShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#preShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#ajaxPageInfo{
color:#000000;
}
#nextShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#lastShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#ajaxSelectText{
color:#000000;
}
#ajaxMaxText{
color:#000000;
}
#firstNoShow{
}
#preNoShow{
}
#nextNoShow{
}
#lastNoShow{
}grails 1.1
grails 1.3.5下测试通过
最后页面上应该以下几句
<g:javascript library="prototype" />
<script type="text/javascript" src="${resource(dir: 'js', file: 'ajaxPage.js')}"></script>
<link rel="stylesheet" href="${resource(dir:'css',file:'ajaxPage.css')}" />
要源码可以下载:
hg clone https://asdtiang@bitbucket.org/asdtiang/mygrailsstudy
一、设计目标
1、采用ajax实现
2、要多少条数据,取多少条,不从数据库中一次性全部取出
3、实现指定页面跳转
4、用户可以指定选择每页显示几条数据
5、按那个字段排序
6、最好不要占用session
二、如何实现
2、传入参数:显示页码,共有多少条数据,每页显示几条数据,返回的页面
可选按那个字段排序
if(!params.total){
params.total=TestAjaxPage.count()///这个必须要,ajax请求时就不用在count总数了
}
params.view=params.view==null?"list":params.view
params.max = Math.min(params.max ? params.max as int : 2, 100)
params.linkTotal = Math.min(params.linkTotal ? params.linkTotal as int : 2, 100)
params.offset = Math.min(params.offset ? params.offset as int : 0, 100)
params.sort=params.sort==null?"dateCreated":params.sort
params.order=params.order==null?"desc":params.order
截个图:
talib code
import org.springframework.web.servlet.support.RequestContextUtils as RCU;
import org.codehaus.groovy.grails.commons.ConfigurationHolder
class AjaxPageTagLib {
def paginateAjax={attrs ->
def writer = out
params.offset = Math.min(params.offset ? params.offset as int : 0, 100)
params.sort=params.sort==null?"dateCreated":params.sort
params.order=params.order==null?"desc":params.order
def messageSource = grailsAttributes.getApplicationContext().getBean("messageSource")
def locale = RCU.getLocale(request)
def total = attrs.total.toInteger()
def offset = params.offset?.toInteger()
def max = params.max?.toInteger()
int pageSize=Math.round(Math.ceil(total / max))
def path=request.getContextPath()
def pageNow=offset/max+1
def selectMax=attrs.selectMax?.toInteger()
if(!selectMax){
selectMax=20
}
selectMax=selectMax>total?total:selectMax
////js输出
writer<<"""
<div id="ajaxPage">
"""
/////显示首页和上页
def firstText=messageSource.getMessage('paginate.first', null, messageSource.getMessage('default.paginate.first', null, 'First', locale), locale)
def prevText=messageSource.getMessage('paginate.prev', null, messageSource.getMessage('default.paginate.prev', null, 'Prev', locale), locale)
def nextText=messageSource.getMessage('paginate.next', null, messageSource.getMessage('default.paginate.next', null, 'Next', locale), locale)
def lastText=messageSource.getMessage('paginate.last', null, messageSource.getMessage('default.paginate.last', null, 'Last', locale), locale)
if(offset!=0){
def firstUrl="""offset=0&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="firstShow" title="${firstText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${firstUrl}'});
return false;" >
[${firstText}]
</span>
"""
int prev=offset-max
def prevUrl="""offset=${prev}&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="preShow" title="${prevText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${prevUrl}'});
return false;" >
[${prevText}]
</span>
"""
}
else{
writer<<"""<span id="firstNoShow" title="${firstText}">
[${firstText}]
</span>
"""
writer<<"""<span id="preNoShow" title="${prevText}">
[${prevText}]
</span>
"""
}
////数据信息输出
writer<<"""<span id="ajaxPageInfo">当前${pageNow}/${pageSize}页(共${total})</span>"""
//下一页和末页输出,
if(offset!=max*(pageSize-1)){
int next1=offset+max
def nextUrl="""offset=${next1}&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="nextShow" title="${nextText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${nextUrl}'});
return false;" >
[${nextText}]
</span>
"""
int last=max*(pageSize-1)
def lastUrl="""offset=${last}&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"""
writer<<"""
<span id="lastShow" title="${lastText}" onclick="new Ajax.Updater('${attrs.update}',
'${path}/${params.controller}/${params.action}',{asynchronous:true,evalScripts:true,parameters:'${lastUrl}'});
return false;" >
[${lastText}]
</span>
"""
}
else{
writer<<"""<span id="nextNoShow" title="${nextText}">
[${nextText}]
</span>
"""
writer<<"""<span id="lastNoShow" title="${lastText}">
[${lastText}]
</span>
"""
}
///到指定页连接输出
def selectUrl="&max=${params.max}&sort=${params.sort}&order=${params.order}&total=${total}"
writer<<"""
<span id="ajaxSelectText">转到<select id="ajaxSelect" onchange="myUpdate('${attrs.update}','${path}/${params.controller}/${params.action}'
,'${selectUrl}','${max}')">
"""
for(int j=1;j<=pageSize;j++){
if(pageNow!=j){
writer<<""" <option value ="${j}">${j}/${pageSize}</option> """
}
else{
writer<<""" <option value ="${j}" selected="selected">${j}/${pageSize}</option> """
}
}
writer<<"</select>页</span>"
////每页显示几条数据
def maxUrl="&offset=0&sort=${params.sort}&order=${params.order}&total=${total}"
writer<<"""
<span id="ajaxMaxText"> 每页显示</span><select id="ajaxMax" onchange="myUpdate2('${attrs.update}','${path}/${params.controller}/${params.action}'
,'${maxUrl}')">
"""
for(int j=1;j<=selectMax;j++){
if(max!=j){
writer<<"""<option value ="${j}">${j}</option>"""
}
else{
writer<<"""<option value ="${j}" selected="selected">${j}</option>"""
}
}
writer<<"</select> </div>"
}
}
example code
if(!params.total){
params.total=CompanyFinance.count()////注意total参数
}
def hql="select id,title,dateCreated from CompanyFinance "
params.view=params.view==null?"list":params.view
params.max = Math.min(params.max ? params.max as int : 2, 100)
params.linkTotal = Math.min(params.linkTotal ? params.linkTotal as int : 2, 100)
params.offset = Math.min(params.offset ? params.offset as int : 0, 100)
params.sort=params.sort==null?"dateCreated":params.sort
params.order=params.order==null?"desc":params.order
params.selectMax="true"///暂时没用
def results = sessionFactory.currentSession.createQuery(hql+" order by ${params.sort} ${params.order}")
.setCacheable(false)
.setReadOnly(true)
.setFirstResult(params.offset)
.setMaxResults(params.max)
.list()
render view:params.view,model:[pageAjaxList:results,paginateAjaxTotal:params.total]<g:paginateAjax total="${paginateAjaxTotal}" update="update1"
selectMax="20" />
对了,还有js,css
function myUpdate(update1, url1, parameters1, max) {
var selectValue = document.getElementById("ajaxSelect").value
var offset = max * (selectValue - 1)
var newParams = "offset=" + offset + parameters1
new Ajax.Updater(update1, url1, {
asynchronous : true,
evalScripts : true,
parameters : newParams
});
return false;
}
function myUpdate2(update1, url1, parameters1) {
var max = document.getElementById("ajaxMax").value
var newParams = "max=" + max + parameters1
new Ajax.Updater(update1, url1, {
asynchronous : true,
evalScripts : true,
parameters : newParams
});
return false;
}
css:(css水平有限啊),table的css最好自己写,如果 用默认的main.css会报错
@CHARSET "UTF-8";
#firstShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#preShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#ajaxPageInfo{
color:#000000;
}
#nextShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#lastShow{
color:#0000cc;
cursor:hand;
cursor:pointer;
}
#ajaxSelectText{
color:#000000;
}
#ajaxMaxText{
color:#000000;
}
#firstNoShow{
}
#preNoShow{
}
#nextNoShow{
}
#lastNoShow{
}grails 1.1
grails 1.3.5下测试通过
最后页面上应该以下几句
<g:javascript library="prototype" />
<script type="text/javascript" src="${resource(dir: 'js', file: 'ajaxPage.js')}"></script>
<link rel="stylesheet" href="${resource(dir:'css',file:'ajaxPage.css')}" />
要源码可以下载:
hg clone https://asdtiang@bitbucket.org/asdtiang/mygrailsstudy
发表评论
-
Grails_数据库逆向工程插件 db-reverse-engineer
2018-09-06 17:47 663Grails_数据库逆向工程插件 db-reverse- ... -
无法解析grails的依赖关系处理
2018-09-06 16:43 471无法解析grails的依赖关系处理 ::::::::::: ... -
err:Module is not specified
2018-09-06 09:58 926err:Module is not specifi ... -
grails 中 -> 和 ? 以及*.(
2015-03-10 14:13 634grails 中 -> 和 ? ... -
grails框架不能save对象
2014-11-09 18:58 709grails框架不能save对象 在 ... -
Grails探索之访问存储过程及其事务控制 .
2014-10-30 18:51 799Grails探索之访 ... -
grails 国际化
2014-10-28 15:23 814grails 国际化 引用方法: 无参数:< ... -
Grails项目示例
2014-10-23 16:27 756Grails项目示例 摘自:http://www.cn ... -
GRAILS第一个简单项目
2014-10-23 16:19 782GRAILS第一个简单项目 关键的几个命令 ...
相关推荐
在Grails这个基于Groovy的敏捷开发框架中,实现分页功能对于任何Web应用程序都是至关重要的,特别是当处理大量数据时。Grails提供了一些内置的支持,但如果你需要在自定义的控制器和视图中实现分页,那么就需要遵循...
在Grails中,我们可以使用内置的GSP(Grails Server Pages)标签库来简化Ajax调用。例如,`remoteFunction`标签可以轻松创建Ajax请求,它接受各种参数,如URL、方法类型(GET或POST)、回调函数等。这样,开发者可以...
在Grails中,我们可以利用jQuery库或内置的GSP标签库来实现Ajax功能。 2. **Grails GSP标签库中的Ajax** Grails提供了一个强大的标签库,其中包括用于处理Ajax请求的标签。例如: - `<g:remoteFunction>`:这是一...
在Grails中,我们可以利用AJAX技术实现这种交互,AJAX即异步JavaScript和XML,它允许页面在不刷新整个页面的情况下与服务器交换数据并局部更新页面内容。这正是实现联动效果的关键,因为它能让用户体验更加流畅,...
Grails标签 主要介绍了grails的标签的一个帮助文档
本文将深入探讨如何使用Grails的GORM(Grails Object-Relational Mapping)API以及Ajax技术来实现这种复杂的关系。 首先,了解多对多关系的基本概念。在多对多关系中,两个实体类之间存在一对多的双向关联,即每个...
### 精通Grails之用JSON和Ajax实现异步Grails #### 一、引言 随着Web 2.0技术的发展,JSON (JavaScript Object Notation) 和 Ajax (Asynchronous JavaScript + XML) 成为现代Web应用开发的重要组成部分。本文旨在...
- **特定标签支持**:为了简化Ajax开发过程,Grails提供了一系列特定标签,这些标签能够很好地与Prototype、Yahoo! UI和Dojo等库集成。 - **抽象层**:尽管Dojo目前需要单独安装,但Grails提供了一个抽象层,使得...
Grails 的强大之处在于其插件生态,如Security、Spring Security Core、Cache、Ajax等,它们提供开箱即用的功能,减少重复造轮子的工作。 6. **Grails URL 映射** 通过配置URL映射,Grails允许开发者定义清晰、...
9.4 实现ajax效果(effects) 9.5 如何处理javascript事件 9.6 以异步方式提交表单 9.7 关于ajax性能的讨论 9.8 本章小结 第10章 服务(services)和作业(jobs) 10.1 服务基础知识...
2. **视图(View)**: 视图负责展示数据,通常使用GSP(Grails Server Pages)技术,这是一种结合了HTML和Groovy的模板语言,可以嵌入Groovy表达式和控制结构,实现动态内容的生成。 3. **控制器(Controller)**: ...
借助Groovy的动态特性,Grails能用较少的代码和配置实现常见的Web功能,如表单处理和数据库交互,极大地提高了开发效率。同时,由于Groovy运行在Java虚拟机(JVM)上,Grails应用可无缝集成Java平台,利用Java的成熟...
GORM是Grails的持久化框架,它实现了Hibernate和ActiveRecord的功能,使得与数据库的交互变得简单。通过定义领域类,你可以轻松地完成CRUD(创建、读取、更新、删除)操作。 五、Grails插件系统 Grails的插件系统...
例如,可以创建一个`student_list.gsp`页面,展示所有学生信息,并通过AJAX实现无刷新的查询和分页功能。 五、查询功能与安全性 查询功能通常通过控制器(Controllers)实现,它们接收用户的请求,调用服务层...
通过GORM(Grails Object Relational Mapping),Grails提供了自动的ORM支持,使得开发者无需编写复杂的SQL语句即可实现数据的持久化操作。 #### Controllers(控制器) 控制器(Controllers)负责处理来自用户的...
- **AJAX in Grails**:书中会介绍如何使用jQuery或其他库实现异步更新,提升用户体验。 - **Remote Function Calls (RFC)**:通过AJAX调用控制器的方法,实现页面部分更新。 6. **Java平台集成**: - **...
《Grails权威指南》是一本全面深入探讨Grails框架的专著,旨在帮助读者掌握这一强大的Web开发工具。Grails是一种基于Groovy语言的开源框架,它为构建现代、高效的应用程序提供了简洁高效的解决方案。本指南针对不同...
- **实战技巧**:包括 GORM (Groovy Object Relational Mapping) 的使用、如何在 Grails 中实现 Ajax 功能、处理遗留数据库的方法、利用遗留框架以及如何在 Grails 中使用 WebFlow。 - **高效编程系列**:涵盖使用 ...
Grails提供了方便的分页API,可以轻松地在控制器(Controller)中实现分页逻辑,并在视图(View)中展示结果。在这个例子中,你可能已经掌握了如何实现这一功能。 4. **数据库管理**:`contact_dev.sql`文件可能是...
Grails的独特之处在于它能够吸收其他流行框架的优点,比如Spring的依赖注入、Hibernate的对象关系映射能力、Quartz的强大调度功能以及SiteMesh的布局管理,而这一切都可以在Grails的简单约定和简洁语法下实现。...