Ajax虽是“旧酒装新瓶”,但其威力着实不小。近两年来可谓红透半边天,它之所以能为大众接受,其中一个很大的原因就是提高了用户浏览体验,能更逼真的模拟出GUI界面。 
						
							
Ajax虽是“旧酒装新瓶”,但其威力着实不小。近两年来可谓红透半边天,它之所以能为大众接受,其中一个很大的原因就是提高了用户浏览体验,能更逼真的模拟出GUI界面。好了,Ajax的益处就说到这里,下面让我们看下Grails是如何帮助我们方便地应用Ajax的:
如果您对下面说设计的内容有点不解,那么您可以先看一下 Groovy轻松入门——Grails实战基础篇,然后开始我们的Ajax之旅。
1, 在命令行中输入:“grails create-app AjaxDemo”(注意:不带引号“”)创建一个Grails project,我将它命名为AjaxDemo:
D:\Temp\grails_apps>grails create-app AjaxDemo
| Welcome to Grails 0.5 - http://grails.org/Licensed under Apache Standard License 2.0
 Grails home is set to: D:\D\MY_DEV\grails-0.5
 Base Directory: D:\Temp\grails_appsEnvironment set to production
 Note: No plugin scripts found
 Running script D:\D\MY_DEV\grails-0.5\scripts\CreateApp.groovy
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\src
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\src\java
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\src\groovy
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\src\test
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\controllers
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\jobs
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\services
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\domain
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\taglib
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\utils
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\views
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\views\layouts
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\i18n
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-app\conf
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\grails-tests
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\scripts
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\js
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\css
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\images
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\classes
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\META-INF
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\lib
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\spring
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\hibernate
 [propertyfile] Creating new property file: D:\Temp\grails_apps\AjaxDemo\application.properties
 [copy] Copying 2 files to D:\Temp\grails_apps\AjaxDemo
 [copy] Copying 2 files to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF
 [copy] Copying 5 files to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\tld
 [copy] Copying 119 files to D:\Temp\grails_apps\AjaxDemo\web-app
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\grails-app\conf
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\grails-app\conf
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\grails-app\conf
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\grails-app\conf
 [copy] Copying 13 files to D:\Temp\grails_apps\AjaxDemo\grails-app
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\plugins\core\grails-app\taglib
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\plugins\core\grails-app\utils
 [copy] Copying 7 files to D:\Temp\grails_apps\AjaxDemo\plugins\core\grails-app\taglib
 [copy] Copying 4 files to D:\Temp\grails_apps\AjaxDemo\plugins\core\grails-app\utils
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\spring
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo
 [propertyfile] Updating property file: D:\Temp\grails_apps\AjaxDemo\application.properties
 Created Grails Application at D:\Temp\grails_apps/AjaxDemo
 D:\Temp\grails_apps>
 | 
2,“cd AjaxDemo”,进入AjaxDemo目录,输入“grails create-domain-class User”,创建一个域类User:
| D:\Temp\grails_apps\AjaxDemo>grails create-domain-class UserWelcome to Grails 0.5 - http://grails.org/Licensed under Apache Standard License 2.0
 Grails home is set to: D:\D\MY_DEV\grails-0.5
 Base Directory: D:\Temp\grails_apps\AjaxDemoEnvironment set to production
 Running script D:\D\MY_DEV\grails-0.5\scripts\CreateDomainClass.groovy
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\grails-app\domain
 Created  for User
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\grails-tests
 Created Tests for User
 D:\Temp\grails_apps\AjaxDemo>
 | 
3,“grails generate-all User”,生成scaffolding code(如:list.gsp等):
| D:\Temp\grails_apps\AjaxDemo>grails generate-all User Welcome to Grails 0.5 - http://grails.org/Licensed under Apache Standard License 2.0
 Grails home is set to: D:\D\MY_DEV\grails-0.5
 Base Directory: D:\Temp\grails_apps\AjaxDemoEnvironment set to production
 Running script D:\D\MY_DEV\grails-0.5\scripts\GenerateAll.groovy
 Compiling sources
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\lib
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\spring
 [copy] Copying 34 files to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\lib
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\grails-app\i18n
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\grails-app\views
 [copy] Copying 2 files to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\grails-app\views
 [mkdir] Created dir: D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\templates\scaffolding
 [copy] Copying 5 files to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\templates\scaffolding
 [native2ascii] Converting 7 files from D:\Temp\grails_apps\AjaxDemo\grails-app\i18n to
 D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\grails-app\i18n
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\spring
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\classes
 [copy] Copying 1 file to D:\Temp\grails_apps\AjaxDemo\web-app\WEB-INF\classes
 Generating views for domain class [User]
 Generating list view for domain class [User]
 list view generated at D:\Temp\grails_apps\AjaxDemo\.\grails-app\views\user\list.gsp
 Generating show view for domain class [User]
 Show view generated at D:\Temp\grails_apps\AjaxDemo\.\grails-app\views\user\show.gsp
 Generating edit view for domain class [User]
 Edit view generated at D:\Temp\grails_apps\AjaxDemo\.\grails-app\views\user\edit.gsp
 Generating create view for domain class [User]
 Create view generated at D:\Temp\grails_apps\AjaxDemo\.\grails-app\views\user\create.gsp
 Generating controller for domain class [User]
 Controller generated at .\grails-app\controllers\UserController.groovy
 D:\Temp\grails_apps\AjaxDemo>
 | 
