Èç½ñµÄJava Web¿ª·¢¶ÔÓÚÐèÇóÀ´ËµÒѾ±äµÃ¹ýÓÚ¸´ÔÓ¡£µ±½ñÖÚ¶àJavaÁìÓòµÄWeb¿ª·¢¿ò¼Ü²»½öʹÓø´ÔÓ£¬¶øÇÒ²¢Ã»ÓкܺõÄ×ñÑDon¡¯t Repeat Yourself£¨DRY£©ÔÔò¡£
ÏñRails£¬DjangoºÍTurboGearsÕâÑùµÄ¶¯Ì¬¿ò¼ÜÔÚWeb¿ª·¢ÁìÓò¿ª±ÙÁËÒ»ÌõеĵÀ·£¬Grails»ùÓÚÕâЩ¸ÅÄîÖ®ÉÏ£¬²ÉÓö¯Ì¬·½·¨¼õСÁËJavaƽ̨ÉϽøÐÐWeb¿ª·¢µÄ¸´ÔÓ¶È£¬²»¹ýÓëÄÇЩ¿ò¼Ü²»Í¬µÄÊÇ£¬GrailsÊǹ¹½¨ÔÚSpringºÍHibernateµÈJavaÒÑÓеļ¼ÊõÖ®Éϵġ£
GrailsÊÇÒ»¸öfull-stack¿ò¼Ü£¬Ëü½èÖúÓÚºËÐļ¼ÊõÓëÏà¹ØµÄ²å¼þ£¨plug-in£©À´½â¾öWeb¿ª·¢Öз½·½ÃæÃæµÄÎÊÌ⣬ÆäÖаüÀ¨£º
- Ò×ÓÚʹÓõĻùÓÚHibernateµÄ¶ÔÏó-¹ØÏµÓ³Éä(ORM)²ã
- ³ÆÎªGroovy Server Pages (GSP)µÄ±íÏֲ㼼Êõ
- »ùÓÚSpring MVCµÄ¿ØÖÆÆ÷²ã
- ¹¹½¨ÓÚGant ÉϵÄÃüÁîÐнű¾ÔËÐл·¾³
- ÄÚÖÃJetty·þÎñÆ÷£¬²»ÓÃÖØÐÂÆô¶¯·þÎñÆ÷¾Í¿ÉÒÔ½øÐÐÖØÐ¼ÓÔØ
- ÀûÓÃÄÚÖõÄSpring ÈÝÆ÷ʵÏÖÒÀÀµ×¢Èë
- »ùÓÚSpringµÄMessageSourceºËÐĸÅÄÌṩÁ˶Թú¼Ê»¯£¨i18n£©µÄÖ§³Ö
- »ùÓÚSpringÊÂÎñ³éÏó¸ÅÄʵÏÖÊÂÎñ·þÎñ²ã
½èÖúÓÚ¹¦ÄÜÇ¿´óµÄGroovy¶¯Ì¬ÓïÑÔºÍÁìÓòÌØ¶¨ÓïÑÔ£¨Domain Specific Language£¬DSL£©£¬ÒÔÉÏÄÇÐ©ÌØÐÔ±äµÃ·Ç³£Ò×Óá£
ÕâÆªÎĵµ»áÏòÄã½éÉÜÈçºÎʹÓÃGrails¿ò¼ÜÀ´´î½¨WebÓ¦ÓóÌÐò¡£
Ê×ÏÈÐèÒªÏÂÔØGrailsµÄ·¢Ðаü²¢½øÐа²×°£¬Ö´Ðв½ÖèÈçÏ£º
- ÏÂÔØ Grails¶þ½øÖÆ·¢Ðаü²¢½âѹµ½Ö¸¶¨µÄÎļþĿ¼Ï¡£
- ÔÚ»·¾³±äÁ¿ÖÐÌí¼ÓGRAILS_HOME,ֵΪÉÏÒ»²½½âѹµÄÎļþĿ¼¡£
- Unix/LinuxϵͳÉÏÔËÐÐexport GRAILS_HOME=/path/to/grails¡£
- WindowsϵͳÉÏÓÒ»÷¡°ÎҵĵçÄÔ¡±/¡°ÊôÐÔ¡±/¡°¸ß¼¶¡±/¡°»·¾³±äÁ¿¡±£¬µã»÷н¨¡£
- ½«½âѹĿ¼ÏµÄbinĿ¼·¾¶Ìí¼Óµ½pathÖÐ
- Unix/LinuxϵͳÉÏÔËÐÐexport PATH="$PATH:$GRAILS_HOME/bin¡£
- WindowsϵͳÉÏÓÒ»÷¡°ÎҵĵçÄÔ¡±/¡°ÊôÐÔ¡±/¡°¸ß¼¶¡±/¡°»·¾³±äÁ¿¡±£¬ÐÞ¸ÄpathµÄÖµ¡£
Èç¹û»·¾³±äÁ¿ÉèÖÃÎÞÎ󣬴Ëʱ¿ÉÒÔ´ò¿ªÖÕ¶Ë£¨windowÏÂΪÃüÁîÌáʾ·û£¬Unix/LinuxÏÂΪShell£©£¬ÊäÈëgrails£¬Èç¹ûÆÁÄ»ÉÏÏÔʾÈçÏÂÌáʾÔò˵Ã÷°²×°³É¹¦¡£
Welcome to Grails 1.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Developer/grails-1.0
No script name specified. Use 'grails help' for more info
ÔÚ´´½¨Ó¦ÓóÌÐò֮ǰ£¬ÏÈÊìϤһÏÂgrailsÃüÁîµÄʹÓã¨grailsÖеÄÃüÁî¶¼ÔÚÖÕ¶ËÖÐÊäÈ룬Çë²Î¿¼ÉÏÃæµÄ½²½â£©¡£
grails command name
ÏÖÔÚÎÒÃÇΪÁË´´½¨Ò»¸öGrailsÓ¦Óã¬ÐèÒªÊäÈëµÄÃüÁîÊÇcreate-app
grails create-app helloworld
ÕâÑù¾ÍÔÚµ±Ç°Ä¿Â¼Ï´´½¨ÁËÒ»¸öÃûΪhelloworld£¨¼´ÎÒÃǵÄÓ¦ÓóÌÐòÃû£©µÄÎļþ¼Ð£¬ÔÚÕâ¸öÎļþ¼ÐÖаüº¬ÁËÎÒÃÇÕâ¸öÏîÄ¿µÄÕû¸öÎļþĿ¼£¬¿ÉÒÔʹÓÃÈçÏÂÃüÁî½øÈëÕâ¸öĿ¼Öв鿴£º
cd helloworld
ΪÁËÍê³ÉÕâ¸ö¾µäµÄHello WorldʾÀý£¬ÎÒÃÇÐèÒªÔËÐÐcreate-controllerÃüÁî
grails create-controller hello
ÔËÐиÃÃüÁîºó»áÔÚ
grails-app/controllerĿ¼Ï´´½¨Ò»¸öÃûΪ
HelloController.groovyµÄ¿ØÖÆÆ÷£¨¸ü¶à¹ØÓÚ¿ØÖÆÆ÷µÄÄÚÈÝÇë²Î¿¼
¿ØÖÆÆ÷Ò»½Ú£©
¿ØÖÆÆ÷Ö÷ÒªÓÃÀ´Íê³É¶ÔWebÇëÇóµÄ´¦Àí£¬ÎÒÃÇÉÔ΢ÐÞ¸ÄһϿØÖÆÆ÷µÄÄÚÈÝ£¬Ê¹ËüÄܹ»ÔÚÒ³ÃæÉÏÊä³ö"Hello World!"µÄ×ÖÑù£¬´úÂëÈçÏÂ:
class HelloController {
def world = {
render "Hello World!"
}
}
ÏÖÔÚ¿ØÖÆÆ÷ÒѾÍê³ÉÁË£¬½ÓÏÂÀ´ÒªÊ¹ÓÃ
run-appÀ´Æô¶¯ÄÚÖõÄjetty·þÎñÆ÷ÔËÐиոմ´½¨µÄhelloworld³ÌÐò
grails run-app
ÔËÐкó»áÔÚ8080¶Ë¿Ú£¨Ä¬ÈÏ£¬¿ÉÒÔʹÓÃ-Dserver.portÀ´Ö¸¶¨¶Ë¿Ú£©Æô¶¯·þÎñÆ÷£¬È»ºóÔÚä¯ÀÀÆ÷ÖÐÊäÈëhttp://localhost:8080/helloworldÀ´Æô¶¯Ó¦ÓóÌÐò.
ÔËÐнá¹ûÈçÏÂͼËùʾ£º

