在學(xué)習(xí)任何東西之前,最重要的是培養(yǎng)興趣,Groovy世界最耀眼的技術(shù)之一--Grails相信大家早已耳聞,我將通過Grails實(shí)戰(zhàn)系列文章向您展現(xiàn)Grails的迷人風(fēng)采,使您感受到Grails的魅力,以至瘋狂地愛上Grails,并墜入Groovy的愛河。學(xué)Groovy,Grails與學(xué)Java一樣,在實(shí)戰(zhàn)之前需要搭建開發(fā)環(huán)境,您可以在
Groovy輕松入門--搭建Groovy開發(fā)環(huán)境
學(xué)習(xí)到如何搭建Groovy環(huán)境,之后我會講一下如何搭建Grails環(huán)境,然后手把手地寫個(gè)Demo程序告終,我還會抽空寫篇“Groovy輕松入門--Grails實(shí)戰(zhàn)之進(jìn)階篇”
一,搭建Grails環(huán)境
0,下載Grails(?http://dist.codehaus.org/grails/grails-bin-1.0.zip,請留意朝花夕拾——Groovy & Grails中的“最新版本”提示)并解壓到自己指定位置(我的位置是D:\D\MY_DEV\grails)
1,設(shè)置環(huán)境變量GRAILS_HOME(注意大寫),過程與“設(shè)置環(huán)境變量GROOVY_HOME”相似
2,將%GRAILS_HOME%\bin添加到環(huán)境變量path中,過程與“將GROOVY_HOME目錄下的bin追加到環(huán)境變量path中”相似
(如果只想進(jìn)行Grails開發(fā),可以不設(shè)GROOVY_HOME)
二,創(chuàng)建Grails Demo程序
3,打開“命令行”,選擇當(dāng)前目錄(我的為D:\Temp\grails_apps),在黑底白字的窗口中輸入“grails create-app demo”,不包括雙引號“”,在您的屏幕中可以看到類似下面的輸出結(jié)果:
Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: D:\D\MY_DEV\grails-1.0
Base Directory: D:\_DEV\grails_apps
Environment set to development
Note: No plugin scripts found
Running script D:\D\MY_DEV\grails-1.0\scripts\CreateApp.groovy
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\src
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\src\java
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\src\groovy
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\controllers
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\services
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\domain
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\taglib
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\utils
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\views
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\views\layouts
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\i18n
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\conf
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\test
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\test\unit
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\test\integration
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\scripts
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\web-app
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\web-app\js
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\web-app\css
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\web-app\images
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\web-app\WEB-INF\classes
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\web-app\META-INF
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\lib
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\conf\spring
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\grails-app\conf\hibernate
[propertyfile] Creating new property file: D:\_DEV\grails_apps\demo\application.properties
???? [copy] Copying 2 files to D:\_DEV\grails_apps\demo
???? [copy] Copying 2 files to D:\_DEV\grails_apps\demo\web-app\WEB-INF
???? [copy] Copying 5 files to D:\_DEV\grails_apps\demo\web-app\WEB-INF\tld
???? [copy] Copying 87 files to D:\_DEV\grails_apps\demo\web-app
???? [copy] Copying 17 files to D:\_DEV\grails_apps\demo\grails-app
???? [copy] Copying 1 file to D:\_DEV\grails_apps\demo
???? [copy] Copying 1 file to D:\_DEV\grails_apps\demo
???? [copy] Copying 1 file to D:\_DEV\grails_apps\demo
[propertyfile] Updating property file: D:\_DEV\grails_apps\demo\application.properties
Created Grails Application at D:\_DEV\grails_apps/demo
D:\_DEV\grails_apps>
通過“grails create-app”這個(gè)命令,Grails自動幫我們創(chuàng)建了開發(fā)所需的工程環(huán)境。其實(shí)您現(xiàn)在就已經(jīng)擁有了一個(gè)可運(yùn)行的Web應(yīng)用程序,
然后進(jìn)入demo目錄(“cd demo”),輸入“grails run-app”,回車,啟動這個(gè)‘五臟俱全’的程序雛形,打開瀏覽器,輸入 http://localhost:8080/demo ,回車,看到了吧 :) 讓我們繼續(xù)吧,請停止這個(gè)程序(Ctrl + C)
4,在“命令行”中輸入“cd demo”,回車,以進(jìn)入demo目錄,然后再輸入“grails create-domain-class User”創(chuàng)建domain class即類似于pojo的pogo,它對應(yīng)MVC中的Model,不過由Grails自動創(chuàng)建的pogo是空的,需要自己添加屬性,約束(constraints)等。輸出結(jié)果如下所示:
Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: D:\D\MY_DEV\grails-1.0
Base Directory: D:\_DEV\grails_apps\demo
Environment set to development
Note: No plugin scripts found
Running script D:\D\MY_DEV\grails-1.0\scripts\CreateDomainClass.groovy
???? [copy] Copying 1 file to D:\_DEV\grails_apps\demo\grails-app\domain
Created? for User
???? [copy] Copying 1 file to D:\_DEV\grails_apps\demo\test\integration
Created Tests for User
D:\_DEV\grails_apps\demo>
5,進(jìn)入D:\Temp\grails_apps\demo\grails-app\domain(這個(gè)目錄中存放著所有的domain class),打開User.groovy,修改為如下內(nèi)容:
????String?name
????String?password
????
????String?toString()?{
???????? " $name?:?$password " ????
????}
????
???? static ?constraints? = ?{
????????name(blank:? false )????
????????password(blank:? false ,?size:? 6 .. 16 )
????}
}????
6,在“命令行”中輸入“grails generate-all User”,為User產(chǎn)生所有CRUD操作需要的代碼(如控制器UserController.groovy)和頁面(如list.gsp),輸出結(jié)果如下所示:
Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: D:\D\MY_DEV\grails-1.0
Base Directory: D:\_DEV\grails_apps\demo
Environment set to development
Note: No plugin scripts found
Running script D:\D\MY_DEV\grails-1.0\scripts\GenerateAll.groovy
??? [mkdir] Created dir: D:\_DEV\grails_apps\demo\web-app\WEB-INF\lib
??? [mkdir] Created dir: C:\Documents and Settings\Daniel\.grails\1.0\projects\demo\classes
? [groovyc] Compiling 7 source files to C:\Documents and Settings\Daniel\.grails\1.0\projects\demo\classes
??? [mkdir] Created dir: C:\Documents and Settings\Daniel\.grails\1.0\projects\demo\resources\grails-app\i18n
[native2ascii] Converting 10 files from D:\_DEV\grails_apps\demo\grails-app\i18n to C:\Documents and Settings\Daniel\.grails\1.0\projects\demo\re
sources\grails-app\i18n
???? [copy] Copying 1 file to C:\Documents and Settings\Daniel\.grails\1.0\projects\demo\classes
???? [copy] Copying 1 file to C:\Documents and Settings\Daniel\.grails\1.0\projects\demo\resources
???? [copy] Copying 1 file to C:\Documents and Settings\Daniel\.grails\1.0\projects\demo
[0] spring.GrailsWebApplicationContext Refreshing org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext@2b2057: display name [org
.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext@2b2057]; startup date [Tue Feb 05 23:26:45 CST 2008]; root of context hierarch
y
[16] spring.GrailsWebApplicationContext Bean factory for application context [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationConte
xt@2b2057]: org.springframework.beans.factory.support.DefaultListableBeanFactory@eebf17
Generating views for domain class User ...
Generating controller for domain class User ...
Finished generation for domain class User
D:\_DEV\grails_apps\demo>
7,修改demo\grails-app\controllers\UserController.groovy的內(nèi)容為:
class?UserController?{
????def?loginService?//?新增的代碼
????
????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?=?{
????????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?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.hasErrors()?&&?user.save())?{
????????????????flash.message?=?"User?${params.id}?updated"
????????????????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(params)
????????if(!user.hasErrors()?&&?user.save())?{
????????????flash.message?=?"User?${user.id}?created"
????????????redirect(action:show,id:user.id)
????????}
????????else?{
????????????render(view:'create',model:[user:user])
????????}
????}
????//?新增的代碼
????def?login?=?{
????????if?(request.method?==?'POST')?{
????????????User?u?=?new?User()
????????????u.properties?=?params
????
????????????if?(!u.validate())?{
????????????????render(view:'login',?model:[user:u])
????????????}
????
????????????if?(params.name?&&?params.password)?{
????
????????????????def?user?=?loginService.check(u)
????????????????
????????????????if?(user)?{
??????????????????? flash.message?=?"Welcome?${user.name}"?
??????????????????? render(view:?"ok",?model:?[user:?user])
????????????????}?else?{
??????????????????? flash.error?=?"Invalid?${u.name}?with?${u.password}"
??????????????????? render(view:?"login",?model:?[user:?u])
????????????????}????
????????????}?else?{
????????????????render(view:?"login",?model:?[user:?u])
????????????}
????????}
????}
}
大家或許也看到了LoginService這個(gè)類,我將在后面演示創(chuàng)建它,這個(gè)LoginService類封裝了所有登陸相關(guān)的業(yè)務(wù)邏輯,Grails會自動將其注入到UserController中
8,在“命令行”中,輸入“grails create-service Login”,創(chuàng)建LoginService.groovy,輸出:
Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: D:\D\MY_DEV\grails-1.0
Base Directory: D:\_DEV\grails_apps\demo
Environment set to development
Note: No plugin scripts found
Running script D:\D\MY_DEV\grails-1.0\scripts\CreateService.groovy
???? [copy] Copying 1 file to D:\_DEV\grails_apps\demo\grails-app\services
Created Service for Login
???? [copy] Copying 1 file to D:\_DEV\grails_apps\demo\test\integration
Created ServiceTests for Login
D:\_DEV\grails_apps\demo>
9,修改demo\grails-app\services\LoginService.groovy的內(nèi)容為:
????boolean?transactional?=?true
????def?check(User?u)?{
????????def?user?=?User.findWhere(name:?u.name,?password:?u.password)
????????return?user
????}
}
10,在demo\grails-app\views\user目錄下創(chuàng)建login.gsp和ok.gsp,它們對應(yīng)MVC中的View,內(nèi)容分別為:
login.gsp (復(fù)制demo\grails-app\views\user\create.gsp的內(nèi)容到login.gsp中,并修改):
<html>
????<head>
????????<meta?http-equiv="Content-Type"?content="text/html;?charset=UTF-8"/>
????????<meta?name="layout"?content="main"?/>
????????<!--?將Create?User修改為Login?-->
????????<title>Login</title>?????????
????</head>
????<body>
????????<div?class="nav">
????????????<span?class="menuButton"><a?class="home"?href="${createLinkTo(dir:'')}">Home</a></span>
????????????<span?class="menuButton"><g:link?class="list"?action="list">User?List</g:link></span>
????????</div>
????????<div?class="body">
????????????<!--?將Create?User修改為Login?-->
????????????<h1>Login</h1>
????????????<!--?將flash.message修改為flash.error?-->
????????????<g:if?test="${flash.error}">
????????????<!--?將class="message"修改為class="errors",?將flash.message修改為flash.error?-->
????????????<div?class="errors">${flash.error}</div>
????????????</g:if>
????????????<g:hasErrors?bean="${user}">
????????????<div?class="errors">
????????????????<g:renderErrors?bean="${user}"?as="list"?/>
????????????</div>
????????????</g:hasErrors>
????????????
????????????<!--?將action="save"修改為action="login"?-->
????????????<g:form?action="login"?method="post"?>
????????????????<div?class="dialog">
????????????????????<table>
????????????????????????<tbody>
????????????????????????
????????????????????????????<tr?class="prop">
????????????????????????????????<td?valign="top"?class="name">
????????????????????????????????????<label?for="name">Name:</label>
????????????????????????????????</td>
????????????????????????????????<td?valign="top"?class="value?${hasErrors(bean:user,field:'name','errors')}">
????????????????????????????????????<input?type="text"?id="name"?name="name"?value="${fieldValue(bean:user,field:'name')}"/>
????????????????????????????????</td>
????????????????????????????</tr>?
????????????????????????
????????????????????????????<tr?class="prop">
????????????????????????????????<td?valign="top"?class="name">
????????????????????????????????????<label?for="password">Password:</label>
????????????????????????????????</td>
????????????????????????????????<td?valign="top"?class="value?${hasErrors(bean:user,field:'password','errors')}">
????????????????????????????????????<input?type="text"?maxlength="16"?id="password"?name="password"?value="${fieldValue(bean:user,field:'password')}"/>
????????????????????????????????</td>
????????????????????????????</tr>?
????????????????????????
????????????????????????</tbody>
????????????????????</table>
????????????????</div>
????????????????<div?class="buttons">
????????????????????<!--?將value="Create"修改為value="Login"?-->
????????????????????<span?class="button"><input?class="save"?type="submit"?value="Login"?/></span>
????????????????</div>
????????????</g:form>
????????</div>
????</body>
</html>
ok.gsp:
????<div?class="message">${flash.message}</div>
</g:if>
Name:?${user?.name}???<br>
Password:?${user?.password}
11,修改demo\grails-app\conf\BootStrap.groovy,初始化數(shù)據(jù)庫:將一個(gè)User實(shí)例保存到數(shù)據(jù)庫(grails自帶hsqldb和jetty)中,內(nèi)容如下:
?????def?init?=?{?servletContext?->
???????? new?User(name:?"demo",?password:?"123456").save()
?????}
?????def?destroy?=?{
?????}
}?
12,在“命令行”中,輸入“grails run-app”,運(yùn)行我們的Web應(yīng)用,輸出如下:
Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: D:\D\MY_DEV\grails-1.0
Base Directory: D:\_DEV\grails_apps\demo
Environment set to development
Note: No plugin scripts found
Running script D:\D\MY_DEV\grails-1.0\scripts\RunApp.groovy
? [groovyc] Compiling 4 source files to C:\Documents and Settings\Daniel\.grails\1.0\projects\demo\classes
Running Grails application..
2008-02-05 23:46:08.912::INFO:? Logging to STDERR via org.mortbay.log.StdErrLog
2008-02-05 23:46:08.066::INFO:? jetty-6.1.4
2008-02-05 23:46:08.347::INFO:? No Transaction manager found - if your webapp requires one, please configure one.
2008-02-05 23:46:09.081:/demo:INFO:? Set web app root system property: 'demo' = [D:\_DEV\grails_apps\demo\web-app\]
2008-02-05 23:46:09.081:/demo:INFO:? Initializing Log4J from [file:C:\Documents and Settings\Daniel/.grails/1.0/projects/demo/resources/log4j.pro
perties]
2008-02-05 23:46:09.113:/demo:INFO:? Initializing Spring root WebApplicationContext
[0] spring.GrailsWebApplicationContext Refreshing org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext@5facbd: display name [org
.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext@5facbd]; startup date [Tue Feb 05 23:46:14 CST 2008]; parent: org.springframew
ork.web.context.support.XmlWebApplicationContext@1fef80a
[0] spring.GrailsWebApplicationContext Bean factory for application context [org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContex
t@5facbd]: org.springframework.beans.factory.support.DefaultListableBeanFactory@aa4c7c
2008-02-05 23:46:21.590:/demo:INFO:? Initializing Spring FrameworkServlet 'grails'
2008-02-05 23:46:21.871::INFO:? Started SelectChannelConnector@0.0.0.0:8080
Server running. Browse to http://localhost:8080/demo
13,打開瀏覽器,輸入:http://localhost:8080/demo/user/login?,在Name處輸入demo,Password處輸入123456,點(diǎn)擊‘Login’,跳轉(zhuǎn)到成功頁面:
Password: 123456
如果您對Grails的工程目錄不太熟悉,我這里為大家提供了一張表,詳細(xì)地描述了各目錄的用途:
《Grails權(quán)威指南》表3-1.Grails工程目錄
目錄名稱 | 相關(guān)描述 |
grails-app | 此目錄包含了Grails應(yīng)用程序的核心工件(core artifact) |
+ conf | 此目錄包含了諸如DevelopmentDataSource.groovy的配置文件 |
+ controllers | 此目錄包含了處理請求(request)的控制器(controller),Grails控制器將在第7章中進(jìn)行講解 |
+ domain | 此目錄包含了領(lǐng)域模型(domain model),領(lǐng)域模型將在第4章進(jìn)行講解 |
+ i18n | 此目錄包含了用于國際化的消息束(message bundle)(譯者注:指的是properties文件,如messages.properties) |
+ services | 此目錄包含了封裝業(yè)務(wù)邏輯的service文件,service將在第10章中進(jìn)行講解 |
+ taglib | 此目錄包含了輔助頁面生成的動態(tài)標(biāo)簽庫,動態(tài)標(biāo)簽將在第8章中進(jìn)行講解 |
+ views | 此目錄包含了Groovy服務(wù)器頁面(GSP)以及JSP頁面 |
+ layouts | 此目錄包含了GSP或JSP的布局(layout),這些布局由SiteMesh提供支持,這將在第8章中進(jìn)行講解 |
grails-test | 此目錄包含了應(yīng)用程序的單元測試 |
hibernate | 此目錄包含了可選的Hibernate配置文件,這將在第11章中進(jìn)行講解 |
lib | 此目錄包含了jar文件 |
spring | 此目錄包含了可選的Spring配置文件,這將在第11章中進(jìn)行講解 |
src | 此目錄包含了其他Groovy和Java資源 |
+ java | 此目錄包含了待編譯的Java源文件 |
+ groovy | 此目錄包含了待編譯的Groovy源文件 |
web-app | 此目錄包含了Web應(yīng)用程序的資源(CSS,JavaScript等) |
注:Grails1.0已將hibernate和spring兩個(gè)目錄移到grails-app\conf目錄下了,
而grails-test目錄也更名為test,test目錄下有integration目錄和unit目錄,分別存放集成測試代碼和單元測試代碼
想象一下用您平時(shí)做項(xiàng)目時(shí)所用的框架組合(比如SSH)來創(chuàng)建同樣的Web應(yīng)用程序,您立刻會感受,Grails讓我們專注于業(yè)務(wù)邏輯,而不用浪費(fèi)時(shí)間在那些scaffolding code(如配置文件)上。從今天開始,您不用再羨慕那些Ruby程序員所用的RoR了,您大可以使用Grails來高效開發(fā)Web應(yīng)用。
您也可以訪問Grails官方網(wǎng)站(http://www.grails.org)進(jìn)一步學(xué)習(xí)。
附:朝花夕拾——Groovy & Grails