4,修改AjaxDemo\grails-app\controllers\UserController.groovy的内容为:
| class  UserController {def index  =  { redirect(action:list,params:params) }
 //  the delete, save and update actions only//  accept POST requests
 def allowedMethods  =  [delete: ' POST ' ,
 save: ' POST ' ,
 update: ' POST ' ]
 def list  =  {if ( ! params.max)params.max  =   10
 [ userList: User.list( params ) ]
 }
 def show  =  {[ user : User.get( params.id ) ]
 }
 def delete  =  {def user  =  User.get( params.id )
 if (user) {
 user.delete()
 flash.message  =   " User ${params.id} deleted. "
 redirect(action:list)
 }
 else  {
 flash.message  =   " User not found with id ${params.id} "
 redirect(action:list)
 }
 }
 def edit  =  {def user  =  User.get( params.id )
 if ( ! user) {flash.message  =   " User not found with id ${params.id} "
 redirect(action:list)
 }
 else  {
 return  [ user : user ]
 }
 }
 def update  =  {def user  =  User.get( params.id )
 if (user) {
 user.properties  =  params
 if (user.save()) {
 redirect(action:show,id:user.id)
 }
 else  {
 render(view: ' edit ' ,model:[user:user])
 }
 }
 else  {
 flash.message  =   " User not found with id ${params.id} "
 redirect(action:edit,id:params.id)
 }
 }
 def create  =  {def user  =   new  User()
 user.properties  =  params
 return  [ ' user ' :user]
 }
 def save  =  {def user  =   new  User()
 user.properties  =  params
 if (user.save()) {
 redirect(action:show,id:user.id)
 }
 else  {
 render(view: ' create ' ,model:[user:user])
 }
 }
 //  自己添加的Closure ajax定义def ajax  =  {}
 
 //  自己添加的Closure sayHello定义
 def sayHello  =  {
 render  " [${new Date()}] Hello, ${params.name} "
 }
 }
 | 
添加sayHello闭包的目的很明显,因为客户端需要调用。那为什么还要添加ajax这个闭包呢?其实添加 ajax 这个闭包的目的是使
http://localhost:8080/AjaxDemo/user/ ajax 这个请求合法化,否则会发生404错误,找不到页面:
HTTP ERROR: 404
Not Found
RequestURI=/AjaxDemo/user/ajax
Powered by Jetty://
所以被客户端请求的 每个 gsp页面,都需要在相应的Controller中添加以gsp文件名为变量名的Closure,如上面的ajax.gsp和ajax = {}所示,其中Closure中可以添加相关代码,我们这里仅仅是做Ajax的演示,所以就不需要代码
5,在AjaxDemo\grails-app\views\user目录下,新建ajax.gsp,用来演示remoteLink的用法,内容为:
| < g:javascript  library ="prototype"   />< div  id ="hello" > Content will be displayed here </ div >
 < g:remoteLink  action ="sayHello"  params ="[name:'BlueSUN']"   update ="hello" >Say Hello </ g:remoteLink >
 | 
params表示要传递的参数,而update表示返回结果显示的地方,注意update="hello"中的hello对应于div的id,表示结果将显示于div所在处。
点击链接后的界面:
[Fri May 11 17:46:47 CST 2007] Hello, BlueSUN
Say Hello
6,修改AjaxDemo\grails-app\views\user\ ajax.gsp,演示formRemote的用法,内容为:
| <g:javascript library="prototype" /> <div id="hello">Content will be displayed here</div><div id="error"></div>
 <g:remoteLink action="sayHello" params="[name:'BlueSUN']"  update="hello">Say Hello</g:remoteLink> <hr /> <g:formRemote name="test" url="[controller:'user',action:'sayHello']"  update="[success:'hello',failure:'error']"><input type="text" name="name" value="BlueSUN" />
 <input type="submit" value="Say Hello" />
 </g:formRemote >
 
 | 