Õâ¸öGrails¼ò½éÒ³ÃæÊÇÓÉweb-app/index.gspÀ´ÏÔʾµÄ¡£´ÓÉÏͼ¿ÉÒÔ¿´¼û¸Õ²Å´´½¨µÄ¿ØÖÆÆ÷£¬µã»÷Á´½ÓÖ®ºó»áÔÚä¯ÀÀÆ÷ÖÐÏÔʾHello World!µÄ×ÖÑù¡£
IntelliJ IDEA
ÖÁ½ñΪֹ×î³ÉÊì¡¢×îÈ«ÃæµÄGroovy&Grails¿ª·¢¼¯³É¹¤¾ß¾ÍÊÇ
IntelliJ IDEA 7.0ºÍËüµÄ
JetGroovy²å¼þ¡£¶ÔÓÚ´óÐÍÏîÄ¿£¬GrailsÍŶÓÓÅÏÈÍÆ¼öʹÓÃIntelliJ¡£
TextMate
ÓÉÓÚGrailsÄ¿±ê¼¯ÖÐÓÚÈçºÎ¸ü¼ò½à£¬ËùÒÔÎÒÃÇ¿ÉÒÔʹÓÃһЩ¸ü¼òµ¥µÄ±à¼Æ÷½øÐÐGroovy&GrailsµÄ¿ª·¢£¬ÀýÈçÔÚMacÉÏ¿ÉÒÔʹÓÃ
TextMate £¬ÏÂÔØµØÖ·
Texmate bundles SVNEclipse
Eclipse µÄ
Groovy²å¼þ Ò²¿ÉÒÔÖ§³ÖÓï·¨¸ßÁÁ£¬´úÂë×Ô¶¯Íê³ÉµÈÌØÐÔ¡£
ÔÚGrailsµÄWikiÉÏÓиü¶à¹ØÓÚEclipse²å¼þµÄ̸ÂÛ¡£
GrailsÔÚ´´½¨Ó¦ÓÃʱ»á×Ô¶¯´´½¨EclipseµÄ¹¤³ÌÎļþ
.projectºÍ
classpath£¬ÕâÑùÈç¹ûÒªÔÚEclipseÖе¼ÈëÒ»¸öGrails¹¤³ÌÖ»ÐèÒªÔÚEclipseÖÐÓÒ»÷Package Explorer£¬Ñ¡ÔñImport£¬È»ºóÑ¡ÔñExisting project into Workspace£¬×îºóÖ¸¶¨GrailsµÄÏîĿĿ¼λÖá£
µã»÷OK£¬Finishºó»á×Ô¶¯½«Grails¹¤³Ìµ¼Èëµ½EclipseÖС£
²¢×Ô¶¯´´½¨ºÏÊʵÄÔËÐÐÅäÖã¨Run Configuration£©£¬ÕâÑùÔÚEclipseÖÐÖ±½Óµã»÷Run¾Í¿ÉÒÔÔËÐÐGrailsµÄÏîÄ¿¡£
GrailsÖеÄÅäÖÃ×ñÑ¡°¹æÔ¼ÓÅÓÚÅäÖá±µÄÔÔò£¬¼´Í¨¹ýÎļþµÄÃû³ÆºÍλÖÃÀ´Ìæ´úÏÔʽµÄÅäÖã¬Òò´ËÐèÒªÊìϤÒÔϼ¸¸öĿ¼½á¹¹µÄÓÃ;¡£
´Ë´¦½ö½öΪһ¸ö·ÖÀ࣬¾ßÌåµÄÇë²Î¿¼Ïà¹ØÕ½ڣº
grails-app - GroovyÔ´ÎļþµÄ¶¥¼¶Ä¿Â¼
conf - ÅäÖÃÎļþĿ¼,Ïêϸ²Î¿¼ÅäÖÃ.
controllers - ¿ØÖÆÆ÷Ŀ¼£¨MVCÄ£ÐÍÖеÄC£©£¬Ïêϸ²Î¿¼¿ØÖÆÆ÷
domain - ÁìÓòÄ£ÐÍĿ¼£¨MVCÄ£ÐÍÖеÄM£©£¬Ïêϸ²Î¿¼GORM
i18n - ¹ú¼Ê»¯Ä¿Â¼£¬ÓÃÀ´Ö§³Öi18n£¬Ïêϸ²Î¿¼¹ú¼Ê»¯
services - ·þÎñĿ¼£¬Ïêϸ²Î¿¼·þÎñ²ã
taglib - ±êÇ©¿âĿ¼£¬Ïêϸ²Î¿¼±êÇ©¿â
views - ÊÓͼGSPĿ¼£¨MVCÖеÄV£©£¬Ïêϸ²Î¿¼GSP
scripts - Gant½Å±¾Ä¿Â¼,Ïêϸ²Î¿¼Gant½Å±¾
src - Ô´ÎļþĿ¼
groovy - ÆäËûµÄGroovyÔ´ÎļþĿ¼
java - ÆäËûµÄJavaÔ´ÎļþĿ¼
test - µ¥ÔªºÍ¼¯³É²âÊÔĿ¼,Ïêϸ²Î¿¼²âÊÔ
¿ÉÒÔÔËÐÐ
run-appÃüÁîÀ´Æô¶¯GrailsÄÚÖõÄJetty·þÎñÆ÷£¬Ä¬ÈÏÆô¶¯¶Ë¿ÚΪ8080
Èç¹û8080¶Ë¿ÚÒѾ±»Õ¼Ó㬿ÉÒÔͨ¹ý
server.port ²ÎÊýÖ¸¶¨ÆäËû¶Ë¿Ú
grails -Dserver.port=8090 run-app
¸ü¶à¹ØÓÚ
run-appµÄÄÚÈÝ¿ÉÒÔ²ÎÕղο¼Ö¸ÄÏ¡£
create-* ÃüÁî»áÔÚ
test/integrationĿ¼ÏÂ×Ô¶¯´´½¨ÏàÓ¦µÄ²âÊÔÎļþ£¬¿ÉÒÔÔÚÕâЩ²âÊÔÎļþÖбàд²âÊÔÓÃÀýÀ´½øÐе¥Ôª²âÊԺͼ¯³É²âÊÔ£¬¹ØÓÚ²âÊÔµÄÄÚÈÝ¿ÉÒԲο¼
²âÊÔÕ½ڡ£ÔËÐÐÕâЩ²âÊÔ¿ÉÒÔʹÓÃ
test-appÃüÁî¡£
Grails»á×Ô¶¯´´½¨AntµÄ
build.xmlÎļþ£¬Ò²¿ÉÒÔͨ¹ýAntÀ´ÔËÐвâÊÔ(ÆäʵÔËÐеÄÊÇGrailsµÄ
test-app)¡£
ÕâÑùµ±GrailsÓ¦ÓÃ×÷Ϊ³ÖÐø¼¯³Éƽ̨£¬ÀýÈçCruiseControlµÄÒ»²¿·Öʱ¾Í»áÊ®·Ö·½±ã
GrailsÓ¦ÓóÌÐòÒÔWebÓ¦Óù鵵£¨.WAR£©ÎļþµÄÐÎʽ½øÐв¿Ê𣬲¢ÇÒGrails»¹ÌṩÁË
warÃüÁîÀ´Ö´ÐÐÉú³É¹éµµÎļþ¡£
ÕâÌõÃüÁî»áÉú³Éµ±Ç°Ó¦ÓõÄwarÎļþ£¬¿ÉÒÔ°´ÕÕ·þÎñÆ÷ÈÝÆ÷µÄ²»Í¬½øÐÐÏàÓ¦µÄÅäÖÃ.
Ò»¶¨²»ÒªÊ¹ÓÃrun-appÃüÁîÀ´²¿ÊðGrails£¬ÒòΪ´ËÃüÁî»áÔÚÔËÐÐʱ×Ô¶¯¼ÓÔØ£¬ÕâÑù»á¶Ô·þÎñÆ÷µÄÐÔÄܺͿÉÀ©Õ¹ÐÔÓÐÑÏÖØÓ°Ïì¡£
µ±²¿ÊðʱӦµ±Í¨JVMµÄ
-server²ÎÊýÀ´Îª·þÎñÆ÷·ÖÅä×ã¹»µÄÄÚ´æ¿Õ¼ä£¬ÍƼöµÄVM²ÎÊýÊÇ£º
Grails¿ÉÒÔÖ§³ÖµÄÏ൱¶àµÄWebÈÝÆ÷£¬°üÀ¨:
- Tomcat 5.5
- Tomcat 6.0
- GlassFish v1 (Sun AS 9.0)
- GlassFish v2 (Sun AS 9.1)
- Sun App Server 8.2
- Websphere 6.1
- Websphere 5.1
- Resin 3.2
- Oracle AS
- JBoss 4.2
- Jetty 6.1
- Jetty 5
- Weblogic 7/8/9/10
ËäÈ»ÔÚһЩ·þÎñÆ÷ÉÏÔËÐл¹´æÔÚBug£¬µ«ÊǴ󲿷ÖÇé¿ö϶¼¿ÉÒÔ¹¤×÷µÄºÜºÃ¡£ÔÚGrailsµÄWikiÉÏ¿ÉÒÔÕÒµ½¹ØÓÚ
ÒÑÖª²¿ÊðÎÊÌâµÄÇåµ¥¡£
³ýÁËÒÔÉϽéÉܵÄÃüÁGrails»¹ÓÐһϵÁÐÓÃÀ´´´½¨ÆäËû¹¤¼þÀàÐ͵ÄÃüÁÀýÈç¿ÉÒÔʹÓÃ
create-controller,
create-domain-classµÈµÈ¡£
ΪÁË·½±ã¿ÉÒÔʹÓÃIDE»òÕ߯äËûÄãϲ»¶µÄ±à¼Æ÷À´´´½¨
±ÈÈç˵£¬ÎªÁË´´½¨Ò»¸öÓ¦ÓõĻù´¡£¬ÄãÖÁÉÙÐèÒªÒ»¸ö
ÁìÓòÄ£ÐÍ£¬ÃüÁîÈçÏ£º
grails create-domain-class book
ÕâÑù»áÔÚ
grails-app/domain/Book.groovyÖд´½¨Ò»¸öÁìÓòÀ࣬ÆäÄÚÈÝÈçÏÂ:
¸ü¶àµÄ
create-*ÃüÁî¿ÉÒÔÔڲο¼Ö¸ÄϵÄÃüÁîÐÐÖб»Ì½Ë÷¡£
ÔÚ´´½¨ÍêGrailsÓ¦Óúóͨ³£»áʹÓá°
½ÅÊּܡ±À´Éú³ÉÕû¸öÓ¦ÓóÌÐòµÄ¹Ç¼Ü¡£ÕâÊÇͨ¹ýʹÓÃ
generate-*ÃüÁîÀ´Íê³ÉµÄ£¬ÀýÈçʹÓÃ
generate-allÃüÁîÀ´¸ù¾ÝÁìÓòÄ£ÐÍÉú³É
¿ØÖÆÆ÷¼°ÆäÏàÓ¦
ÊÓͼ¡£ÓÉÓÚ֮ǰÎÒÃÇ´´½¨ÁËÒ»¸öBook.groovyµÄÁìÓòÄ£ÐÍ£¬Òò´ËÔÚÕâÀïÔËÐÐÈçÏÂÃüÁî¡£
¸ü¶à¹ØÓÚ½ÅÊּܵÄÄÚÈÝÇë²Î¿¼Óû§Ö¸Äϵĺó±ßÕ½ڡ£
Ò²ÐíÔÚÕâÀï̸ÂÛÅäÖöÔÓÚÒ»¸ö×ñÑ¡°¹æÔ¼ÓÅÓÚÅäÖᱵĿò¼ÜÀ´Ëµ£¬»áÈÃÈ˸е½±È½ÏÆæ¹Ö£¬µ«ÊÇʵ¼ÊÉÏÎÒÃÇÕâÀïËù˵µÄÅäÖÃÊÇÁ½¸ö²»Í¬µÄ¸ÅÄÇë²»Òª»ìÏý¡£
ʵ¼ÊÉÏGrailsµÄĬÈÏÅäÖÃÒѾ×ãÒÔÎÒÃǽøÐпª·¢£¬²¢ÇÒËüÄÚÖÃÁËÈÝÆ÷ºÍÄÚ´æÄ£Ê½µÄHSQLÊý¾Ý¿â£¬ÕâÑùÎÒÃǼ¸ºõÁ¬Êý¾Ý¿â¶¼²»ÓÃÅäÖÃÁË¡£
²»¹ý£¬ÔÚ½«À´Äã¿Ï¶¨ÊÇÏëÒªÅäÖÃÒ»¸öÕæÕýµÄÊý¾Ý¿âµÄ£¬ÏÂÃæµÄÕ½ڽ«½éÉÜÈçºÎʵÏÖ¡£
GrailsÌṩÁËÒ»¸ö
grails-app/conf/Config.groovyÅäÖÃÎļþ£¬ÓÃÀ´Íê³ÉÒ»°ãͨ³£µÄÅäÖá£Õâ¸öÎļþʹÓ÷dz£ÀàËÆÓÚJavaÊôÐÔ£¨propertiese£©Îļþ¡¢²»¹ýÊÇ´¿GroovyµÄ
ConfigSlurper £¬ÕâÑù¾Í¿ÉÒÔÖØÓã¨re-use£©±äÁ¿ÒÔ¼°Ö¸¶¨ºÏÊʵÄJavaÀàÐÍ¡£
ÀýÈ磬¿ÉÒÔÔÚÎļþÖмÓÉÏ×Ô¼º¶¨ÒåµÄÅäÖÃÐÅÏ¢¡£
ÕâÑùÔÚÓ¦ÓóÌÐòÖÐÓÐÁ½ÖÖ·½Ê½¿ÉÒÔ·ÃÎÊÕâЩÅäÖÃÐÅÏ¢¡£×î³£ÓõÄÒ»ÖÖ·½Ê½ÊÇͨ¹ý
GrailsApplication¶ÔÏó£¬ËüÔÚ¿ØÖÆÆ÷ºÍ±êÇ©¿âÖж¼¿ÉÒÔ×÷Ϊ±äÁ¿À´Ê¹Óá£
assert "world" == grailsApplication.config.foo.bar.hello
GrailsͬÑùÌṩÁËÈçÏÂÅäÖÃÑ¡Ï
grails.config.locations - ÊôÐÔ£¨properties£©ÎļþµÄλÖûòÕßGrails½«Í¬Ö÷ÅäÖúϲ¢µÄ¶îÍâÅäÖÃÎļþ¡£
grails.enable.native2ascii-Èç¹û²»ÐèÒª¶ÔGrailsµÄi18nÅäÖÃÎļþʹÓÃĬÈϵÄnative2asciiÔ¼¶¨£¬¿ÉÒÔ½«¸ÃÑ¡ÏîÉèΪfalse¡£
grails.views.default.codec - ÉèÖÃGSPȱʡµÄ×Ö·û±àÂ룬¿ÉÒÔÊÇ£º'none', 'html', »òÕß 'base64' (ȱʡΪ'none'). ΪÁ˼õÉÙXSS¹¥»÷µÄ·çÏÕ£¬½¨ÒéÉèÖóÉ'html'.
grails.views.gsp.encoding - GSPÔ´ÎļþµÄ×Ö·û±àÂ루ȱʡÊÇ'utf-8'£©
grails.war.destFile - ÉèÖÃwarÉú³ÉWARÎļþµÄλÖÃ
grails.mime.file.extensions - ÊÇ·ñʹÓÃÎļþµÄÀ©Õ¹Ãû±íʾÄÚÈÝÐÉÌÖеÄýÌåÀàÐÍ(mime type)
grails.mime.types - ÄÚÈÝÐÉÌËùÖ§³ÖµÄýÌåÀàÐÍ
grails.serverURL - Ò»¸öÖ¸Ïò·þÎñÆ÷URLµÄ¾ø¶ÔÁ¬½Ó£¬°üÀ¨·þÎñÆ÷Ãû³Æ±ÈÈçgrails.serverURL="http://my.yourportal.com". ÏêϸÇë¿´createLink.
ÈÕÖ¾»ù´¡
Grailsͨ¹ý×ÔÉíµÄÅäÖûúÖÆÀ´ÅäÖÃ
Log4j ÈÕ־ϵͳ¡£ÒªÊ¹ÓÃÈÕÖ¾¼Ç¼¹¦ÄÜ£¬ÐèÒªÐÞ¸ÄλÓÚ
grails-app/confĿ¼ÏµÄ
Config.groovyÎļþ¡£ÔÚÕâ¸öÎļþÖпÉÒÔÖ¸¶¨²»Í¬»·¾³£¬ÀýÈç
development,
testºÍ
production»·¾³ÏµÄÈÕÖ¾·½Ê½¡£Grails»á×Ô¶¯´¦Àí¸ÃÎļþ²¢ÔÚ
web-app/WEB-INF/classesĿ¼ÏÂÉú³ÉÏàÓ¦µÄ
log4j.propertiesÎļþ¡£
ÀýÈ磬ÔÚGrailsÖпÉÒÔ°´ÕÕÈçÏ·½Ê½ÅäÖÃLog4j£º
log4j {
appender.stdout = "org.apache.log4j.ConsoleAppender"
appender.'stdout.layout'="org.apache.log4j.PatternLayout"
rootLogger="error,stdout"
logger {
grails="info,stdout"
org {
grails.spring="info,stdout"
codehaus.groovy.grails.web="info,stdout"
codehaus.groovy.grails.commons="info,stdout"
…
}
}Èç¹ûÏëʹÓÃLog4jÎļþµÄ±ê×¼·ç¸ñ½øÐÐÅäÖ㬿ÉÒÔʹÓÃGroovyÖеĶàÐÐ×Ö·û´®£¬ÀýÈ磺
log4j = '''
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# ...remaining configuration
'''
ÆäËûһЩÓÐÓõÄÈÕÖ¾¼Ç¼Æ÷°üÀ¨£º
org.codehaus.groovy.grails.commons - ÓÃÀ´¼Ç¼ºËÐŤ¼þµÄÐÅÏ¢£¬ÀýÈçÀàµÄ¼ÓÔØµÈµÈ¡£
org.codehaus.groovy.grails.web - ÓÃÀ´¼Ç¼Grails webÇëÇó´¦Àí
org.codehaus.groovy.grails.web.mapping - ÓÃÀ´µ÷ÊÔURLÓ³Éä
org.codehaus.groovy.grails.plugins - ÓÃÀ´¼Ç¼²å¼þµÄ»î¶¯×´¿ö
org.springframework - ÓÃÀ´¼Ç¼SpringµÄ»î¶¯
org.hibernate - ÓÃÀ´¼Ç¼HibernateµÄ»î¶¯
ÍêÕûµÄÐÅÏ¢¸ú×Ù
µ±Òì³£·¢ÉúµÄʱºò£¬¿ÉÄÜÓÉÓÚJavaºÍGroovyÄÚ²¿µÄ´íÎó¶ø²úÉúÒ»´ó¶ÑµÄÎÞÓÃÐÅÏ¢¡£Grails¶ÔÕâЩ²»ÐèÒªµÄÐÅÏ¢½øÐÐÁ˹ýÂË£¬±£Ö¤¶Ô·ÇGrails/GroovyºËÐÄÀà°üµÄÐÅÏ¢¸ú×Ù¡£
ͨ³£ÕâЩÐÅÏ¢¶¼»áͨ¹ýStackTraceÈÕÖ¾¼Ç¼Æ÷¼Ç¼µ½stacktrace.logÎļþÖС£²»¹ýͨ¹ýÐÞ¸ÄConfig.groovy¿ÉÒԸıäÆä¼Ç¼·½Ê½£¬ÀýÈçÈç¹ûÒª½«¸ú×ÙÐÅÏ¢Ö±½ÓÊä³öµ½±ê×¼Êä³ö£¨standard out£©£¬ÐèÒª½«ÈçÏÂÅäÖÃ:
StackTrace="error,errors"
ÐÞ¸ÄΪ:
StackTrace="error,stdout"
Ò²¿ÉÒÔͨ¹ýÉèÖÃ
grails.full.stacktraceÐéÄâ»úÊôÐÔΪ
trueÀ´½ûÓöԸú×ÙÐÅÏ¢µÄ¹ýÂË£¬ÀýÈç
grails -Dgrails.full.stacktrace=true run-app
°´ÕÕ¹æÔ¼µÄÈÕÖ¾¼Ç¼
ËùÓеÄÓ¦ÓóÌÐò¹¤¼þ¶¼¶¯Ì¬µØÔö¼ÓÁË
logÊôÐÔ£¬ÆäÖаüÀ¨
ÁìÓòÄ£ÐÍ£¨Domain Class£©£¬
¿ØÖÆÆ÷ÒÔ¼°±êÇ©¿âµÈµÈ¡£Ê¹Ó÷½·¨ÈçÏÂËùʾ:
def foo = "bar"
log.debug "The value of foo is $foo"
ÔÚGrailsÖÐʹÓÃ
grails.app.<artefactType>.ClassNameµÄÃüÃû¹æÔ¼À´ÃüÃûÈÕÖ¾¼Ç¼Æ÷¡£ÀýÈç
# Set level for all application artefacts
log4j.logger.grails.app="info, stdout"# Set for a specific controller
log4j.logger.grails.app.controller.YourController="debug, stdout"# Set for a specific domain class
log4j.logger.grails.app.domain.Book="debug, stdout"# Set for a specific taglib
log4j.logger.grails.app.tagLib.FancyAjax="debug, stdout"# Set for all taglibs
log4j.logger.grails.app.tagLib="info, stdout"
ÆäÖеŤ¼þÃû£¨¼´<artefactType>£©Ò²Êǰ´ÕÕ¹æÔ¼À´ÃüÃûµÄ£¬Ò»Ð©³£¼ûµÄÈçÏÂËùʾ:
bootstrap - ÓÃÓÚÆô¶¯Ê±µÄ¼ÓÔØÀà
dataSource - ÓÃÓÚÊý¾ÝÔ´
tagLib - ÓÃÓÚ±êÇ©¿â
service - ÓÃÓÚ·þÎñÀà
controller - ÓÃÓÚ¿ØÖÆÆ÷
domain - ÓÃÓÚÁìÓòÄ£ÐÍÀà
¸÷¸ö»·¾³µÄÅäÖÃ
GrailsÖ§³ÖÕë¶Ô²»Í¬µÄ»·¾³½øÐв»Í¬µÄÅäÖã¬ÕâÑù²»¹ÜÊÇ
Config.groovyÎļþ»¹ÊÇ
grails-app/confĿ¼ÏµÄ
DataSource.groovyÎļþ£¬¶¼¿ÉÒÔ½èÖúÓÚ
ConfigSlurper À´ËæÊ±¸Ä±äËù´¦µÄ»·¾³¡£ÀýÈ磬ĬÈÏGrailsÖеÄ
DataSource¶¨ÒåÈçÏ£º
dataSource {
pooling = false
driverClassName = "org.hsqldb.jdbcDriver"
username = "sa"
password = ""
}
environments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'createeate-drop','update'
url = "jdbc:hsqldb:mem:devDB"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:mem:testDb"
}
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}×¢Ò⣬ÔÚÎļþµÄ×ʼÌṩÁËÒ»¸öͨÓõÄÅäÖã¬È»ºóÔÚ
environments´úÂë¿éÖÐÕë¶Ô²»Í¬µÄ»·¾³ÏµÄ
DataSource£¬ÅäÖÃÁ˶ÔÓ¦µÄ
dbCreateºÍ
urlÊôÐÔ¡£ÔÚ
Config.groovyÖÐÒ²¿ÉÒÔʹÓÃÕâÑùµÄÓï·¨¡£
´ò°üÒÔ¼°Çл»»·¾³
grailsµÄ
ÃüÁîÐÐÖпÉÒÔÖ¸¶¨ÔËÐÐʱµÄ»·¾³£¬ÐÎʽÈçÏ£º
grails [environment] [command name]
ÆäÖеÄenvironment²ÎÊý·Ö±ðÓÃ
dev,
prod,
testÖ¸´ú¿ª·¢»·¾³£¨development£©£¬²úÆ·»·¾³£¨production£©ÒÔ¼°²âÊÔ»·¾³£¨test£©£¬ÀýÈçÎÒÃÇÏëÔÚ²âÊÔ»·¾³Öд´½¨warÎļþ£¬¿ÉÒÔÖ´ÐÐÈçÏÂÃüÁ
Èç¹û×Ô¶¨ÒåÁËÆäËûµÄ»·¾³£¬¿ÉÒÔÔÚÃüÁîÐÐÖÐͨ¹ý
grails.env²ÎÊýÖ¸¶¨»·¾³£¬ÀýÈç:
grails -Dgrails.env=UAT run-app
ÔÚ³ÌÐòÖмì²â»·¾³
ÔÚGant½Å±¾»òÕ߯ô¶¯ÀàÖУ¬¿ÉÒÔͨ¹ý
GrailsUtilÀàÀ´ÅжÏÔËÐеĻ·¾³£¬ÀýÈ磺
import grails.util.GrailsUtil...switch(GrailsUtil.environment) {
case "development":
configureForDevelopment()
break
case "production":
configureForProduction()
break
}
ÓÉÓÚGrailsÊÇ»ùÓÚJavaÖ®Éϵģ¬ËùÒÔÐèÒª¶ÁÕßÓÐÒ»¶¨µÄ¹ØÓÚJDBCµÄ֪ʶ¡£
Ê×ÏÈ£¬Èç¹ûҪʹÓÃHSQLÖ®ÍâÆäËüµÄÊý¾Ý¿â£¬ÐèÒªÓÐÏàÓ¦µÄJDBC Driver£¨Çý¶¯£©£¬ÀýÈç¶ÔÓÚMySQLÐèÒªÓÐ
Connector/JÕâЩÊý¾Ý¿âÇý¶¯Ò»°ã¶¼ÊÇJARµÄÐÎʽ·¢²¼£¬Ö»ÐèÒª°ÑÕâЩJARÎļþ·Åµ½¹¤³ÌϵÄ
libĿ¼Ï¼´¿É¡£
ÔÚ·ÅÖÃÍêJDBCÇý¶¯ºó£¬ÎÒÃÇÐèÒªÊìϤÒÔÏÂλÓÚ
grails-app/conf/ϵÄGrailsÊý¾Ý¿âÅäÖÃÎļþ
DataSoruce.groovy¡£³õʼ״̬ϸÃÎļþ»á°üÀ¨ÈçÏÂÑ¡Ïî:
driverClassName - JDBC Çý¶¯£¨driver£©µÄÀàÃû
username - ÓÃÀ´´´½¨JDBCÁ¬½ÓµÄÓû§Ãû
password - ÓÃÀ´´´½¨JDBCÁ¬½ÓµÄÃÜÂë
url - Êý¾Ý¿âµÄ JDBC URL
dbCreate - ÊÇ·ñ¸ù¾ÝÓòÄ£ÐÍÀà×Ô¶¯´´½¨Êý¾Ý¿â
pooling - ÊÇ·ñʹÓÃÊý¾ÝÁ¬½Ó³Ø(ĬÈÏÉèÖÃΪtrue)
logSql - Æô¶¯sqlÈÕÖ¾¼Ç¼
Ò»¸öµäÐ͵ÄMySQLµÄÅäÖÃÈçÏ£º
dataSource {
pooling = true
dbCreate = "update"
url = "jdbc:mysql://localhost/yourDB"
driverClassName = "com.mysql.jdbc.Driver"
username = "yourUser"
password = "yourPassword"
}
֮ǰµÄʾÀýǰÌáÊǼÙÉèÎÒÃÇÔÚdevelopment,productionºÍtestµÈ»·¾³ÏµÄÅäÖÃÒ»Ñù¡£
²»¹ýGrailsÖеÄÊý¾ÝÔ´ÊÇ¿ÉÒÔ¸ù¾Ý²»Í¬»·¾³À´½øÐв»Í¬µÄÅäÖã¬ÀýÈ磺
dataSource {
// common settings here
}
environments {
production {
dataSource {
url = "jdbc:mysql://liveip.com/liveDb"
}
}
}
ÓÉÓÚJ2EEÈÝÆ÷Ò»°ã¶¼Ö§³Ö¸ù¾Ý
Java Naming and Directory Interface (JNDI)À´²éÕÒÊý¾ÝÔ´¡£
ËùÒÔGrailsÒ²ÌṩÁ˸ù¾ÝJNDIÀ´ÅäÖÃÊý¾ÝÔ´µÄ·½Ê½,ʾÀýÈçÏ£º
dataSource {
jndiName = "java:comp/env/myDataSource"
}
ËäÈ»J2EEÈÝÆ÷¼ä¶¨ÒåJNDIÃû³Æ¸ñʽ²î±ðºÜ´ó£¬µ«ÊÇÄ㶨Òå
DataSourceµÄ·½Ê½ÒÀ¾ÉÊÇÏàͬµÄ¡£
DataSource.groovyÎļþÖеÄ
dbCreateÊôÐÔÊ®·ÖÖØÒª£¬ÒòΪËü¿ÉÒÔÓÃÀ´Ö¸¶¨ÊÇ·ñ×Ô¶¯¸ù¾Ý
GORMÀàÀ´´´½¨Êý¾Ý¿â±í¡£Æä¿ÉѡֵΪ£º
create-drop - µ±GrailsÔËÐÐʱɾ³ý²¢ÖØÐ½¨Á¢Êý¾Ý¿â
create - Èç¹ûÊý¾Ý¿â²»´æÔÚÔò´´½¨Êý¾Ý¿â£¬´æÔÚÔò²»×÷ÈκÎÐÞ¸Ä
update - Èç¹ûÊý¾Ý¿â²»´æÔÚÔò´´½¨Êý¾Ý¿â£¬´æÔÚÔò½øÐÐÐÞ¸Ä
¿ª·¢»·¾³£¨development£©ÏÂ
dbCreateÊôÐÔĬÈÏÉèÖÃΪcreate-drop:
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
}ÕâÑùÔÚGrailsÓ¦ÓóÌÐòÆô¶¯µÄʱºò»áɾ³ýµôÔÀ´µÄÊý¾Ý¿â²¢ÖØÐ½¨Á¢£¬ÔÚproduction»·¾³ÖÐͨ³£ÐèÒªÐ޸ĸÃÖµ¡£
ËäÈ»GrailsÔÝʱ²»Ö§³ÖRails·½Ê½µÄÒÆÖ²£¬²»¹ý¿ÉÒÔͨ¹ý°²×°LiquiBaseºÍDbMigrateÁ½¸ö²å¼þÀ´ÊµÏÖ£¬ÔÚ¿ØÖÆÌ¨ÖпÉÒÔͨ¹ýgrails list-pluginsÃüÁîÀ´²é¿´ÕâÁ½¸ö²å¼þ¡£
¶ÔÓÚ´ó¶àÊýÇé¿öÀ´Ëµ£¬Ê¹ÓÃλÓÚ
grails-app/confĿ¼ÏµÄ
DataSource.groovyÎļþÖеÄĬÈÏÅäÖÃÒѾ¹»ÓÃÁË¡£²»¹ýÓÐЩÇé¿öÏÂÐèÒªÔÚ¹¤³ÌÏîÄ¿ÒÔÍâÀ´±£´æÕâЩÅäÖá£ÀýÈçÔÚ´ò°üWARʱ£¬ÓÐʱºòÐèÒª½«ÅäÖÃÎļþ·ÅÖÃÓÚ¹¤³ÌÖ®ÍâÀ´±ÜÃâÓÉÓÚÅäÖõÄÐ޸ĵ¼ÖÂWAR°üµÄÖØÐ´ò°ü¡£
ΪÁËÖ§³ÖÕâÖÖÍⲿÅäÖã¬ÐèÒªÔÚ
Config.groovyÎļþÖÐÊ×ÏÈÖ¸¶¨
grails.config.locationsÑ¡ÏÒÔ±ã¸æËßGrailsÓ¦¸Ãµ½ºÎ´¦È¥¼ÓÔØÍⲿÅäÖÃÎļþ¡£
grails.config.locations = [ "classpath:${appName}-config.properties",
"classpath:${appName}-config.groovy",
"file:${userHome}/.grails/${appName}-config.properties",
"file:${userHome}/.grails/${appName}-config.groovy"]ÔÚÉÏÀýÖУ¬ÎÒÃǼÓÔØÁ˲»Í¬classpathÏÂÒÔ¼°USER_HOMEϵÄÅäÖÃÎļþ£¬°üÀ¨JavaÊôÐÔÎļþºÍ
ConfigSlurper ÅäÖÃÎļþ¡£
×îÖÕ¿ÉÒÔͨ¹ý
GrailsApplication¶ÔÏóµÄ
configÊôÐÔÀ´»ñµÃÕâЩÅäÖÃÎļþÖеÄÖµ¡£
Grails»¹Ö§³ÖSpring ÖеÄÊôÐÔռ루property place holders£©ºÍÊôÐÔÖØÔØ£¨property override£©ÅäÖ㬹ØÓÚÕâЩ·½ÃæµÄÏêϸÄÚÈÝÇë²Î¿¼GrailsºÍSpringÕ½ڡ£
°æ±¾¶¨Òå»ù´¡
GrailsÄÚÖÃÖ§³ÖÓ¦ÓóÌÐòµÄ°æ±¾¶¨Òå¡£µ±Ê¹ÓÃ
create-app´´½¨Ò»¸öÓ¦ÓóÌÐòµÄʱºò£¬¸ÃÓ¦ÓóÌÐòµÄ°æ±¾¼´±»ÉèÖÃΪ
0.1¡£°æ±¾ÊÇ´æ´¢ÔÚÏîÄ¿ÎļþµÄ¸ùĿ¼ÏµÄ
application.propertiesÔªÎļþÖС£
Òª¸Ä±äÓ¦ÓóÌÐòµÄ°æ±¾¿ÉÒÔʹÓÃ
set-versionÃüÁÀýÈ磻
GrialsÔںܶàµÄÃüÁîÖж¼»áʹÓõ½°æ±¾£¬ÀýÈç
warÃüÁî¾Í»áÔÚÉú³ÉµÄWARÎļþ×îºó¼ÓÉÏÓ¦ÓóÌÐòµÄ°æ±¾¡£
ÔËÐÐʱÅжϰ汾
ÓÉÓÚGrailsÖ§³ÖÓ¦ÓóÌÐòÔªÊý¾Ý£¨metadata£©£¬ËùÒÔ¿ÉÒÔͨ¹ý
GrailsApplicationÀàÀ´µÃµ½µ±Ç°µÄ°æ±¾ÐÅÏ¢¡£ÀýÈçÔÚ¿ØÖÆÆäÖпÉÒÔʹÓÃÄÚÖõÄ
grailsApplication±äÁ¿¡£
def version = grailsApplication.metadata['app.version']
Èç¹ûÏë²é¿´GrailsµÄ°æ±¾£¬¿ÉÒÔÓÐÁ½ÖÖ·½Ê½£º
def grailsVersion = grailsApplication.metadata['app.grails.version']
»òÕß
GrailsUtilÀࣺ
import grails.util.*
def grailsVersion = GrailsUtil.grailsVersion
GrailsµÄÃüÁîÐÐÊÇ»ùÓÚ
Gant--ÓÃGroovy¶Ô
Apache Ant½øÐеļòµ¥·â×°Ö®Éϵġ£
²»¹ýGrailsͨ¹ýʹÓùæÔ¼ÒÔ¼°grailsÃüÁî½øÒ»²½¶ÔÆä½øÐÐÁËÀ©Õ¹¡£µ±ÊäÈë:
ʱ£¬Grails»áÔÚÒÔÏÂĿ¼ÖÐËÑË÷ÏàÓ¦µÄGant½Å±¾²¢Ö´ÐУº
USER_HOME/.grails/scripts
PROJECT_HOME/scripts
PROJECT_HOME/plugins/*/scripts
GRAILS_HOME/scripts
Grails»á×Ô¶¯½«ÃüÁîÃû³Æ´ÓСдÐÎʽת»»³ÉÍÕ·åÐÎʽ£¨camel case£©À´²éÕÒÏàÓ¦½Å±¾Îļþ£¬ÀýÈçÈç¹ûÊäÈë:
ÄÇôGrails»áÈ¥ËÑË÷ÒÔϽű¾Îļþ£º
USER_HOME/.grails/scripts/RunApp.groovy
PROJECT_HOME/scripts/RunApp.groovy
PROJECT_HOME/plugins/*/scripts/RunApp.groovy
GRAILS_HOME/scripts/RunApp.groovy
Èç¹ûÓжà¸öÆ¥ÅäÎļþ£¬Grails»áÈÃÄãÑ¡ÔñÆäÖеÄÒ»¸öÀ´Ö´ÐС£µ±Gant½Å±¾Ö´ÐеÄʱºò£¬¡°default¡±Ä¿±ê£¨Target£©Ò²»áһִͬÐС£
ÒªÏë»ñµÃÓÐЧÃüÁîµÄÇåµ¥£¬¿ÉÒÔÊäÈë:
ÕâÑù»áÁгöGrailsÖпÉÒÔʹÓÃÃüÁîÇåµ¥£¬È磺
Usage (optionals marked with *):
grails [environment]* [target] [arguments]*Examples:
grails dev run-app
grails create-app booksAvailable Targets (type grails help 'target-name' for more info):
grails bootstrap
grails bug-report
grails clean
grails compile
...
¹ØÓÚµ¥¸öÃüÁîµÄ¸ü¶àÏêϸÐÅÏ¢Çë²Î¿¼×ó±ß²Ëµ¥µÄÃüÁîÐÐÖ¸ÄÏ¡£
ͨ¹ýÔÚÏîÄ¿µÄ¸ùĿ¼ÏÂÔËÐÐ
create-scriptÃüÁî¿ÉÒÔ´´½¨Gant½Å±¾¡£ÀýÈ磺
grails create-script compile-sources
ÕâÌõÃüÁî»áÔÚ
scriptsĿ¼Ï´´½¨Ò»¸öÃûΪ
CompileSources.groovyµÄ½Å±¾Îļþ¡£Gant½Å±¾±¾ÉíÀàËÆÓÚGroovy´úÂ룬µ«ÊÇËü¿ÉÒÔÖ§³ÖÄ¿±ê£¨Target£©ÒÔ¼°ËüÃÇÖ®¼äµÄÒÀÀµ¹ØÏµ¡£
target(default:"The default target is the one that gets executed by Grails") {
depends(clean, compile)
}
target(clean:"Clean out things") {
Ant.delete(dir:"output")
}
target(compile:"Compile some sources") {
Ant.mkdir(dir:"mkdir")
Ant.javac(srcdir:"src/java", destdir:"output")
}´ÓÈçÉϽű¾ÖпÉÒÔ¿´³ö£¬ÆäÖÐÓÐÒ»¸öĬÈÏ¿ÉÒÔ·ÃÎÊ
Apache Ant APIµÄ
Ant±äÁ¿¡£
ÈçÉÏ
defaultÄ¿±êÖÐËùʹÓõÄÒ»Ñù£¬ÄãÒ²¿ÉÒÔʹÓÃ
depends·½·¨À´Ö¸¶¨ÆäÒÀÀµµÄÆäËûÄ¿±ê¡£
GrailsµÄÃüÁîÐÐÖл¹¿ÉÒÔÖØÓÃÐí¶àÓÐÓõĽű¾´úÂë(²é¿´ËùÓÐÃüÁîµÄÈëÃÅÖ¸ÄÏÇë²Î¿¼ÃüÁîÐÐÖ¸ÄÏ)£¬ÆäÖÐ×îÖ÷ÒªµÄÓÐ
compile,
packageºÍ
bootstrap½Å±¾¡£
ÒÔ
bootstrap½Å±¾ÎªÀý£¬ÒÔÏ´úÂë¿ÉÒÔÔÚÆô¶¯Ê±µ÷ÓÃSpringÖеÄ
ApplicationContextʵÀýÀ´·ÃÎÊÊý¾ÝÔ´£º
Ant.property(environment:"env")
grailsHome = Ant.antProject.properties."env.GRAILS_HOME"includeTargets << new File ( "${grailsHome}/scripts/Bootstrap.groovy" )
target ('default': "Load the Grails interactive shell") {
depends( configureProxy, packageApp, classpath, loadApp, configureApp ) Connection c
try {
// do something with connection
c = appCtx.getBean('dataSource').getConnection()
}
finally {
c?.close()
}
}
GrailsÌṩÁ˵÷Óýű¾Ê¼þµÄÄÜÁ¦£¬ÕâЩʼþÊÇÔÚGrailsÄ¿±ê£¨target£©ºÍ²å¼þ½Å±¾Ö´ÐÐʱËù´¥·¢µÄ¡£
´Ë»úÖÆ×ÚÖ¼ÊǼòµ¥ºÍ×ÔÓÉ£¬Òò´ËÎÞ·¨µÃµ½ËùÓпÉÄÜ´¥·¢Ê¼þµÄÁÐ±í¡£ÕâÑùµ±Ã»ÓкËÐÄÄ¿±ê½Å±¾´¥·¢Ê¼þµÄʱºò£¬¾ÍÓпÉÄܵ÷Óòå¼þ½Å±¾Ëù´¥·¢µÄʼþ¡£
¶¨Òåʼþ¾ä±ú
ʼþ¾ä±úÊÇÔÚ
scripts/Ŀ¼Ï£¨²å¼þ½Å±¾£©»òÕß
USER_HOMEĿ¼ÏµÄ
.grails/scripts/Ŀ¼ÏµÄ
Events.groovy½Å±¾Öж¨ÒåµÄ¡£µ±Ò»¸öʼþ´¥·¢µÄʱºò»áµ÷ÓÃËùÓеÄʼþ½Å±¾£¬ËùÒÔ¿ÉÒÔʹÓÃ10¸ö²å¼þ½Å±¾»òÕßʹÓÃÒ»¸öÓû§×Ô¶¨Òå½Å±¾À´´¦Àíʼþ¡£
ÔÚ
Events.groovyÖÐÊÇͨ¹ýÒÔ¡°event¡±¿ªÍ·ÃüÃûµÄ´úÂë¿éÀ´¶¨ÒåʼþµÄ¡£ÈçÏÂÀýËùʾ£¬Ç뽫ÏÂÀý·ÅÈë/scriptsĿ¼¡£
eventCreatedArtefact = { type, name ->
println "Created $type $name"
}eventStatusUpdate = { msg ->
println msg
}eventStatusFinal = { msg ->
println msg
}¿ÉÒÔ¿´µ½ÆäÖж¨ÒåÁËÈý¸ö¾ä±ú
eventCreatedArtefact,
eventStatusUpdateºÍ
eventStatusFinal¡£GrailsÒ²ÌṩÆäËûһЩ±ê×¼µÄʼþ£¬¿ÉÒÔÔÚÃüÁîÐвο¼Ö¸ÄÏÖÐÕÒµ½¡£ÀýÈ磬
compileÃüÁî»á´¥·¢ÈçÏÂʼþ¡£
CompileStart - µ±±àÒ뿪ʼʱ´¥·¢£¬Ö¸¶¨±àÒëµÄÀàÐÍ??Ô´Îļþ»òÕß²âÊÔ
CompileEnd - µ±±àÒë½áÊøÊ±´¥·¢£¬Ö¸¶¨±àÒëµÄÀàÐÍ??Ô´Îļþ»òÕß²âÊÔ
´¥·¢Ê¼þ
ÈçÏÂÀýËùʾ£¬Òª´¥·¢Init.groovy½Å±¾µÄʼþÖ»ÐèÒýÈëËü²¢ÇÒµ÷ÓÃevent()±Õ°ü¡£
Ant.property(environment:"env")
grailsHome = Ant.antProject.properties."env.GRAILS_HOME"
includeTargets << new File ( "${grailsHome}/scripts/Init.groovy" )
event("StatusFinal", ["Super duper plugin action complete!"])³£ÓÃʼþ
ϱíÁгöÁËһЩ³£ÓõÄʼþ£º
| ʼþ | ²ÎÊý | ÃèÊö |
|---|
| StatusUpdate | message | ´«ÈëµÄ×Ö·û´®±íÃ÷µ±Ç°½Å±¾µÄ״̬/½ø¶È |
| StatusError | message | ´«ÈëµÄ×Ö·û´®±íÃ÷µ±Ç°½Å±¾µÄ´íÎóÐÅÏ¢ |
| StatusFinal | message | ´«ÈëµÄ×Ö·û´®±íÃ÷×îºó½Å±¾µÄ״̬ÐÅÏ¢£¬±ÈÈçµ±Ò»¸öÄ¿±ê/ÈÎÎñ£¨target£©Íê³Éʱ£¬¼´±ãÊǽű¾»·¾³Öв¢²¢´æÔÚÄ¿±ê£¬ÕÕÑù¿ÉÒÔÏÔʾ״̬ÐÅÏ¢ |
| CreatedArtefact | artefactType,artefactName | ÔÚÒ»¸öcreate-xxxx½Å±¾Íê³É²¢ÇÒ´´½¨ÁËÒ»¸ö¹¤¼þµÄʱºòµ÷Óà |
| CreatedFile | fileName | ÔÚÒ»¸ö¹¤³ÌµÄÔ´Îļþ±»´´½¨µÄʱºòµ÷Ó㬵«²»°üÀ¨±»Grails¹ÜÀíµÄÄÇЩ³£Á¿Îļþ |
| Exiting | returnCode | Ôڽű¾»·¾³¼´½«ÍêÈ«ÖÕÖ¹µÄʱºò±»µ÷Óà |
| PluginInstalled | pluginName | ÔÚÒ»¸ö²å¼þ±»°²×°ÒÔºó±»µ÷Óà |
| CompileStart | kind | ÔÚ±àÒ뿪ʼµÄʱºòµ÷Ó㬴«ÈëµÄ²ÎÊýÊDZàÒëµÄÔ´Îļþ»òÕß²âÊÔÎļþµÄÖÖÀà |
| CompileEnd | kind | ÔÚ±àÒë½áÊøµÄʱºòµ÷Ó㬴«ÈëµÄ²ÎÊýÊDZàÒëµÄÔ´Îļþ»òÕß²âÊÔÎļþµÄÖÖÀà |
| DocStart | kind | ÔÚÉú³ÉÎĵµ¼´½«¿ªÊ¼µÄʱºòµ÷ÓðüÀ¨javadoc»òÕßgroovydoc |
| DocEnd | kind | ÔÚÉú³ÉÎĵµ½áÊøµÄʱºòµ÷ÓðüÀ¨javadoc»òÕßgroovydoc |
| SetClasspath | rootLoader | ÔÚclasspath³õʼ»¯Æä¼äµ÷Óã¬ÕâÑù²å¼þ¾Í¿ÉÒÔʹÓÃrootLoader.addURL(...)À´ÉèÖÃclasspath²ÎÊý¡£×¢Ò⣡´ËÉèÖÃclasspath²ÎÊýÊÇÔÚʼþ½Å±¾¼ÓÔØÖ®ºó£¬Òò´ËÄã²»ÄÜÓôËclasspathÀ´¼ÓÔØËùÐèµÄÀ࣬¼´±ãÊÇÄãÔÚʼþ½Å±¾ÖÐÒѾµ¼È룬µ«ÊÇÈç¹ûÄãÊÇͨ¹ýÃû×ÖÀ´¼ÓÔØÀ࣬ÄÇÊÇ¿ÉÒԵġ£ |
| PackagingEnd | none | ÔÚ´ò°üÍêÍê±ÏµÄʱºòµ÷Óã¨ÔÚJetty·þÎñÆ÷Æô¶¯Ö®Ç°£¬µ«ÔÚweb.xmlÉú³ÉÖ®ºó£© at the end of packaging (which is called prior to the Jetty server being started and after web.xml is generated) |
| ConfigureJetty | Jetty Server object | ÔÚJetty web·þÎñÆ÷ÅäÖóõʼ»¯Ö®ºóµ÷Óà |
Ant¼¯³É
µ±Í¨¹ýcreate-appÃüÁî´´½¨ÁËÒ»¸öGrailsÓ¦ÓÃʱ£¬Grails»á×Ô¶¯´´½¨Ò»¸ö
Apache Ant µÄ
build.xmlÎļþ£¬ÆäÖаüÀ¨ÒÔÏÂÄ¿±ê£º
clean - Çå³ýGrailsÓ¦ÓÃ
war - ´´½¨WARÎļþ
test - ÔËÐе¥Ôª²âÊÔ
deploy - ȱʡÊǿգ¬µ«ÊÇ¿ÉÒÔ±»ÓÃÀ´ÊµÏÖ×Ô¶¯·¢²¼¡£
Õ⼸¸öÄ¿±ê¶¼¿ÉÒÔͨ¹ýAntÀ´ÔËÐУ¬Èç:
Õâ¸ö
build.xmlÎļþ¿ÉÒÔµ÷ÓÃGrailsÖеÄÃüÁÕâÑù¾Í¿ÉÒÔ½«GrailsÓ¦ÓÃÓë³ÖÐø¼¯³É·þÎñÆ÷£¬Èç
CruiseControl ºÍ
Hudson ¼¯³ÉÆðÀ´¡£
Maven ¼¯³É
GrailsÔÝʱ²»Ö§³Ö
Maven £¬µ«ÊÇÒѾÓÐÁËÒ»¸öÃûΪ
Maven Tools for Grails µÄÏîÄ¿£¬Ëü¿ÉÒÔ¶Ôµ±Ç°µÄGrailsÓ¦Óô´½¨Ò»¸öPOM£¬ÕâÑù¾Í¿ÉÒÔ½«Grails¼¯³Éµ½Maven µÄÉúÃüÖÜÆÚÖС£
Òª»ñµÃ¸ü¶àÐÅÏ¢Çë·ÃÎÊ
Maven Tools for Grails ÏîÄ¿ÍøÕ¾
ÁìÓòÀàÊÇÈκÎÉÌÒµÓ¦ÓõĺËÐÄ£¬ËüÃDZ£´æÕâÕâЩÉÌÒµ¹ý³ÌµÄ״̬²¢ÇÒʵÏÖÏàÓ¦µÄÐÐΪ£¬ËüÃÇ»¹Í¨¹ýÒ»¶ÔÒ»»òÕßÒ»¶Ô¶àµÄ¹ØÏµÏ໥ÁªÏµÔÚÒ»Æð¡£
GORMÊÇGrailsµÄ¶ÔÏó¹ØÏµÓ³É䣨ORM£©µÄʵÏÖ£¬Êµ¼ÊÉÏËüʹÓõÄÊÇHibernate3£¨·Ç³£Á÷ÐкÍÁé»îµÄ¿ªÔ´ORM½â¾ö·½°¸£©£¬µ«ÒòΪÓÐGroovyµÄ¶¯Ì¬ÌØÐÔÖ§³Ö£¬Òò´ËGORM¼ÈÖ§³Ö¶¯Ì¬ÀàÐÍÒ²Ö§³Ö¾²Ì¬ÀàÐÍ£¬ÔÙ¼ÓÉÏGrailsµÄ¹æÔ¼£¬ÏÖÔÚ´´½¨GrailsµÄÁìÓòÀàÖ»ÐèÒª¸üÉÙµÄÅäÖþͿÉÒÔÁË¡£
ÄãÒ²¿ÉÒÔÓÃJavaÀàдGrailsµÄÁìÓòÀà¡£¼¯³ÉHibernateµÄÏà¹ØÕ½ڽéÉÜÁËÈçºÎʹÓÃJavaÀ´Ð´GrailsÁìÓòÀ࣬µ«ÓÖ²»Ê§¶¯Ì¬³Ö¾Ã·½·¨µÄÓÅÊÆ¡£ÒÔÏÂÊÇGORMʵ¼ùµÄÔ¤ÀÀ£º
def book = Book.findByTitle("Groovy in Action")book
.addToAuthors(name:"Dierk Koenig")
.addToAuthors(name:"Guillaume LaForge")
.save()ÓÃ
create-domain-class ÃüÁî´´½¨Ò»¸ödomainÀà:
grails create-domain-class Person
Õ⽫ÔÚ
grails-app/domain/Person.groovy Öд´½¨ÏÂÃæµÄÀࣺ
Èç¹ûÄãÔÚÊý¾ÝÔ´Öн« dbCreate ÊôÐÔÉèÖÃΪ"update", "create" »ò "create-drop"£¬Grails»á×Ô¶¯Éú³É»òÐÞ¸ÄÊý¾Ý¿âÖÐµÄ±í¡£
Äã¿ÉÒÔͨ¹ýÌí¼ÓÊôÐÔÀ´×Ô¶¨ÒåÀࣺ
class Person {
String name
Integer age
Date lastVisit
}Ò»µ©ÄãÓÐÁËÒ»¸ödomainÀ࣬Äã¿ÉÒÔͨ¹ý
shell»ò
console ÖвÙ×ÝËü£º
Õ⽫»áΪÄãÔØÈëÒ»¸ö¿ÉÒÔÊäÈëGroovyÃüÁîµÄ½»»¥Ê½Í¼ÐνçÃæ¡£
³¢ÊÔÖ´ÐÐһЩ»ù±¾µÄCRUD (Create/Read/Update/Delete)²Ù×÷¡£
´´½¨
ÓÃGroovyµÄnew ²Ù×÷·û´´½¨Ò»¸ödomainÀàµÄʵÀý£¬ÉèÖÃËüµÄÊôÐÔ,È»ºóµ÷ÓÃ
save:
def p = new Person(name:"Fred", age:40, lastVisit:new Date())
p.save()
save ·½·¨½«»áʹÓõײãµÄHibernate ORM½«ÄãµÄʵÀý³Ö¾Ã»¯µ½Êý¾Ý¿â¡£
¶ÁÈ¡
Grails×Ô¶¯ÔÚÄãµÄdomainÀàÖÐÌí¼ÓÁËÒ»¸öÒþº¬µÄ
idÊôÐÔ£¬Äã¿ÉÒÔÓÃËüÀ´È¡»Ø¶ÔÏó£º
def p = Person.get(1)
assert 1 == p.id
ÕâÀïʹÓÃ
get·½·¨£¬Ëü»á¸ù¾ÝÊý¾Ý¿â±êʶ·û´ÓÊý¾Ý¿âÖÐÈ¡»ØÒ»¸ö
Person¶ÔÏó¡£
¸üÐÂ
Òª¸üÐÂÒ»¸öʵÀý£¬Ö»ÒªÉèÖÃÒ»ÏÂÊôÐÔ£¬È»ºóÒ²ÊǼòµ¥µÄµ÷ÓÃÒ»ÏÂ
save£º
def p = Person.get(1)
p.name = "Bob"
p.save()
ɾ³ý
ʹÓÃ
deleteÀ´É¾³ýÒ»¸öʵÀý:
def p = Person.get(1)
p.delete()
µ±¹¹½¨Ò»¸öGrialsÓ¦ÓõÄʱºò£¬Äã±ØÐëÊÂÏÈ¿¼ÂÇÐèÒª½â¾öµÄÎÊÌâÓò£¨problem domain£©¡£±ÈÈ磬Èç¹ûÄãÒª¹¹½¨Ò»¸ö
Amazon Êéµê£¬Äã¾ÍÒª¿¼ÂÇÊ飬×÷Õߣ¬¹Ë¿ÍºÍ³ö°æÉ̵ȵȡ£
ÕâЩÔÚGORMÖÐÊÇ×÷ΪGroovyÀàÀ´½¨Ä£µÄ£¬Òò´Ë
BookÀàÒªÓÐtitle,release date,ISBN numberµÈÊôÐÔ¡£ÔÚÏÂÃæµÄ¼¸½Ú½«ÑÝʾÔÚGORMÖÐÈçºÎΪÁìÓò½¨Ä£¡£
Òª´´½¨Ò»¸öÁìÓòÀ࣬ÔËÐÐ
create-domain-class:
grails create-domain-class Book
Éú³ÉÁË
grails-app/domain/Book.groovy:
Èç¹ûÄãÏëʹÓðü£¬Äã¿ÉÒÔ°ÑBook.groovyÀàÒÆÈëdomainĿ¼ÏµÄÒ»¸ö×ÓĿ¼£¬²¢¸ù¾ÝGroovy(Ò²ÊÇJava)µÄ°ü¹æÔòÌí¼ÓÒ»¸öºÏÊʵÄpackageÉùÃ÷¡£
ÉÏÃæµÄÀཫ»áÔÚÊý¾Ý¿âÖÐ×Ô¶¯Ó³ÉäÒ»¸ö
book (¸úÀàͬÃû)µÄ±í¡£Ó³É乿Ôò¿ÉÒÔͨ¹ý
ORMµÄDSLÀ´×Ô¶¨Òå¡£
ÏÖÔÚ£¬ÄãÓÐÁËÒ»¸öÁìÓòÀ࣬Äã¿ÉÒÔ°ÑËüµÄÊôÐÔ¶¨ÒåΪJavaÓïÑÔµÄÀàÐÍ.±ÈÈç:
class Book {
String title
Date releaseDate
String ISBN
}
ÿ¸öÊôÐÔÓ³Éäµ½Êý¾Ý¿âÖеÄÒ»¸öÁУ¬ÁÐÃûµÄ¹æÔòÃüÃû¹æÔòÊÇÈ«²¿Ð¡Ð´²¢ÓÃÏ»®Ïß·Ö¸ô¡£±ÈÈç
releaseDateÓ³ÉäΪÁÐ
release_dateÉÏ¡£SQLÀàÐÍÊǸù¾ÝJavaÀàÐÍÀ´×Ô¶¯¼ì²âµÄ£¬ÄãÒ²¿ÉÒÔÓÃ
Ô¼Êø »òÕß
ORM DSL×Ô¶¨ÒåÓ³ÉäÀàÐÍ¡£
¹ØÁª¶¨ÒåÁËdomainÀàÖ®¼äÈçºÎ»¥Ïཻ»¥¡£³ý·ÇÔÚÁ½¶Ë¶¼ÏÔʽµÄÖ¸¶¨£¬·ñÔòÒ»¸ö¹ØÁªÖ»´æÔÚÓÚ¶¨ÒåËüµÄÄǶˡ£
Ò»¶ÔÒ»µÄ¹ØÁªÊÇ×î¼òµ¥µÄ¹ØÁª¡£ËüÖ»Òª¶¨ÒåÒ»¸öÊôÐÔµÄÀàÐÍΪÁíÒ»¸ödomainÀà¾Í¿ÉÒÔÁË¡£¿´ÏÂÃæµÄÀý×Ó:
ʾÀý A
class Face {
Nose nose
}
class Nose {
}ÕâÑùÎÒÃǾÍÓÐÁËÒ»¸ö´Ó
Face µ½
NoseµÄµ¥Ïò¹ØÁª¡£Òª°ÑÕâ¸ö¹ØÁª±äΪ˫ÏòµÄ£¬Ö»ÒªÔÚÁíÒ»¶Ë¶¨ÒåÒ»ÏÂ:
ʾÀý B
class Face {
Nose nose
}
class Nose {
Face face
}ÕâÑù¾ÍÊÇË«Ïò¹ØÁªÁË¡£µ«ÊÇ£¬ÕâÖÖÇé¿öÏ£¬¹ØÁªµÄË«·½²¢²»Äܼ¶Áª¸üС£
¿´ÏÂÃæµÄ±ä»¯:
ʾÀý C
class Face {
Nose nose
}
class Nose {
static belongsTo = [face:Face]
}ÔÚÕâÀÎÒÃÇʹÓÃ
belongsTo ±íʾ
Nose "ÊôÓÚ" Face¡£Æä½á¹û¾ÍÊÇÎÒÃÇ´´½¨²¢±£´æËüʱ£¬Êý¾Ý¿â¿ÉÒÔ_¼¶Áª_¸üÐÂ/²åÈë
Nose:
new Face(nose:new Nose()).save()
ÉÏÃæÕâ¸öÀý×ӻὫfaceºÍnose¶¼±£´æ¡£×¢Òâ·´ÏòµÄ²Ù×÷²¢²»¿ÉÐУ¬Ëü»áµ¼ÖÂÒ»¸ö¶ÔÓÚÁÙʱ
Face¶ÔÏóµÄ´íÎó:
new Nose(face:new Face()).save() // will cause an error
belongsTo µÄÁíÒ»¸öÖØÒª×÷ÓÃÊÇ£¬Èç¹ûÄãɾ³ýÁËÒ»¸ö
Face ʵÀý£¬ÄÇôÏà¹ØµÄ
NoseÒ²»á±»É¾³ý:
def f = Face.get(1)
f.delete() // both Face and Nose deleted
ûÓÐ
belongsTo µÄ»°£¬½«²»»á¼¶ÁªÉ¾³ý£¬Äã»áµÃµ½Ò»¸öÍâ¼üÔ¼ÊøµÄ´íÎ󣬳ý·ÇÄãÊÖ¹¤È¥É¾³ýNose:
// error here without belongsTo
def f = Face.get(1)
f.delete()// no error as we explicitly delete both
def f = Face.get(1)
f.nose.delete()
f.delete()
Äã¿ÉÒÔ±£³ÖÇ°ÃæÄÇÖÖµ¥Ïò¹ØÁªµÄ¹ØÏµ£¬²¢ÔÊÐí¼¶Áª±£´æ/¸üÐÂ:
class Face {
Nose nose
}
class Nose {
static belongsTo = Face
}×¢Ò⣬ÔÚÕâÖÖÇé¿öÏ£¬ÒòΪÎÒÃÇûÓÐÔÚ
belongsToÉùÃ÷ÖÐʹÓÃÓ³ÉäÓï·¨Ã÷È·µØÉùÃ÷Õâ¸ö¹ØÁª,Grails½«ÈÏΪËüÊÇÒ»¸öµ¥Ïò¹ØÁª¡£ÏÂÃæÊǶÔÕâÈý¸öÀý×ÓµÄ×ܽá:
Ò»¶Ô¶àµÄ¹ØÏµÊÇÖ¸£¬µ±Ò»¸öÀà(±ÈÈç
Author)ÓµÓÐÁíÒ»¸öÀà(
Book)µÄ¶à¸öʵÀýÕâÖÖÇé¿ö¡£ÔÚGrailsÖУ¬Äã¿ÉÒÔʹÓÃ
hasMany À´¶¨ÒåÕâÖÖ¹ØÁª£º
class Author {
static hasMany = [ books : Book ] String name
}
class Book {
String title
}ÕâÑùÎÒÃÇÓÐÁËÒ»¸öÒ»¶Ô¶àµÄµ¥Ïò¹ØÁª¡£GrailsÔÚÊý¾Ý¿â¼¶±ð½«Ä¬ÈÏʹÓÃÍâ¼üÓ³ÉäÀ´Ó³ÉäÕâÖÖ¹ØÁª¡£
ORM DSL ÔÊÐíʹÓÃÁ¬½Ó±í×÷Ϊ´úÌæÀ´Ó³Éäµ¥Ïò¹ØÁª¡£
Grails ½«»á¸ù¾Ý
hasMany ÉèÖÃΪdomainÀà×Ô¶¯×¢ÈëÒ»¸öÀàÐÍΪjava.util.SetµÄÊôÐÔ¡£Õâ¸ö¿ÉÒÔ±»ÓÃÀ´±éÀú¼¯ºÏ:
def a = Author.get(1)a.books.each {
println it.title
}
GrailsʹÓõÄĬÈÏץȡ²ßÂÔÊÇ"lazy",ÕâÒâζÕ⼯ºÏ½«»á±»ÑÓ³Ù³õʼ»¯¡£Èç¹ûÄ㲻СÐĵϰ,Õâ¿ÉÄܵ¼Ö n+1 ÎÊÌâ .Èç¹ûÄãÐèÒª"eager"ץȡ£¬Äã¿ÉÒÔʹÓÃORM DSL »òÕßÖ¸¶¨Á¢¼´×¥È¡×÷Ϊ²éѯµÄÒ»²¿·Ö¡£
ĬÈϵļ¶ÁªÐÐΪÊǼ¶Áª±£´æºÍ¸üУ¬µ«²»¼¶ÁªÉ¾³ý£¬³ý·ÇÄãÒ²Ö¸¶¨ÁË
belongsTo £º
class Author {
static hasMany = [ books : Book ] String name
}
class Book {
static belongsTo = [author:Author]
String title
}Èç¹ûÄãÓÐÁ½¸öÏàͬÀàÐ͵ÄÊôÐÔ£¬ËûÃǶ¼ÊÇÒ»¶Ô¶à¹ØÏµµÄ¶à·½£¬Äã±ØÐëÓÃ
mappedByÀ´Ö¸¶¨ËûÃÇ·Ö±ðÓ³ÉäµÄÊÇÄĸö¼¯ºÏ:
class Airport {
static hasMany = [flights:Flight]
static mappedBy = [flights:"departureAirport"]
}
class Flight {
Airport departureAirport
Airport destinationAirport
}Èç¹ûÄãÓжà¸öÓ³Éäµ½²»Í¬ÊôÐԵļ¯ºÏ£¬Ò²ÐèÒªÕâÑù:
class Airport {
static hasMany = [outboundFlights:Flight, inboundFlights:Flight]
static mappedBy = [outboundFlights:"departureAirport", inboundFlights:"destinationAirport"]
}
class Flight {
Airport departureAirport
Airport destinationAirport
}GrailsÖ§³Ö¶à¶Ô¶à¹ØÁª£¬ÕâÖÖ¹ØÁªÐèÒªÔÚ¹ØÁªµÄÁ½·½¶¼¶¨Òå
hasMany£¬²¢ÔÚ¹ØÁªµÄ±»ÓµÓз½¶¨Òå
belongsTo:
class Book {
static belongsTo = Author
static hasMany = [authors:Author]
String title
}
class Author {
static hasMany = [books:Book]
String name
}GrialsÔÚÊý¾Ý¿â²ãʹÓÃÁ¬½Ó±íÀ´Ó³Éä¶à¶Ô¶à¹ØÁª¡£¹ØÁªµÄÓµÓз½£¬ÔÚÕâÀïÊÇ
Author,¸ºÔð³Ö¾Ã»¯Õâ¸ö¹ØÁª£¬²¢ÇÒËüÊÇΨһ¿ÉÒÔ¼¶Áª±£´æ¶Ô·½µÄÒ»·½¡£
±ÈÈçÏÂÃæµÄ´úÂë¿ÉÒÔ¹¤×÷£¬²¢»á¼¶Áª±£´æ:
new Author(name:"Stephen King")
.addToBooks(new Book(title:"The Stand"))
.addToBooks(new Book(title:"The Shining"))
.save()
µ«ÊÇÏÂÃæµÄ´úÂëÖ»±£´æ
Book ¶ø²»±£´æauthors!
new Book(name:"Groovy in Action")
.addToAuthors(new Author(name:"Dierk Koenig"))
.addToAuthors(new Author(name:"Guillaume Laforge"))
.save()
ÕâÕýÊÇÎÒÃÇÆÚÍûµÄÐÐΪ£¬¸úHibernateÖÐÒ»Ñù£¬¶à¶Ô¶à¹ØÁªÖÐÖ»ÓÐÒ»·½¿ÉÒÔ¹ÜÀí¹ØÁª¡£
GrailsµÄ ½ÅÊÖ¼Ü ÌØÐÔµ±Ç°»¹²»Ö§³Ö¶à¶Ô¶à¹ØÁª£¬Òò´ËÄã±ØÐë×Ô¼ºÐ´´úÂëÀ´¹ÜÀí¹ØÁª¡£
¸ú
¹ØÁªÒ»Ñù,GrailsÖ§³Ö×éºÏµÄ¸ÅÄî¡£ÔÚÕâÖÖÇé¿öÏÂ,ÒªÓ³Éäµ½Ò»¸ö¶ÀÁ¢µÄ±íµÄÀà,¿ÉÒÔǶÈëµ½µ±Ç°±í¡£±ÈÈç:
class Person {
Address homeAddress
Address workAddress
static embedded = ['homeAddress', 'workAddress']
}
class Address {
String number
String code
}Ó³ÉäµÄ½á¹û¿´ÆðÀ´ÏñÏÂÃæÕâÑù:

Èç¹ûÄãÔÚgrails-app/domain Ŀ¼ÏÂÒ»¸öµ¥¶ÀµÄGroovyÎļþÖж¨ÒåÁË Address À࣬Ä㻹ÊÇ»áµÃµ½Ò»¸ö address ±í¡£Èç¹ûÄã²»ÏëÕâÑù£¬Äã¿ÉÒÔʹÓÃGroovy¿ÉÒÔÔÚÒ»¸öÎļþÖж¨Òå¶à¸öÀàµÄÌØÐÔ£¬ÔÚgrails-app/domain/Person.groovy ÎļþÖÐÔÚ Person ÀàµÄÏÂÃæ¶¨Òå Address Àà¡£
GORMÖ§³Ö´Ó³éÏó»ùÀàºÍ´Ó¾ßÌåʵÌåÀà¼Ì³Ð¡£±ÈÈ磺
class Content {
String author
}
class BlogEntry extends Content {
URL url
}
class Book extends Content {
String ISBN
}
class PodCast extends Content {
byte[] audioStream
}ÔÚÉÏÃæµÄÀý×ÓÖÐÎÒÃÇÓиö½Ð
Content µÄ¸¸À࣬Ȼºó²»Í¬µÄ×ÓÀàÓиü¶àËüÃǸ÷×ÔÌØ¶¨µÄÐÐΪ¡£
¼Ì³ÐÓ³ÉäµÄ˼¿¼
ÔÚÊý¾Ý¿â¼¶±ðGrailsĬÈÏʹÓÃÿ¸öÀà·Ö²ã½á¹¹Ò»¸ö±í(uses table-per-hierarchy)µÄÓ³Éä²ßÂÔ£¬ÓÐÒ»¸ö±æ±ð±êʶ(discriminator)ÁнÐ
class £¬Òò´Ë¸¸Àà
Content ºÍËüµÄ×ÓÀà(
BlogEntry,
Book µÈµÈ.)¹²Ïíͬһ¸ö±í¡£
ÿ¸öÀà·Ö²ã½á¹¹Ò»¸ö±í(uses table-per-hierarchy)ÓÐÒ»¸ö¸±×÷Ó㬾ÍÊÇÄã¼Ì³ÐÓ³ÉäÖеÄÊôÐÔ²»ÄÜÓзǿÕÔ¼Êø¡£Ò»¸öÑ¡ÔñÊÇʹÓÃÿ¸ö×ÓÀàÒ»¸ö±í(table-per-subclass)Ó³É䣬Ëü¿ÉÒÔͨ¹ý
ORM DSLÉèÖá£
µ«ÊÇ£¬¹ý¶ÈµÄʹÓü̳кÍÿ¸ö×ÓÀàÒ»¸ö±í(table-per-subclass)µÄÓ³Éä²ßÂÔ£¬»áµ¼Ö¹ý¶ÈʹÓÃÁ¬½Ó²éѯ£¬Ê¹µÃ²éѯÐÔÄܺܲͨ³£ÎÒÃǽ¨Òé±£³Ö¼òµ¥£¬Ö»ÓÐÔÚÄãȷʵÐèÒª¼Ì³ÐµÄʱºò²ÅÓÃËü¡£
¶à̬²éѯ
ʹÓü̳еĺô¦ÊÇÄã»ñµÃÁ˶à̬²éѯµÄÄÜÁ¦£¬±ÈÈçÔÚ³¬Àà
Content ÉÏʹÓÃ
list ·½·¨½«»á·µ»Ø
ContentµÄËùÓÐ×ÓÀà:
def content = Content.list() // list all blog entries, books and pod casts
content = Content.findAllByAuthor('Joe Bloggs') // find all by authordef podCasts = PodCast.list() // list only pod casts
¶ÔÏ󼯺Ï(Set)
µ±ÄãÔÚGROMÖж¨ÒåÒ»¸ö¹ØÁªµÄʱºò,ĬÈϵØÊ¹ÓÃ
java.util.Set ,ËüÊÇÒ»¸öÎÞÐò²¢²»Äܰüº¬Öظ´¶ÔÏóµÄ¼¯ºÏ.»»¾ä»°Ëµ,µ±ÄãдÁËÏÂÃæ´úÂë:
class Author {
static hasMany = [books:Book]
}GORM×¢ÈëµÄbooksÊôÐÔÊÇÒ»¸ö
java.util.Set.ÕâÀïÓÐÒ»¸öÎÊÌ⣬µ±·ÃÎÊÕâ¸ö¼¯ºÏʱÊÇÎÞÐòµÄ,Õâ¿ÉÄܲ»ÊÇÄãÏëÒªµÄ.ΪÁË»ñµÃ×Ô¶¨ÒåµÄ˳ÐòÄã¿ÉÒÔ½«Õâ¸ö¼¯ºÏÉèÖÃΪ
SortedSet:
class Author {
SortedSet books
static hasMany = [books:Book]
} ÔÚÕâÀïʹÓÃÁË
java.util.SortedSet ʵÏÖ,Õâ¾ÍÒâζ×ÅÄãµÄBookÀà±ØÐëʵÏÖ
java.lang.Comparable ½Ó¿Ú:
class Book implements Comparable {
String title
Date releaseDate = new Date() int compareTo(obj) {
releaseDate.compareTo(obj.releaseDate)
}
}ÉÏÃæÀàµÄ½á¹ûÊÇAuthorÀàµÄbooks¼¯ºÏÖÐËùÓеÄBookʵÀý½«°´ËûÃǵķ¢²¼ÈÕÆÚÅÅÐò.
¶ÔÏóÁбí
Èç¹ûÄãÖ»ÊÇÏëÄܹ»¼òµ¥µÄ±£³Ö¶ÔÏó°´ÕÕËûÃDZ»¼Ó½øÈ¥µÄ˳ÐòÅÅÐò£¬²¢ÄÜÏñÊý×éÒ»Ñù°´ÕÕË÷ÒýÀ´ÒýÓÃËûÃÇ,Äã¿ÉÒÔ¶¨ÒåÄãµÄ¼¯ºÏÀàÐÍΪ
List:
class Author {
List books
static hasMany = [books:Book]
}ÔÚÕâÖÖÇé¿öϵ±ÄãÏòbooks¼¯ºÏÖÐÌí¼ÓÒ»¸öÐÂÔªËØÊ±,Õâ¸ö˳Ðò½«»á±£´æÔÚÒ»¸ö´Ó0¿ªÊ¼µÄÁбíË÷ÒýÖÐ,Òò´ËÄã¿ÉÒÔ:
author.books[0] // get the first book
ÕâÖÖ·½·¨ÔÚÊý¾Ý¿â²ãµÄ¹¤×÷ÔÀíÊÇ:ΪÁËÔÚÊý¾Ý¿â²ã±£´æÕâ¸ö˳Ðò,Hibernate´´½¨Ò»¸ö½Ð×ö
books_idxµÄÁÐ,Ëü±£´æ×ŸÃÔªËØÔÚ¼¯ºÏÖеÄË÷Òý.
µ±Ê¹ÓÃ
List ʱ,ÔªËØÔÚ±£´æÖ®Ç°±ØÐëÏÈÌí¼Óµ½¼¯ºÏÖÐ,·ñÔòHibernate»áÅ׳öÒì³£(
org.hibernate.HibernateException: null index column for collection):
// This won't work!
def book = new Book(title: 'The Shining')
book.save()
author.addToBooks(book)// Do it this way instead.
def book = new Book(title: 'Misery')
author.addToBooks(book)
author.save()
Ó³Éä(Maps)¶ÔÏó
Èç¹ûÄãÏëÒªÒ»¸ö¼òµ¥µÄ string/value ¶Ômap,GROM¿ÉÒÔÓÃÏÂÃæ·½·¨À´Ó³Éä:
class Author {
Map books // my of ISBN:book names
}def a = new Author()
a.books = ["1590597583":"Grails Book"]
a.save()ÕâÖÖÇé¿ömapµÄ¼üºÍÖµ¶¼±ØÐëÊÇ×Ö·û´®.
Èç¹ûÄãÏëÓÃÒ»¸ö¶ÔÏóµÄmap,ÄÇôÄã¿ÉÒÔÕâÑù×ö:
class Book {
Map authors
static hasMany = [authors:Author]
}def a = new Author(name:"Stephen King")def book = new Book()
book.authors = [stephen:a]
book.save()static
hasMany ÊôÐÔ¶¨ÒåÁËmapÖÐÔªËØµÄÀàÐÍ,mapÖеÄkey
±ØÐë ÊÇ×Ö·û´®
¹ØÓÚGrailsÒª¼ÇסµÄºÜÖØÒªµÄÒ»µã¾ÍÊÇ£¬GrailsµÄµ×²ãʹÓÃ
Hibernate À´½øÐг־û¯.Èç¹ûÄúÒÔǰʹÓõÄÊÇ
ActiveRecord »òÕß
iBatis , Äú¿ÉÄÜ»á¶ÔHibernateµÄ"session"Ä£Ð͸е½ÓеãİÉú.
±¾ÖÊÉÏ,Grails×Ô¶¯°ó¶¨Hibernate sessionµ½µ±Ç°ÕýÔÚÖ´ÐеÄÇëÇóÉÏ.ÕâÔÊÐíÄãÏñʹÓÃGORMµÄÆäËû·½·¨Ò»ÑùºÜ×ÔÈ»µØÊ¹ÓÃ
save ºÍ
delete·½·¨ .
ÏÂÃæ¿´Ò»¸öʹÓÃ
save ·½·¨µÄÀý×Ó:
def p = Person.get(1)
p.save()
HibernateµÄÒ»¸öÖ÷ÒªµÄ²»Í¬ÔÚÓÚµ±Äãµ÷ÓÃ
save ʱËü²»ÐèÒªÂíÉÏÖ´ÐÐÈκÎSQL²Ù×÷.Hibernateͨ³£½«SQLÓï¾ä·ÖÅú,×îºóÖ´ÐÐËûÃÇ.¶ÔÄãÀ´Ëµ,ÕâЩһ°ã¶¼ÊÇÓÉGrails×Ô¶¯Íê³ÉµÄ,Ëü¹ÜÀí×ÅÄãµÄHibernate session.
Ò²ÓÐÒ»Ð©ÌØÊâÇé¿ö,ÓÐʱºòÄã¿ÉÄÜÏë×Ô¼º¿ØÖÆÄÇЩÓï¾äʲôʱºò±»Ö´ÐÐ,»òÕßÓÃHibernateµÄÊõÓïÀ´Ëµ,¾ÍÊÇʲôʱºòsession±»"flushed".ÒªÕâÑùµÄ»°,Äã¿ÉÒÔ¶Ôsave·½·¨Ê¹ÓÃflush²ÎÊý:
def p = Person.get(1)
p.save(flush:true)
ÐèҪעÒâµÄÊÇ,Õâʱ°üÀ¨±£´æÖ®Ç°ËùÓеȴýÖ´ÐеÄSQLÓï¾ä¶¼»áͬ²½µ½Êý¾Ý¿âÖÐ.ÄãÒ²¿ÉÒÔ²¶»ñÈκÎÅ׳öµÄÒì³£,Õâͨ³£ÔÚ°üº¬ÁË
ÀÖ¹ÛËøµÄ¸ß²¢·¢Çé¿öÏ·dz£ÓÐÓÃ.
def p = Person.get(1)
try {
p.save(flush:true)
}
catch(Exception e) {
// deal with exception
}
ÏÂÃæÊÇ
delete·½·¨µÄÒ»¸öÀý×Ó:
def p = Person.get(1)
p.delete()
delete ·½·¨Ò²ÔÊÐíͨ¹ý
flush ²ÎÊýÀ´¿ØÖÆflushing.
def p = Person.get(1)
p.delete(flush:true)
×¢ÒâGrailsûÓÐÌṩ
deleteAll ·½·¨,ÒòΪɾ³ýÊý¾ÝÊÇdiscouragedµÄ£¬¶øÇÒͨ³£¿ÉÒÔͨ¹ý²¼¶û±ê¼Ç/Âß¼À´±ÜÃâ.
Èç¹ûÄãȷʵÐèÒªÅúÁ¿É¾³ýÊý¾Ý,Äã¿ÉÒÔʹÓÃ
executeUpdate·½·¨À´Ö´ÐÐÅúÁ¿µÄDMLÓï¾ä:
Customer.executeUpdate("delete Customer c where c.name = :oldName", [oldName:"Fred"])ÔÚʹÓÃGORMʱ,Àí½âÈçºÎ¼¶Áª¸üкÍɾ³ýÊǺÜÖØÒªµÄ.ÐèÒª¼ÇסµÄ¹Ø¼üÊÇ
belongsTo µÄÉèÖÿØÖÆ×ÅÄĸöÀà"ÓµÓÐ"Õâ¸ö¹ØÁª.
ÎÞÂÛÊÇÒ»¶ÔÒ»,Ò»¶Ô¶à»¹ÊǶà¶Ô¶à,Èç¹ûÄ㶨ÒåÁË
belongsTo ,¸üкÍɾ³ý½«»á´ÓÓµÓÐÀൽ±»ËüÓµÓеÄÀà(¹ØÁªµÄÁíÒ»·½)¼¶Áª²Ù×÷.
Èç¹ûÄãûÓж¨Òå
belongsTo ,ÄÇô¾ÍÄܼ¶Áª²Ù×÷,Ä㽫ÐèÒªÊÖ¹¤±£´æÃ¿¸ö¶ÔÏó.
ÏÂÃæÊÇÒ»¸öÀý×Ó:
class Airport {
String name
static hasMany = [flights:Flight]
}
class Flight {
String number
static belongsTo = [airport:Airport]
}Èç¹ûÎÒÏÖÔÚ´´½¨Ò»¸ö
Airport ¶ÔÏó,²¢ÏòËüÌí¼ÓһЩ
Flight,Ëü¿ÉÒÔ±£´æÕâ¸ö
Airport ²¢¼¶Áª±£´æÃ¿¸öflight,Òò´Ë»á±£´æÕû¸ö¶ÔÏóͼ:
new Airport(name:"Gatwick")
.addToFlights(new Flight(number:"BA3430"))
.addToFlights(new Flight(number:"EZ0938"))
.save()
Ïà·´µÄ,Èç¹ûÉÔºóÎÒɾ³ýÁËÕâ¸ö
Airport,ËùÓиúËü¹ØÁªµÄ
FlightÒ²¶¼½«»á±»É¾³ý:
def airport = Airport.findByName("Gatwick")
airport.delete()È»¶ø,Èç¹ûÎÒ½«
belongsTo È¥µôµÄ»°,ÉÏÃæµÄ¼¶ÁªÉ¾³ý´úÂë¾Í²»Äܹ¤×÷ÁË.
ÔÚGORMÖÐ,¹ØÁªÄ¬ÈÏÊÇlazyµÄ.×îºÃµÄ½âÊÍÊÇÀý×Ó:
class Airport {
String name
static hasMany = [flights:Flight]
}
class Flight {
String number
static belongsTo = [airport:Airport]
}ÉÏÃæµÄdomainÀàºÍÏÂÃæµÄ´úÂë:
def airport = Airport.findByName("Gatwick")
airport.flights.each {
println it.name
}GORM½«»áÖ´ÐÐÒ»¸öµ¥¶ÀµÄSQL²éѯÀ´×¥È¡
Airport ʵÀý,È»ºóÔÙÓÃÒ»¸ö¶îÍâµÄ²éѯÖðÌõµü´ú
flights ¹ØÁª.»»¾ä»°Ëµ,ÄãµÃµ½ÁËN+1Ìõ²éѯ.
¸ù¾ÝÕâ¸ö¼¯ºÏµÄʹÓÃÆµÂÊ,ÓÐʱºòÕâ¿ÉÄÜÊÇ×î¼Ñ·½°¸.ÒòΪÄã¿ÉÒÔÖ¸¶¨Ö»ÓÐÔÚÌØ¶¨µÄÇé¿öϲŷÃÎÊÕâ¸ö¹ØÁªµÄÂß¼.
Ò»¸ö¿ÉÑ¡µÄ·½°¸ÊÇʹÓÃÁ¢¼´×¥È¡,Ëü¿ÉÒÔ°´ÕÕÏÂÃæµÄ·½·¨À´Ö¸¶¨:
class Airport {
String name
static hasMany = [flights:Flight]
static fetchMode = [flights:"eager"]
}ÔÚÕâÖÖÇé¿öÏÂ,
AirportʵÀý¶ÔÓ¦µÄ
flights¹ØÁª»á±»Ò»´ÎÐÔÈ«²¿¼ÓÔØ½øÀ´(ÒÀÀµÓÚÓ³Éä).ÕâÑùµÄºÃ´¦ÊÇÖ´ÐиüÉٵIJéѯ,µ«ÊÇҪСÐÄʹÓÃ,ÒòΪʹÓÃÌ«¶àµÄeager¹ØÁª¿ÉÄܻᵼÖÂÄ㽫Õû¸öÊý¾Ý¿â¼ÓÔØ½øÄÚ´æ.
¹ØÁªÒ²¿ÉÒÔÓà ORM DSL ½«¹ØÁªÉùÃ÷Ϊ non-lazy
ÀÖ¹ÛËø
ĬÈϵÄGORMÀà±»ÅäÖÃΪÀÖ¹ÛËø¡£ÀÖ¹ÛËøÊµÖÊÉÏÊÇHibernateµÄÒ»¸öÌØÐÔ£¬ËüÔÚÊý¾Ý¿âÀïÒ»¸öÌØ±ðµÄ
version ×Ö¶ÎÖб£´æÁËÒ»¸ö°æ±¾ºÅ¡£
versionÁжÁÈ¡°üº¬µ±Ç°ÄãËù·ÃÎʵij־û¯ÊµÀýµÄ°æ±¾×´Ì¬µÄ
versionÊôÐÔ:
def airport = Airport.get(10)println airport.version
µ±ÄãÖ´ÐиüвÙ×÷ʱ£¬Hibernate½«×Ô¶¯¼ì²éversionÊôÐÔºÍÊý¾Ý¿âÖÐversionÁУ¬Èç¹ûËûÃDz»Í¬£¬½«»áÅ׳öÒ»¸ö
StaleObjectExceptionÒì³££¬²¢ÇÒµ±Ç°ÊÂÎïÒ²»á±»»Ø¹ö¡£
ÕâÊǺÜÓÐÓõģ¬ÒòΪËüÔÊÐíÄ㲻ʹÓñ¯¹ÛËø(ÓÐһЩÐÔÄÜÉϵÄËðʧ)¾Í¿ÉÒÔ»ñµÃÒ»¶¨µÄÔ×ÓÐÔ¡£ÓÉ´Ë´øÀ´µÄ¸ºÃæÓ°ÏìÊÇ£¬Èç¹ûÄãÓÐһЩ¸ß²¢·¢µÄд²Ù×÷µÄ»°£¬Äã±ØÐë´¦ÀíÕâ¸öÒì³£¡£ÕâÐèҪˢ³ö(flushing)µ±Ç°µÄsession£º
def airport = Airport.get(10)try {
airport.name = "Heathrow"
airport.save(flush:true)
}
catch(org.springframework.dao.OptimisticLockingFailureException e) {
// deal with exception
}Äã´¦ÀíÒì³£µÄ·½·¨È¡¾öÓÚÄãµÄÓ¦Óá£Äã¿ÉÒÔ³¢ÊԺϲ¢Êý¾Ý,»òÕß·µ»Ø¸øÓû§²¢ÈÃËûÃÇÀ´´¦Àí³åÍ».
×÷ΪѡÔñ£¬Èç¹ûËü³ÉÁËÎÊÌ⣬Äã¿ÉÒÔÇóÖúÓÚ±¯¹ÛËø¡£
±¯¹ÛËø¡£
±¯¹ÛËøµÈ¼ÛÓÚÖ´ÐÐÒ»¸ö SQL "SELECT * FOR UPDATE" Óï¾ä ²¢Ëø¶¨Êý¾Ý¿âÖеÄÒ»ÐС£ÕâÒâζ×ÅÆäËûµÄ¶Á²Ù×÷½«»á±»Ëø¶¨Ö±µ½Õâ¸öËø·Å¿ª¡£
ÔÚGrailsÖб¯¹ÛËøÍ¨¹ý
lock ·½·¨Ö´ÐÐ:
def airport = Airport.get(10)
airport.lock() // lock for update
airport.name = "Heathrow"
airport.save()
Ò»µ©µ±Ç°ÊÂÎï±»Ìá½»£¬Grails»á×Ô¶¯µÄΪÄãÊÍ·ÅËø¡£
GORMÌṩÁË´Ó¶¯Ì¬²éѯÆ÷µ½criteriaµ½HibernateÃæÏò¶ÔÏó²éѯÓïÑÔHQLµÄһϵÁвéѯ·½Ê½¡£
Groovyͨ¹ý
GPath ²Ù×ݼ¯ºÏµÄÄÜÁ¦£¬ºÍGORMµÄÏñsort,findAllµÈ·½·¨½áºÏÆðÀ´£¬ÐγÉÁËÒ»¸öÇ¿´óµÄ×éºÏ¡£
µ«ÊÇ£¬ÈÃÎÒÃÇ´Ó»ù´¡¿ªÊ¼°É¡£
»ñȡʵÀýÁбí
Èç¹ûÄã¼òµ¥µÄÐèÒª»ñµÃ¸ø¶¨ÀàµÄËùÓÐʵÀý£¬Äã¿ÉÒÔʹÓÃ
list·½·¨:
list ·½·¨Ö§³Ö·ÖÒ³²ÎÊý:
def books = Book.list(offset:10, max:20)
Ò²¿ÉÒÔÅÅÐò:
def books = Book.list(sort:"asc", order:"title")
¸ù¾ÝÊý¾Ý¿â±êʶ·ûÈ¡»Ø
µÚ¶þ¸öÈ¡»ØµÄ»ù±¾ÐÎʽÊǸù¾ÝÊý¾Ý¿â±êʶ·ûÈ¡»Ø£¬Ê¹ÓÃ
get ·½·¨:
ÄãÒ²¿ÉÒÔ¸ù¾ÝÒ»¸ö±êʶ·ûµÄ¼¯ºÏʹÓÃ
getAll·½·¨È¡µÃÒ»¸öʵÀýÁбí:
def books = Book.getAll(23, 93, 81)
GORMÖ§³Ö¶¯Ì¬²éÕÒÆ÷µÄ¸ÅÄî¡£¶¯Ì¬²éÕÒÆ÷¿´ÆðÀ´ÏñÒ»¸ö¾²Ì¬·½·¨µÄµ÷Ó㬵«ÊÇÕâЩ·½·¨±¾ÉíÔÚ´úÂëÖÐʵ¼ÊÉϲ¢²»´æÔÚ¡£
¶øÊÇÔÚÔËÐÐʱ»ùÓÚÒ»¸ö¸ø¶¨ÀàµÄÊôÐÔ,×Ô¶¯Éú³ÉÒ»¸ö·½·¨¡£±ÈÈçÀý×ÓÖеÄ
BookÀà:
class Book {
String title
Date releaseDate
Author author
}
class Author {
String name
} Book ÀàÓÐһЩÊôÐÔ£¬±ÈÈç
title,
releaseDate ºÍ
author. ÕâЩ¶¼¿ÉÒÔ°´ÕÕ·½·¨±í´ïʽµÄ¸ñʽ±»ÓÃÓÚ
findBy ºÍ
findAllBy ·½·¨¡£
def book = Book.findByTitle("The Stand")book =
Book
.findByTitleLike("Harry Pot%")book =
Book
.findByReleaseDateBetween( firstDate, secondDate )book =
Book
.findByReleaseDateGreaterThan( someDate )book =
Book
.findByTitleLikeOrReleaseDateLessThan( "%Something%", someDate )·½·¨±í´ïʽ
ÔÚGORMÖÐÒ»¸ö·½·¨±í´ïʽÓÉǰ׺(±ÈÈç
findBy)ºóÃæ¸úÒ»¸ö±í´ïʽ×é³É£¬Õâ¸ö±í´ïʽÓÉÒ»¸ö»ò¶à¸öÊôÐÔ×é³É¡£»ù±¾ÐÎʽÊÇ:
Book.findBy[Property][Suffix]*[Boolean Operator]*[Property][Suffix]
ÓÃ*±ê¼ÇµÄ²¿·ÖÊÇ¿ÉÑ¡µÄ¡£Ã¿¸öºó׺¶¼»á¸Ä±ä²éѯµÄÐÔÖÊ¡£ÀýÈç:
def book = Book.findByTitle("The Stand")book = Book.findByTitleLike("Harry Pot%")ÔÚÉÏÃæµÄÀý×ÓÖУ¬µÚÒ»¸ö²éѯµÈ¼ÛÓÚµÈÓÚºóÃæµÄÖµ¡£µÚ¶þ¸öÒòΪÔö¼ÓÁË
Likeºó׺£¬ËüµÈ¼ÛÓÚSQLµÄ
like±í´ïʽ¡£
¿ÉÓõĺó׺°üÀ¨:
LessThan - СÓÚ¸ø¶¨Öµ
LessThanEquals -СÓÚ»òµÈÓÚ¸ø¶¨Öµ
GreaterThan - ´óÓÚ¸ø¶¨Öµ
GreaterThanEquals - ´óÓÚ»òµÈÓÚ¸ø¶¨Öµ
Like - µÈ¼ÛÓÚ SQL like ±í´ïʽ
Ilike -ÀàËÆÓÚ Like, µ«²»ÊÇ´óСдÃô¸Ð
NotEqual - ²»µÈÓÚ
Between - ½éÓÚÁ½¸öÖµÖ®¼ä (ÐèÒªÁ½¸ö²ÎÊý)
IsNotNull - ²»ÎªnullµÄÖµ(²»ÐèÒª²ÎÊý)
IsNull - ΪnullµÄÖµ (²»ÐèÒª²ÎÊý)
Äã»á·¢ÏÖ×îºóÈý¸ö·½·¨±ê×¢Á˲ÎÊýµÄ¸öÊý£¬ËûÃǵÄʾÀýÈçÏ£º
def now = new Date()
def lastWeek = now - 7
def book =
Book
.findByReleaseDateBetween( lastWeek, now )ͬÑùµÄ
isNull ºÍ
isNotNull ²»ÐèÒª²ÎÊý:
def books = Book.findAllByReleaseDateIsNull()
²¼¶ûÂß¼(AND/OR)
·½·¨±í´ïʽҲ¿ÉÒÔʹÓÃÒ»¸ö²¼¶û²Ù×÷·ûÀ´×éºÏÁ½¸öcriteria£º
def books =
Book
.findAllByTitleLikeAndReleaseDateGreaterThan("%Java%", new Date()-30)ÔÚÕâÀïÎÒÃÇÔÚ²éѯÖмäʹÓÃ
AndÀ´È·±£Á½¸öÌõ¼þ¶¼Âú×㣬µ«ÊÇͬÑùµØÄãÒ²¿ÉÒÔʹÓÃ
Or:
def books =
Book
.findAllByTitleLikeOrReleaseDateGreaterThan("%Java%", new Date()-30)ÏÔÈ»ÕâÖÖÇé¿öÏ·½·¨Ãû»á±äµÃÏ൱³¤£¬ÕâʱºòÄãÓ¦¸Ã¿¼ÂÇʹÓÃ
Ìõ¼þ²éѯ.
²éѯ¹ØÁª
¹ØÁªÒ²¿ÉÒÔ±»ÓÃÔÚ²éѯÖÐ:
def author = Author.findByName("Stephen King")def books = author ? Book.findAllByAuthor(author) : []ÔÚÕâÀïÈç¹û
Author ʵÀý²»Îªnull,ÎÒÃÇÔÚ²éѯÖÐÓÃËüÈ¡µÃ¸ø¶¨
AuthorµÄËùÓÐ
Book ʵÀý.
·ÖÒ³ºÍÅÅÐò
¸ú
list ·½·¨ÉÏ¿ÉÓõķÖÒ³ºÍÅÅÐò²ÎÊýÒ»Ñù£¬ËûÃÇͬÑù¿ÉÒÔ±»ÌṩΪһ¸ömapÓÃÓÚ¶¯Ì¬²éѯÆ÷µÄ×îºóÒ»¸ö²ÎÊý¡£
def books =
Book.findAllByTitleLike("Harry Pot%", [max:3,
offset:2,
sort:"asc",
order:"title"])
CriteriaÊÇÒ»ÖÖÀàÐͰ²È«µÄ¡¢¸ß¼¶µÄ²éѯ·½·¨£¬ËüʹÓÃGroovy builder¹¹ÔìÇ¿´ó¸´ÔӵIJéѯ¡£ËüÊÇÒ»ÖÖ±ÈʹÓÃStringBufferºÃµÃ¶àµÄÑ¡Ôñ¡£
Criteria¿ÉÒÔͨ¹ý
createCriteria »òÕß
withCriteria ·½·¨À´Ê¹Óá£builderʹÓÃHibernateµÄCriteria API,builderÉϵĽڵã¶ÔÓ¦Hibernate Criteria APIÖÐ
Restrictions ÀàÖеľ²Ì¬·½·¨¡£Ó÷¨Ê¾Àý:
def c = Account.createCriteria()
def results = c {
like("holderFirstName", "Fred%")
and {
between("balance", 500, 1000)
eq("branch", "London")
}
maxResults(10)
order("holderLastName", "desc")
}Âß¼Ó루Conjunctions£©ºÍÂß¼»ò£¨Disjunctions£©
ÈçÇ°ÃæÀý×ÓËùÑÝʾµÄ£¬Äã¿ÉÒÔÓÃ
and { } ¿éÀ´·Ö×écriteriaµ½Ò»¸öÂß¼AND:
and {
between("balance", 500, 1000)
eq("branch", "London")
}Âß¼ORÒ²¿ÉÒÔÕâô×ö:
or {
between("balance", 500, 1000)
eq("branch", "London")
}ÄãÒ²¿ÉÒÔÓÃÂß¼NOTÀ´·ñ¶¨:
not {
between("balance", 500, 1000)
eq("branch", "London")
}²éѯ¹ØÁª
¹ØÁª¿ÉÒÔͨ¹ýʹÓÃÒ»¸ö¸ú¹ØÁªÊôÐÔͬÃûµÄ½ÚµãÀ´²éѯ¡£±ÈÈçÎÒÃÇ˵
AccountÀàÓйØÁªµ½¶à¸ö
Transaction ¶ÔÏó:
class Account {
…
def hasMany = [transactions:Transaction]
Set transactions
…
}
ÎÒÃÇ¿ÉÒÔʹÓÃÊôÐÔÃû
transaction ×÷ΪbuilderµÄÒ»¸ö½ÚµãÀ´²éѯÕâ¸ö¹ØÁª:
def c = Account.createCriteria()
def now = new Date()
def results = c.list {
transactions {
between('date',now-10, now)
}
}
The above code will find all the
Account instances that have performed
transactions within the last 10 days.
ÉÏÃæµÄ´úÂ뽫»á²éÕÒËùÓйýÈ¥10ÌìÄÚÖ´Ðйý
transactions µÄ
AccountʵÀý¡£ÄãÒ²¿ÉÒÔÔÚÂß¼¿éÖÐǶÌ×¹ØÁª²éѯ:
def c = Account.createCriteria()
def now = new Date()
def results = c.list {
or {
between('created',now-10,now)
transactions {
between('date',now-10, now)
}
}
}
ÕâÀï,ÎÒÃǽ«ÕÒ³öÔÚ×î½ü10ÌìÄÚ½øÐйý½»Ò×»òÕß×î½ü10ÌìÄÚд´½¨µÄËùÓÐÓû§¡£
ͶӰ(Projections)²éѯ
ͶӰ±»ÓÃÓÚ¶¨ÖƲéѯ½á¹û¡£ÒªÊ¹ÓÃͶӰÄãÐèÒªÔÚcriteria builderÊ÷ÀﶨÒåÒ»¸ö"projections"½Úµã¡£projections½ÚµãÄÚ¿ÉÓõķ½·¨µÈͬÓÚ Hibernate µÄ
Projections ÀàÖеķ½·¨.
def c = Account.createCriteria()def numberOfBranches = c.get {
projections {
countDistinct('branch')
}
}ʹÓÿɹö¶¯µÄ½á¹û
Äã¿ÉÒÔͨ¹ýµ÷ÓÃscroll·½·¨À´Ê¹ÓÃHibernateµÄ
ScrollableResults ÌØÐÔ¡£
def results = crit.scroll {
maxResults(10)
}
def f = results.first()
def l = results.last()
def n = results.next()
def p = results.previous()def future = results.scroll(10)
def accountNumber = results.getLong('number')
ÏÂÃæÒýÓõÄÊÇHibernateÎĵµÖйØÓÚScrollableResultsµÄÃèÊö:
½á¹û¼¯µÄµü´úÆ÷£¨iterator£©¿ÉÒÔÒÔÈÎÒâ²½½øµÄ·½Ê½Ç°ºóÒÆ¶¯£¬¶øQuery / ScrollableResultsģʽ¸úJDBCµÄPreparedStatement/ ResultSetÒ²ºÜÏñ£¬Æä½Ó¿Ú·½·¨ÃûµÄÓïÒâÒ²¸úResultSetµÄÀàËÆ¡£
²»Í¬ÓÚJDBC£¬½á¹ûÁеıàºÅÊÇ´Ó0¿ªÊ¼.
ÔÚCriteriaʵÀýÖÐÉèÖÃÊôÐÔ
Èç¹ûÔÚbuilderÊ÷ÄÚ²¿µÄÒ»¸ö½Úµã²»Æ¥ÅäÈκÎÒ»ÏîÌØ¶¨±ê×¼£¬Ëü½«³¢ÊÔÉèÖÃΪCriteria¶ÔÏó×ÔÉíµÄÊôÐÔ¡£Òò´ËÔÊÐíÍêÈ«·ÃÎÊÕâ¸öÀàµÄËùÓÐÊôÐÔ¡£ÏÂÃæµÄÀý×ÓÊÇÔÚ
CriteriaʵÀýÉϵ÷ÓÃ
setMaxResults ºÍ
setFirstResult:
import org.hibernate.FetchMode as FM
....
def results = c.list {
maxResults(10)
firstResult(50)
fetchMode("aRelationship", FM.EAGER)
}Á¢¼´×¥È¡µÄ·½Ê½²éѯ
ÔÚ
Á¢¼´¼ÓÔØºÍÑÓ³Ù¼ÓÔØ Õâ½Ú£¬ÎÒÃÇÌÖÂÛÁËÈç¹ûÖ¸¶¨Ìض¨µÄץȡ·½Ê½À´±ÜÃâN+1²éѯµÄÎÊÌâ¡£Õâ¸öcriteria²éѯҲ¿ÉÒÔ×öµ½:
import org.hibernate.FetchMode as FM
// ......def criteria = Task.createCriteria()
def tasks = criteria.list{
eq("assignee.id", task.assignee.id)
fetchMode('assignee', FM.EAGER)
fetchMode('project', FM.EAGER)
order('priority', 'asc')
}
·½·¨ÒýÓÃ
Èç¹ûÄãµ÷ÓÃÒ»¸öûÓз½·¨ÃûµÄbuilder£¬±ÈÈç:
ĬÈϵĻáÁгöËùÓнá¹û£¬Òò´ËÉÏÃæ´úÂëµÈ¼ÛÓÚ:
| ·½·¨ | ÃèÊö |
|---|
|
| list | ÕâÊÇĬÈϵķ½·¨¡£Ëü»á·µ»ØËùÓÐÆ¥ÅäµÄÐС£ |
| get | ·µ»ØÎ¨Ò»µÄ½á¹û¼¯£¬±ÈÈ磬¾ÍÒ»ÐС£criteriaÒѾ¹æ¶¨ºÃÁË£¬½ö½ö²éѯһÐС£Õâ¸ö·½·¨¸ü·½±ã£¬ÃâµÃʹÓÃÒ»¸ölimitÀ´Ö»È¡µÚÒ»ÐÐʹÈËÃÔ»ó¡£ |
| scroll | ·µ»ØÒ»¸ö¿É¹ö¶¯µÄ½á¹û¼¯ |
| listDistinct | Èç¹û×Ó²éѯ»òÕß¹ØÁª±»Ê¹Óã¬ÓÐÒ»¸ö¿ÉÄܾÍÊÇÔÚ½á¹û¼¯Öжà´Î³öÏÖͬһÐУ¬Õâ¸ö·½·¨ÔÊÐíÖ»Áгö²»Í¬µÄÌõÄ¿£¬ËüµÈ¼ÛÓÚCriteriaSpecification ÀàµÄDISTINCT_ROOT_ENTITY¡£ |
GORMÒ²Ö§³ÖHibernateµÄ²éѯÓïÑÔHQL,ÔÚHibernateÎĵµÖеÄ
Chapter 14. HQL: The Hibernate Query Language ,¿ÉÒÔÕÒµ½Ëü·Ç³£ÍêÕûµÄ²Î¿¼Êֲᡣ
GORMÌṩÁËһЩʹÓÃHQLµÄ·½·¨£¬°üÀ¨
find,
findAll ºÍ
executeQuery¡£ÏÂÃæÊÇÒ»¸ö²éѯµÄÀý×Ó:
def results =
Book.findAll("from Book as b where b.title like 'Lord of the%'")λÖúÍÃüÃû²ÎÊý
ÉÏÃæµÄÀý×ÓÖд«µÝ¸ø²éѯµÄÖµÊÇÓ²±àÂëµÄ£¬µ«ÊÇ£¬Äã¿ÉÒÔͬÑùµØÊ¹ÓÃλÖòÎÊý:
def results =
Book.findAll("from Book as b where b.title like ?", ["The Shi%"])»òÕßÉõÖÁʹÓÃÃüÃû²ÎÊý:
def results =
Book.findAll("from Book as b where b.title like :search or b.author like :search", [search:"The Shi%"])¶àÐвéѯ
Èç¹ûÄãÐèÒª½«²éѯ·Ö¸îµ½¶àÐÐÄã¿ÉÒÔʹÓÃÒ»¸öÐÐÁ¬½Ó·û:
def results = Book.findAll("""\\
from Book as b, \\
Author as a \\
where b.author = a and a.surname = ?""", ['Smith'])
Groovy µÄ¶àÐÐ×Ö·û´®¶ÔHQL²éѯÎÞЧ
·ÖÒ³ºÍÅÅÐò
ʹÓÃHQL²éѯµÄʱºòÄãÒ²¿ÉÒÔ½øÐзÖÒ³ºÍÅÅÐò¡£Òª×öµÄÖ»ÊǼòµ¥Ö¸¶¨·ÖÒ³ºÍÅÅÐò²ÎÊý×÷Ϊһ¸öÉ¢ÁÐÔÚ·½·¨µÄĩβµ÷ÓÃ:
def results =
Book.findAll("from Book as b where b.title like 'Lord of the%'",
[max:10, offset:20, sort:"asc", order:"title"])
½ÓÏÂÀ´µÄÕ½ڸ²¸Ç¸ü¶à¸ß¼¶µÄGORMʹÓà °üÀ¨ »º´æ¡¢¶¨ÖÆÓ³ÉäºÍʼþ
GORM supports the registration of events as closures that get fired when certain events occurs such as deletes, inserts and updates. To add an event simply register the relevant closure with your domain class.
GORMÖ§³Öʼþ×¢²á£¬Ö»ÐèÒª½«Ê¼þ×÷Ϊһ¸ö±Õ°ü¼´¿É£¬µ±Ä³¸öʼþ´¥·¢£¬±ÈÈçɾ³ý£¬²åÈ룬¸üС£ÎªÁËÌí¼ÓÒ»¸öʼþÐèÒªÔÚÄãµÄÁìÓòÀàÖÐÌí¼ÓÏà¹ØµÄ±Õ°ü¡£
ʼþÀàÐÍ
beforeInsertʼþ
´¥·¢µ±Ò»¸ö¶ÔÏó±£´æµ½Êý¾Ý¿â֮ǰ
class Person {
Date dateCreated def beforeInsert = {
dateCreated = new Date()
}
}beforeUpdateʼþ
¸üÐÂǰʼþ
class Person {
Date dateCreated
Date lastUpdated def beforeInsert = {
dateCreated = new Date()
}
def beforeUpdate = {
lastUpdated = new Date()
}
}beforeDeleteʼþ
´¥·¢µ«Ò»¸ö¶ÔÏó±»É¾³ý
class Person {
String name
Date dateCreated
Date lastUpdated def beforeDelete = {
new ActivityTrace(eventName:"Person Deleted",data:name).save()
}
}onLoadʼþ
´¥·¢µ±Ò»¸ö¶ÔÏó´ÓÊý¾Ý¿âÈ¡³ö
class Person {
String name
Date dateCreated
Date lastUpdated def onLoad = {
name = "I'm loaded"
}
}×Ô¶¯Ê±¼ä´Á
ÉÏÃæµÄÀý×ÓÑÝʾÁËʹÓÃʼþÀ´¸üÐÂÒ»¸ö
lastUpdatedºÍ
dateCreatedÊôÐÔÀ´¸ú×Ù¶ÔÏóµÄ¸üС£ÊÂʵÉÏ£¬ÕâЩÉèÖò»ÊDZØÐëµÄ¡£Í¨¹ý¼òµ¥µÄ¶¨ÒåÒ»¸ö
lastUpdatedºÍ
dateCreatedÊôÐÔ £¬GORM»á×Ô¶¯µÄΪÄã¸üС£
Èç¹û£¬ÕâЩÐÐΪ²»ÊÇÄãÐèÒªµÄ£¬¿ÉÒÔÆÁ±ÎÕâЩ¹¦ÄÜ¡£ÈçÏÂÉèÖÃ
class Person {
Date dateCreated
Date lastUpdated
static mapping = {
autoTimestamp false
}
}Grails µÄÓò¶ÔÏó¿ÉÒÔÓ³Éäµ½Ðí¶àÒÅÁôµÄÄ£ÐÍͨ¹ý ¹ØÏµ¶ÔÏóÓ³ÉäÓòÓïÑÔ¡£½ÓÏÂÀ´µÄ²¿·Ö½«´øÄãÁìÂÔËüÊÇ¿ÉÄܵÄͨ¹ýORM DSL
ÕâÊDZØÒªµÄ£¬Èç¹ûÄã¸ßÐ˵ؼá³ÖÒÔÔ¼¶¨À´¶¨ÒåGORM¶ÔÓ¦µÄ±í£¬ÁÐÃûµÈ¡£ÄãÖ»ÐèÒªÕâ¸ö¹¦ÄÜ£¬Èç¹ûÄãÐèÒª¶¨ÖÆGORM Ó³Éäµ½ÒÅÁôÄ£ÐÍ»ò½øÐлº´æ
×Ô¶¨ÒåÓ³ÉäÊÇʹÓþ²Ì¬µÄ
mapping¿é¶¨ÒåÔÚÄãµÄÓòÀàÖеģº
class Person {
..
static mapping = { }
}
±íÃû
ÀàÓ³Éäµ½Êý¾Ý¿âµÄ±íÃû¿ÉÒÔͨ¹ýʹÓÃ
table¹Ø¼ü×ÖÀ´¶¨ÖÆ
class Person {
..
static mapping = {
table 'people'
}
}ÔÚÉÏÃæµÄÀý×ÓÖУ¬Àà»áÓ³Éäµ½
people±íÀ´´úÌæÄ¬ÈϵÄ
person±í
ÁÐÃû
ͬÑù£¬Ò²ÊÇ¿ÉÄ͍ܵ֯ij¸öÁе½Êý¾Ý¿â¡£±ÈÈç˵£¬ÄãÏë¸Ä±äÁÐÃûÀý×ÓÈçÏÂ
class Person {
String firstName
static mapping = {
table 'people'
firstName column:'First_Name'
}
}ÔÚÕâ¸öÀý×ÓÖУ¬Ä㶨ÒåÁËÒ»¸ö
column¿é£¬´Ë¿é°üº¬µÄ·½·¨µ÷ÓÃÆ¥Åäÿһ¸öÊôÐÔÃû³Æ£¨±¾Àý×ÓÖÐÊÇ
firstName£©£¬½ÓÏÂÀ´Ê¹ÓÃÃüÃûµÄ
columnÀ´Ö¸¶¨×Ö¶ÎÃû³ÆµÄÓ³Éä
ÁÐÀàÐÍ
GORM supports configuration of Hibernate types via the DSL using the type attribute. This includes specifing user types that subclass the Hibernate
org.hibernate.types.UserType class. As an example
GORM»¹¿ÉÒÔͨ¹ýDSLµÄtypeÊôÐÔÀ´Ö§³ÖHibernateÀàÐÍ£¬°üÀ¨Ìض¨HibernateµÄ
org.hibernate.types.UserTypeµÄ×ÓÀà¡£±ÈÈ磬ÓÐÒ»¸öPostCodeType,Äã¿ÉÒÔÏóÏÂÃæÕâÑùʹÓãº
class Address {
String number
String postCode
static mapping = {
postCode type:PostCodeType
}
}ÁíÍâÈç¹ûÄãÏ뽫ËüÓ³Éäµ½HibernateµÄ»ù±¾ÀàÐͶø²»ÊÇGrailsµÄĬÈÏÀàÐÍ£¬¿ÉÒԲο¼ÏÂÃæ´úÂ룺
class Address {
String number
String postCode
static mapping = {
postCode type:'text'
}
}ÉÏÃæµÄÀý×Ó½«Ê¹postCodeÁÐÓ³Éäµ½Êý¾Ý¿âµÄSQL TEXT»òÕßCLOBÀàÐÍ
Ò»¶ÔÒ»Ó³Éä
ÔÚ¹ØÁªÖУ¬ÄãÒ²Óлú»á¸Ä±äÍâ¼üÓ³ÉäÁªÏµ£¬ÔÚÒ»¶ÔÒ»µÄ¹ØÏµÖУ¬¶ÔÁеIJÙ×÷¸úÆäËû³£¹æµÄÁвÙ×÷²¢ÎÞ¶þÒ죬Àý×ÓÈçÏÂ
class Person {
String firstName
Address address
static mapping = {
table 'people'
firstName column:'First_Name'
address column:'Person_Adress_Id'
}
}ĬÈÏÇé¿öÏ£¬
address½«Ó³Éäµ½Ò»¸öÃû³ÆÎªaddress_id µÄÍâ¼ü¡£µ«ÊÇʹÓÃÉÏÃæµÄÓ³É䣬ÎÒÃǸıäÍâ¼üÁÐΪ
Person_Adress_IdÒ»¶Ô¶àÓ³Éä
ÔÚÒ»¸öË«ÏòµÄÒ»¶Ô¶à¹ØÏµÖУ¬Äã¿ÉÒÔÏóǰ½ÚÖеÄÒ»¶ÔÒ»¹ØÏµÖÐÄÇÑù¸Ä±äÍâ¼üÁУ¬Ö»ÐèÒªÔÚ¶àµÄÒ»¶ËÖиıäÁÐÃû¼´¿É¡£È»¶ø£¬ÔÚµ¥Ïò¹ØÁªÖУ¬Íâ¼üÐèÒªÔÚ¹ØÁª×ÔÉíÖУ¨¼´Ò»µÄÒ»¶Ë-ÒëÕß×¢£©Ö¸¶¨¡£±ÈÈ磬¸ø¶¨Ò»¸öµ¥ÏòÒ»¶Ô¶àÁªÏµ
PersonºÍ
Address£¬ÏÂÃæµÄ´úÂë»á¸Ä±ä
address±íÖÐÍâ¼ü¡£
class Person {
String firstName
static hasMany = [addresses:Address]
static mapping = {
table 'people'
firstName column:'First_Name'
addresses column:'Person_Address_Id'
}
}Èç¹ûÄã²»ÏëÔÚ
address±íÖÐÓÐÕâ¸öÁУ¬¿ÉÒÔͨ¹ýÖÐ¼ä¹ØÁª±íÀ´Íê³É£¬Ö»ÐèҪʹÓÃjoinTable²ÎÊý¼´¿É£º
class Person {
String firstName
static hasMany = [addresses:Address]
static mapping = {
table 'people'
firstName column:'First_Name'
addresses joinTable:[name:'Person_Addresses', key:'Person_Id', column:'Address_Id']
}
}¶à¶Ô¶àÓ³Éä
ĬÈÏÇé¿öÏ£¬GrailsÖжà¶Ô¶àµÄÓ³ÉäÊÇͨ¹ýÖмä±íÀ´Íê³ÉµÄ£¬ÒÔÏÂÃæµÄ¶à¶Ô¶à¹ØÁªÎªÀý£º
class Group {
…
static hasMany = [people:Person]
}
class Person {
…
static belongsTo = Group
static hasMany = [groups:Group]
}ÔÚÉÏÃæµÄÀý×ÓÖУ¬Grails½«»á´´½¨Ò»¸ö
group_person±í°üº¬Íâ¼ü
person_idºÍ
group_id¶ÔÓ¦
personºÍ
group±í¡£¼ÙÈçÄãÐèÒª¸Ä±äÁÐÃû£¬Äã¿ÉÒÔΪÿ¸öÀàÖ¸¶¨Ò»¸öÁÐÓ³Éä
class Group {
…
static mapping = {
people column:'Group_Person_Id'
}
}
class Person {
…
static mapping = {
groups column:'Group_Group_Id'
}
}ÄãÒ²¿ÉÒÔÖ¸¶¨Öмä±íµÄÃû³Æ
class Group {
…
static mapping = {
people column:'Group_Person_Id',joinTable:'PERSON_GROUP_ASSOCIATIONS'
}
}
class Person {
…
static mapping = {
groups column:'Group_Group_Id',joinTable:'PERSON_GROUP_ASSOCIATIONS'
}
}
ÉèÖûº´æ
Hibernate ±¾ÉíÌṩÁË×Ô¶¨Òå¶þ¼¶»º´æµÄÌØÐÔ£¬Õâ¾ÍÐèÒªÔÚ
grails-app/conf/DataSource.groovyÎļþÖÐÅäÖãº
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='org.hibernate.cache.EhCacheProvider'
}µ±È»£¬ÄãÒ²¿ÉÒÔ°´ÄãËùÐèÀ´¶¨ÖÆÉèÖᣱÈÈ磬ÄãÏëʹÓ÷ֲ¼Ê½»º´æ»úÖÆ
ÏëÁ˽â¸ü¶àHibernateµÄ¶þ¼¶»º´æ£¬²Î¿¼HibernateÏà¹ØÎĵµ
»º´æÊµÀý
¼ÙÈçÒªÔÚÓ³Éä´úÂë¿éÖÐÆôÓÃȱʡµÄ»º´æ£¬¿ÉÒÔͨ¹ýµ÷ÓÃ
cache·½·¨ÊµÏÖ£º
class Person {
..
static mapping = {
table 'people'
cache true
}
}ÉÏÃæµÄÀý×ÓÖн«ÅäÖÃÒ»¸ö¶Á-д(read-write)»º´æ°üÀ¨lazyºÍnon-lazyÊôÐÔ¡£¼ÙÈçÄãÏë¶¨ÖÆÕâÐ©ÌØÐÔ£¬Äã¿ÉÒÔÈçÏÂËùʾ£º
class Person {
..
static mapping = {
table 'people'
cache usage:'read-only', include:'non-lazy'
}
}»º´æ¹ØÁª¶ÔÏó
¾ÍÏñʹÓÃHibernateµÄ¶þ¼¶»º´æÀ´»º´æÊµÀýÒ»Ñù£¬ÄãÒ²¿ÉÒÔÀ´»º´æ¼¯ºÏ£¨¹ØÁª£©£¬±ÈÈ磺
class Person {
String firstName
static hasMany = [addresses:Address]
static mapping = {
table 'people'
version false
addresses column:'Address', cache:true
}
}
class Address {
String number
String postCode
}ÉÏÃæµÄÀý×ÓÖУ¬ÎÒÃÇÔÚaddresses¼¯ºÏÆôÓÃÁËÒ»¸ö¶Á-д»º´æ£¬ÄãÒ²¿ÉÒÔʹÓÃ
cache:'read-write' // or 'read-only' or 'transactional'
¸ü¶àÅäÖÃÇë²Î¿¼»º´æÓ÷¨
»º´æÓ÷¨
ÏÂÃæÊDz»Í¬»º´æÉèÖúÍËûÃǵÄʹÓ÷½·¨
read-only - ¼ÙÈçÄãµÄÓ¦ÓóÌÐòÐèÒª¶Áµ«ÊÇ´Ó²»ÐèÒª¸ü¸Ä³Ö¾Ã»¯ÊµÀý£¬Ö»¶Á»º´æ»òÐíÊÊÓÃ
read-write - ¼ÙÈçÄãµÄÓ¦ÓóÌÐòÐèÒª¸üÐÂÊý¾Ý£¬¶Á-д»º´æ»òÐíÊǺÏÊʵÄ
nonstrict-read-write - ¼ÙÈçÄãµÄÓ¦ÓóÌÐò½öż¶ûÐèÒª¸üÐÂÊý¾Ý£¨Ò²¾ÍÊÇ˵£¬Èç¹ûÕâÊǼ«²»¿ÉÄÜÁ½±Ê½»Ò×£¬½«³¢ÊÔ¸üÐÂͬһÏîĿͬʱ£©²¢ÇÒʱ½øÐУ© £¬²¢Ñϸñ½»Ò׸ôÀ룬ÊDz»ÊÇÐèÒªÒ»¸ö·ÇÑϸñ-¶Áд»º´æ¿ÉÄÜÊÇÊÊÒ˵Ä
transactional - transactional»º´æ²ßÂÔÌṩ֧³Ö¶ÔÈ«ÊÂÎñ»º´æÌṩ±ÈÈçJBossµÄTreeCache¡£Õâ¸ö»º´æ»òÐí½ö½öʹÓÃÔÚÒ»¸öJTA»·¾³£¬Í¬Ê±Äã±ØÐëÔÚgrails-app/conf/DataSource.groovyÎļþÖÐÅäÖÃhibernate.transaction.manager_lookup_class
ĬÈÏÇé¿öÏÂGORM ÀàʹÓÃ
table-per-hierarchyÀ´Ó³Éä¼Ì³ÐµÄ¡£Õâ¾ÍÓÐÒ»¸öȱµã¾ÍÊÇÔÚÊý¾Ý¿â²ãÃæ£¬Áв»ÄÜÓÐ
NOT-NULLµÄÔ¼Êø¡£Èç¹ûÄã¸üϲ»¶
table-per-subclass£¬Äã¿ÉÒÔʹÓÃÏÂÃæ·½·¨
class Payment {
Long id
Long version
Integer amount static mapping = {
tablePerHierarchy false
}
}
class CreditCardPayment extends Payment {
String cardNumber
}ÔÚ׿ÏÈPaymentÀàµÄÓ³ÉäÉèÖÃÖУ¬Ö¸¶¨ÁËÔÚËùÓеÄ×ÓÀàÖУ¬²»Ê¹ÓÃ
table-per-hierarchyÓ³Éä¡£
Äã¿ÉÒÔͨ¹ýDSLÀ´¶¨ÖÆGORMÉú³ÉÊý¾Ý¿â±êʶ£¬È±Ê¡Çé¿öÏÂGORM½«¸ù¾ÝÔÉúÊý¾Ý¿â»úÖÆÀ´Éú³Éids£¬ÕâÊÇÆù½ñΪֹ×îºÃµÄ·½·¨£¬µ«ÊÇÈÔ´æÔÚÐí¶àģʽ£¬²»Í¬µÄ·½·¨À´Éú³É±êʶ¡£
Ϊ´Ë£¬HibernateÌØµØ¶¨ÒåÁËidÉú³ÉÆ÷µÄ¸ÅÄÄã¿ÉÒÔ×Ô¶¨ÒåËüÒªÓ³ÉäµÄidÉú³ÉÆ÷ºÍÁУ¬ÈçÏ£º
class Person {
..
static mapping = {
table 'people'
version false
id generator:'hilo', params:[table:'hi_value',column:'next_value',max_lo:100]
}
}ÔÚÉÏÃæµÄÀý×ÓÖУ¬ÎÒÃÇʹÓÃÁËHibernateÄÚÖõÄ'hilo'Éú³ÉÆ÷£¬´ËÉú³ÉÆ÷ͨ¹ýÒ»¸ö¶ÀÁ¢µÄ±íÀ´Éú³Éids¡£´ËÍ⻹ÓÐÐí¶à²»Í¬µÄÉú³ÉÆ÷¿ÉÒÔÅäÖ㬾ßÌå²Î¿¼HibernateÔÚÕâ¸öÖ÷ÌâÉϵÄÏà¹ØÎĵµ¡£
ÏëÁ˽â¸ü¶à²»Í¬µÄHibernateÉú³ÉÆ÷Çë²Î¿¼HibernateÎĵµ
×¢Ò⣬Èç¹ûÄã½ö½öÏë¶¨ÖÆÁÐid£¬Äã¿ÉÒÔÕâÑù
class Person {
..
static mapping = {
table 'people'
version false
id column:'person_id'
}
}
GORMÖ§³Ö¸´ºÏ±êʶ£¨¸´ºÏÖ÷¼ü--ÒëÕß×¢£©¸ÅÄ±êʶÓÉÁ½¸ö»òÕ߸ü¶àÊôÐÔ×é³É£©¡£Õâ²»ÊÇÎÒÃǽ¨ÒéµÄ·½·¨£¬µ«ÊÇÈç¹ûÄãÏëÕâô×ö£¬ÕâÒ²ÊÇ¿ÉÄܵģº
class Person {
String firstName
String lastName static mapping = {
id composite:['firstName', 'lastName']
}
}ÉÏÃæµÄ´úÂ뽫ͨ¹ý
PersonÀàµÄ
firstNameºÍ
lastNameÊôÐÔÀ´´´½¨Ò»¸ö¸´ºÏid¡£µ±ÄãºóÃæÐèҪͨ¹ýidȡһ¸öʵÀýʱ£¬Äã±ØÐëÓÃÕâ¸ö¶ÔÏóµÄÔÐÍ
def p = Person.get(new Person(firstName:"Fred", lastName:"Flintstone"))
println p.firstName
ΪµÃµ½×îºÃµÄ²éѯÐÔÄÜ£¬Í¨³£ÄãÐèÒªµ÷Õû±íµÄË÷Òý¶¨Òå¡£ÈçºÎµ÷ÕûËüÃÇÊǸúÌØ¶¨ÁìÓòºÍÒª²éѯµÄÓ÷¨Ä£Ê½Ïà¹ØµÄ¡£Ê¹ÓÃGORMµÄDSLÄã¿ÉÒÔÖ¸¶¨ÄǸöÁÐÐèÒªË÷Òý
class Person {
String firstName
String address
static mapping = {
table 'people'
version false
id column:'person_id'
firstName column:'First_Name', index:'Name_Idx'
address column:'Address', index:'Name_Idx, Address_Index'
}
}¾ÍÏñÔÚ
ÀÖ¹ÛËøºÍ±¯¹ÛËø²¿·ÖÌÖÂ۵ģ¬Ä¬ÈÏÇé¿öÏ£¬GORMʹÓÃÀÖ¹ÛËøºÍÔÚÿһ¸öÀàÖÐ×Ô¶¯×¢ÈëÒ»¸ö
versionÊôÐÔ£¬´ËÊôÐÔ½«Ó³ÉäÊý¾Ý¿âÖеÄÒ»¸ö
versionÁÐ
Èç¹ûÄãÓ³ÉäµÄÊÇÒ»¸öÒÅÁôÊý¾Ý¿â£¨ÒѾ´æÔÚµÄÊý¾Ý¿â--ÒëÕß×¢£©£¬Õ⽫ÊÇÒ»¸öÎÊÌ⣬Òò´Ë¿ÉÒÔͨ¹ýÈçÏ·½·¨À´¹Ø±ÕÕâ¸ö¹¦ÄÜ£º
class Person {
..
static mapping = {
table 'people'
version false
}
}
Èç¹ûÄã¹Ø±ÕÁËÀÖ¹ÛËø£¬Ä㽫×Ô¼º¸ºÔð²¢·¢¸üв¢ÇÒ´æÔÚÓû§¶ªÊ§Êý¾ÝµÄ·çÏÕ£¨³ý·ÇÄãʹÓñ¯¹ÛËø£©¡£
ÑÓ³Ù¼ÓÔØ¼¯ºÏ
¾ÍÏñÔÚ
Á¢¼´¼ÓÔØºÍÑÓ³Ù¼ÓÔØ²¿·ÖÌÖÂ۵ģ¬Ä¬ÈÏÇé¿öÏ£¬GORM ¼¯ºÏʹÓÃÑÓ³Ù¼ÓÔØµÄ²¢ÇÒ¿ÉÒÔͨ¹ý
fetchModeÀ´ÅäÖà ¡£µ«Èç¹ûÄã¸üϲ»¶°ÑÄãËùÓеÄÓ³Éä¶¼¼¯ÖÐÔÚ
mappings´úÂë¿éÖУ¬ÄãÒ²¿ÉÒÔʹÓÃORMµÄDSLÀ´ÅäÖûñȡģʽ£º
class Person {
String firstName
static hasMany = [addresses:Address]
static mapping = {
addresses lazy:false
}
}
class Address {
String street
String postCode
}ÑÓ³Ù¼ÓÔØµ¥Ïò¹ØÁª
ÔÚGORMÖУ¬one-to-oneºÍmany-to-one¹ØÁªÈ±Ê¡ÊÇ·ÇÑÓ³Ù¼ÓÔØµÄ¡£ÕâÔÚÓкܶàʵÌ壨Êý¾Ý¿â¼Ç¼-ÒëÕß×¢£©µÄʱºò£¬»á²úÉúÐÔÄÜÎÊÌ⣬ÓÈÆäÊǹØÁª²éѯÊÇÒÔеÄSELECTÓï¾äÖ´ÐеÄʱºò£¬´ËʱÄãÓ¦¸Ã½«one-to-oneºÍmany-to-one¹ØÁªµÄÑÓ³Ù¼ÓÔØÏ󼯺ÏÄÇÑù½øÐÐÉèÖÃ:
class Person {
String firstName
static belongsTo = [address:Address]
static mapping = {
address lazy:true // lazily fetch the address
}
}
class Address {
String street
String postCode
}ÕâÀïÎÒÃÇÉèÖÃ
PersonµÄ
addressÊôÐÔΪÑÓ³Ù¼ÓÔØ
GrailsÊǹ¹½¨ÔÚSpringµÄ»ù´¡Éϵģ¬ËùÒÔʹÓÃSpringµÄÊÂÎñÀ´³éÏó´¦ÀíÊÂÎñ±à³Ì£¬µ«GORMÀàͨ¹ý
withTransaction·½·¨Ê¹µÃ´¦Àí¸ü¼òµ¥£¬·½·¨µÄµÚÒ»¸ö²ÎÊýÊÇSpringµÄ
TransactionStatus¶ÔÏó
µäÐ͵ÄʹÓó¡¾°ÈçÏ£º
def transferFunds = {
Account.withTransaction { status ->
def source = Account.get(params.from)
def dest = Account.get(params.to) def amount = params.amount.toInteger()
if(source.active) {
source.balance -= amount
if(dest.active) {
dest.amount += amount
}
else {
status.setRollbackOnly()
}
}
}}ÔÚÉÏÃæµÄÀý×ÓÖУ¬Èç¹ûÄ¿µÄÕË»§Ã»Óд¦Óڻ״̬£¬ÏµÍ³½«»Ø¹öÊÂÎñ£¬Í¬Ê±Èç¹ûÓÐÈκÎÒì³£Å׳öÔÚÊÂÎñµÄ´¦Àí¹ý³ÌÖÐÒ²½«»á×Ô¶¯»Ø¹ö¡£
¼ÙÈçÄã²»Ïë»Ø¹öÕû¸öÊÂÎñ£¬ÄãÒ²¿ÉÒÔʹÓÃ"save points"À´»Ø¹öÒ»¸öÊÂÎñµ½Ò»¸öÌØ¶¨µÄµã¡£Äã¿ÉÒÔͨ¹ýʹÓÃSpringµÄ
SavePointManager½Ó¿ÚÀ´´ïµ½Õâ¸öÄ¿µÄ¡£
withTransaction·½·¨ÎªÄã´¦Àíbegin/commit/rollback´úÂë¿é×÷ÓÃÓòÄÚµÄÂß¼¡£
¾¡¹ÜÔ¼ÊøÊÇ
ÑéÖ¤Õ½ڵÄÄÚÈÝ£¬µ«ÊÇÔÚ´ËÉæ¼°µ½Ô¼ÊøÒ²ÊǺÜÖØÒªµÄ£¬ÒòÎªÒ»Ð©Ô¼Êø»áÓ°Ïìµ½Êý¾Ý¿âµÄÉú³É¡£
Grailsͨ¹ýʹÓÃÁìÓòÀàµÄÔ¼ÊøÀ´Ó°ÏìÊý¾Ý¿â±í×ֶΣ¨ÁìÓòÀàËù¶ÔÓÚµÄÊôÐÔ£©µÄÉú³É£¬»¹ÊÇ¿ÉÐеġ£
¿¼ÂÇÏÂÃæµÄÀý×Ó£¬¼ÙÈçÎÒÃÇÓÐÒ»¸öÓòÄ£ÐÍÈçϵÄÊôÐÔ£º
ĬÈÏÇé¿öÏ£¬ÔÚMySqlÊý¾Ý¿âÖУ¬Grails½«»á¶¨ÒåÕâ¸öÁÐΪ
column name | data type
description | varchar(255)
µ«ÊÇ£¬ÔÚÒµÎñ¹æÔòÖУ¬ÒªÇóÕâ¸öÁìÓòÀàµÄ
descriptionÊôÐÔÄܹ»ÈÝÄÉ1000¸ö×Ö·û£¬ÔÚÕâÖÖÇé¿öÏ£¬Èç¹ûÎÒÃÇÊÇʹÓÃSQL½Å±¾£¬ÄÇôÎÒÃǶ¨ÒåµÄÕâ¸öÁпÉÄÜÊÇ£º
column name | data type
description | TEXT
ÏÖÔÚÎÒÃÇÓÖÏëÒªÔÚ»ùÓÚÓ¦ÓóÌÐòµÄ½øÐÐÑéÖ¤£¬_ÒªÇóÔڳ־û¯ÈκμǼ֮ǰ_£¬È·±£²»Äܳ¬¹ý1000¸ö×Ö·û¡£ÔÚGrailsÖУ¬ÎÒÃÇ¿ÉÒÔͨ¹ý
Ô¼ÊøÀ´Íê³É£¬ÎÒÃǽ«ÔÚÁìÓòÀàÖÐÐÂÔöÈçϵÄÔ¼ÊøÉùÃ÷£º
static constraints = {
description(maxSize:1000)
}Õâ¸öÔ¼ÊøÌõ¼þ½«»áÌṩÎÒÃÇËùÐèµÄ»ùÓÚÓ¦ÓóÌÐòµÄÑéÖ¤²¢ÇÒÒ²½«Éú³ÉÉÏÊöʾÀýËùʾµÄÊý¾Ý¿âÐÅÏ¢¡£ÏÂÃæÊÇÓ°ÏìÊý¾Ý¿âÉú³ÉµÄÆäËûÔ¼ÊøµÄÃèÊö¡£
Ó°Ïì×Ö·û´®ÀàÐÍÊôÐÔµÄÔ¼Êø
Èç¹û
maxSize»òÕß
sizeÔ¼Êø±»¶¨Ò壬Grails½«¸ù¾ÝÔ¼ÊøµÄÖµÉèÖÃÁеÄ×î´ó³¤¶È¡£
ͨ³££¬²»½¨ÒéÔÚͬһ¸öµÄÁìÓòÀàÖÐ×éºÏʹÓÃÕâÐ©Ô¼Êø¡£µ«ÊÇ£¬Èç¹ûÄã·ÇҪͬʱ¶¨Òå
maxSizeºÍ
sizeÔ¼ÊøµÄ»°£¬Grails½«ÉèÖÃÁеij¤¶ÈΪ
maxSizeÔ¼ÊøºÍ
sizeÉÏÏÞÔ¼ÊøµÄ×îÉÙÖµ£¨GrailsʹÓÃÁ½ÕßµÄ×îÉÙÖµ£¬Òò´ËÈκγ¬¹ý×îÉÙÖµµÄ³¤¶È½«µ¼ÖÂÑéÖ¤´íÎó£©
Èç¹û¶¨ÒåÁËinListÔ¼Êø£¨
maxSizeºÍ
size䶨Ò壩µÄ»°£¬×Ö¶Î×î´ó³¤¶È½«È¡¾öÓÚÁÐ±í£¨list£©ÖÐ××Ö·û´®µÄµÄ³¤¶È¡£ÒÔ"Java"¡¢"Groovy"ºÍ"C++"ΪÀý£¬Grails½«ÉèÖÃ×ֶεij¤¶ÈΪ6£¨"Groovy"µÄ×º¬ÓÐ6¸ö×Ö·û£©¡£
Ó°ÏìÊýÖµÀàÐÍÊôÐÔµÄÔ¼Êø
Èç¹û¶¨ÒåÁËÔ¼Êø
max¡¢
min»òÕß
range£¬Grails½«»ùÓÚÔ¼ÊøµÄÖµ³¢ÊÔ×ÅÉèÖÃÁеÄ
¾«¶È£¨ÉèÖõĽá¹ûºÜ´ó³Ì¶ÈÉÏÒÀÀµÓÚHibernate¸úµ×²ãÊý¾Ý¿âϵͳµÄ½»»¥³Ì¶È£©¡£
ͨ³£À´Ëµ£¬²»½¨ÒéÔÚͬһÁìÓòÀàµÄÊôÐÔÉÏ×éºÏ³ÉË«µÄmin/maxºÍrangeÔ¼Êø£¬µ«ÊÇÈç¹ûÕâÐ©Ô¼ÊøÍ¬Ê±±»¶¨ÒåÁË£¬ÄÇôGrails½«Ê¹ÓÃÔ¼ÊøÖµÖеÄ×îÉÙ¾«¶ÈÖµ£¨GrailsÈ¡Á½ÕßµÄ×îÉÙÖµ£¬ÊÇÒòΪÈÎÒⳬ¹ý×îÉÙ¾«¶ÈµÄ³¤¶È½«»áµ¼ÖÂÒ»¸öÑéÖ¤´íÎ󣩡£
Èç¹û¶¨ÒåÁËscaleÔ¼Êø£¬ÄÇôGrails»áÊÔͼʹÓûùÓÚÔ¼ÊøµÄÖµÀ´ÉèÖÃÁеÄ
±ê¶È£¨scale£©¡£´Ë¹æÔò½ö½öÓ¦ÓÃÓÚ¸¡µ