原本用params传递的参数,现在可以以form的形式传递了,将想传递的内容输入name的textfield中即可。
默认值我设为BlueSUN,现在我将值改为terry,点击Say Hello按钮,结果如下:
[Fri May 11 18:16:17 CST 2007] Hello, terry
Say Hello
7,修改AjaxDemo\grails-app\views\user\ ajax.gsp和AjaxDemo\grails-app\controllers\UserController.groovy,演示remoteField的用法:
ajax.gsp:
| <g:javascript library="prototype" /><div id="hello">Content will be displayed here</div>
 <div id="error"></div>
 <g:remoteLink action="sayHello" params="[name:'BlueSUN']"  update="hello">Say Hello</g:remoteLink> <hr /> <g:formRemote name="test" url="[controller:'user',action:'sayHello']"  update="[success:'hello',failure:'error']"><input type="text" name="name" value="BlueSUN" />
 <input type="submit" value="Say Hello" />
 </g:formRemote >
 <hr /> <g:remoteField action="sayHello2" update="hello"  name="name" value="" /> UserController.groovy:
 class UserController {
 def index = { redirect(action:list,params:params) }
 // the delete, save and update actions only// accept POST requests
 def allowedMethods = [delete:'POST',
 save:'POST',
 update:'POST']
 def list = {if(!params.max)params.max = 10
 [ userList: User.list( params ) ]
 }
 def show = {[ user : User.get( params.id ) ]
 }
 def delete = {def user = User.get( params.id )
 if(user) {
 user.delete()
 flash.message = "User ${params.id} deleted."
 redirect(action:list)
 }
 else {
 flash.message = "User not found with id ${params.id}"
 redirect(action:list)
 }
 }
 def edit = {def user = User.get( params.id )
 if(!user) {flash.message = "User not found with id ${params.id}"
 redirect(action:list)
 }
 else {
 return [ user : user ]
 }
 }
 def update = {def user = User.get( params.id )
 if(user) {
 user.properties = params
 if(user.save()) {
 redirect(action:show,id:user.id)
 }
 else {
 render(view:'edit',model:[user:user])
 }
 }
 else {
 flash.message = "User not found with id ${params.id}"
 redirect(action:edit,id:params.id)
 }
 }
 def create = {def user = new User()
 user.properties = params
 return ['user':user]
 }
 def save = {def user = new User()
 user.properties = params
 if(user.save()) {
 redirect(action:show,id:user.id)
 }
 else {
 render(view:'create',model:[user:user])
 }
 }
 // 自己添加的Closure ajax定义def ajax = {}
 
 // 自己添加的Closure sayHello定义
 def sayHello = {
 render "[${new Date()}] Hello, ${params.name}"
 }
 
 // 自己添加的Closure sayHello2定义
 def sayHello2 = {
 render "[${new Date()}] Hello, ${params.value}"
 }
 }
 | 
由于 用remoteField传递过来的参数名为value,又为了保留以前的演示,所以再定义一个sayHello2闭包,注意是params.value而非params.name
输入“BlueSUN” ,请注意输入时页面的相应更新效果,结果界面:
输入到一半,即输入“Blue”
[Fri May 11 18:34:03 CST 2007] Hello, Blue
Say Hello
紧接着输入“SUN”
[Fri May 11 18:32:42 CST 2007] Hello, BlueSUN
Say Hello
8,修改AjaxDemo\grails-app\views\user\ ajax.gsp,演示remoteFunction的用法,内容为:
| <g:javascript library="prototype" /><div id="hello">Content will be displayed here</div>
 <div id="error"></div>
 <g:remoteLink action="sayHello" params="[name:'BlueSUN']"  update="hello">Say Hello</g:remoteLink> <hr /> <g:formRemote name="test" url="[controller:'user',action:'sayHello']"  update="[success:'hello',failure:'error']"><input type="text" name="name" value="BlueSUN" />
 <input type="submit" value="Say Hello" />
 </g:formRemote >
 <hr /> <g:remoteField action="sayHello2" update="hello"  name="name" value="" /> <hr /> <button onClick="${remoteFunction(action:'sayHello', update:[success:'hello', failure:'error'], params:'\'name=\' + \'BlueSUN\'')}"> Say Hello</button> | 
点击Say Hello按钮后,结果页面:
| [Fri May 11 18:48:37 CST 2007] Hello, BlueSUNSay Hello
 Say Hello | 
9,Grails也可以利用Ajax异步显示Server端返回的页面,新建页面AjaxDemo\grails-app\views\user\result.gsp:
| < html >< head >
 < meta  http-equiv ="Content-Type"
  content ="text/html; charset=UTF-8" />< meta  name ="layout"  content ="main"   />
 < title > Result Page </ title >
 </ head >
 < body >
 < div  class ="nav" >
 < span  class ="menuButton" >
 < a  href ="${createLinkTo(dir:'')}" > Home </ a ></ span ></ div >
 < div  class ="body" >
 < h1 > ${name} </ h1 >
 </ div >
 </ body >
 </ html >
 | 
修改AjaxDemo\grails-app\controllers\UserController.groovy:
| class  UserController {def index  =  { redirect(action:list,params:params) }
 //  the delete, save and update actions only//  accept POST requests
 def allowedMethods  =  [delete: ' POST ' ,
 save: ' POST ' ,
 update: ' POST ' ]
 def list  =  {if ( ! params.max)params.max  =   10
 [ userList: User.list( params ) ]
 }
 def show  =  {[ user : User.get( params.id ) ]
 }
 def delete  =  {def user  =  User.get( params.id )
 if (user) {
 user.delete()
 flash.message  =   " User ${params.id} deleted. "
 redirect(action:list)
 }
 else  {
 flash.message  =   " User not found with id ${params.id} "
 redirect(action:list)
 }
 }
 def edit  =  {def user  =  User.get( params.id )
 if ( ! user) {flash.message  =   " User not found with id ${params.id} "
 redirect(action:list)
 }
 else  {
 return  [ user : user ]
 }
 }
 def update  =  {def user  =  User.get( params.id )
 if (user) {
 user.properties  =  params
 if (user.save()) {
 redirect(action:show,id:user.id)
 }
 else  {
 render(view: ' edit ' ,model:[user:user])
 }
 }
 else  {
 flash.message  =   " User not found with id ${params.id} "
 redirect(action:edit,id:params.id)
 }
 }
 def create  =  {def user  =   new  User()
 user.properties  =  params
 return  [ ' user ' :user]
 }
 def save  =  {def user  =   new  User()
 user.properties  =  params
 if (user.save()) {
 redirect(action:show,id:user.id)
 }
 else  {
 render(view: ' create ' ,model:[user:user])
 }
 }
 //  自己添加的Closure ajax定义def ajax  =  {}
 
 //  自己添加的Closure sayHello定义
 def sayHello  =  {
 render  " [${new Date()}] Hello, ${params.name} "
 }
 
 //  自己添加的Closure sayHello2定义
 def sayHello2  =  {
 render  " [${new Date()}] Hello, ${params.value} "
 }
 //  自己添加的Closure displayResultPage定义
 def displayResultPage  =  {
 render(view: ' result ' , model:[name:params.name])
 }
 }
 | 
修改AjaxDemo\grails-app\views\user\ajax.gsp:
| < g:javascript  library ="prototype"   />< div  id ="hello" > Content will be displayed here </ div >
 < div  id ="error" ></ div >
 < g:remoteLink  action ="sayHello"  params ="[name:'BlueSUN']"   update ="hello" > Say Hello </ g:remoteLink > < hr  /> < g:formRemote  name ="test"  url ="[controller:'user',action:'sayHello']"   update ="[success:'hello',failure:'error']" >< input  type ="text"  name ="name"  value ="BlueSUN"   />
 < input  type ="submit"  value ="Say Hello"   />
 </ g:formRemote  >
 < hr  /> < g:remoteField  action ="sayHello2"   update ="hello"   name ="name"  value =""   /> < hr  /> < button  onClick ="${remoteFunction(action:'sayHello', update:[success:'hello', failure:'error'], params:'\'name=\' + \'BlueSUN\'')}"  > Say Hello </ button > < hr  /> < g:formRemote  name ="test"  url ="[controller:'user',action:'displayResultPage']"   update ="[success:'hello',failure:'error']" >< input  type ="text"  name ="name"  value ="BlueSUN"   />
 < input  type ="submit"  value ="Say Hello"   />
 </ g:formRemote  >
 | 
输入“terry”,点击Say Hello按钮,结果页面(样式的丢失是因为在ajax.gsp中没有声明css,目的是抓重点,抛开一切琐碎的内容):
最后要提醒大家一点,如果要使用中文,请将中文写在AjaxDemo\grails-app\i18n\messages_zh_CN.properties中,然后用<g:message code="key" />来显示。
查看本文来源