Scott Davis:
British Sky Broadcasting Group 最近将它的 Web 站点迁移到了 Grails。他们现在每月的点击量达到 1.1 亿次。LinkedIn.com
在其站点的某些商业部分使用 Grails。Tropicana Juice 在英国有一个 Web 站点,该站点几年来一直在 Grails 上运行。
Grails.org 本身就是用 Grails 编写的,每月支持 70,000 多次下载。
美国时间2008年11月11日, SpringSource宣布并购G2One公司(G2One公司拥有Groovy和Grails两大产品)。此次收购后,
SpringSource现在将会向groovy和Grails开发团队提供全面的技术和解决方案的支持。
grails应用的成功案例:
http://grails.org/Success+Stories
在grails的门外徘徊了很久,现在是该用它做东西的时候了。
[lcl@team ~]$ grails stats
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: C:\grails-1.1.1
Base Directory: D:\myeclispe-iplatform\iplatform-test-tools
Running script C:\grails-1.1.1\scripts\Stats.groovy
Environment set to development
+----------------------+-------+-------+
| Name | Files | LOC |
+----------------------+-------+-------+
| Controllers | 9 | 904 |
| Domain Classes | 8 | 95 |
| Tag Libraries | 1 | 10 |
+----------------------+-------+-------+
| Totals | 18 | 1009 |
+----------------------+-------+-------+
有点感慨:
1:敏捷:
东西很小, 但啥都有: permission control/persistence(8 tables)/webservice/ajax/upload
确实够敏捷的:一人日基本就够用了。
2:关于GORM:
grails的domain采用“裸对象”(ps:也拥抱配置),把hibenate很薄的封装了一层,让数据库对java程序员完全透明.
观察一下GORM 创建的表结构,居然加入了version控制(多人编辑同一条数据遇到的version问题,Hibernate乐观锁),优化多表关联查询的索引也加好了。
比如如下两个domain class的多对一关系:
class Conference{ static constraints = { conference(blank:false, nullable:false, maxSize:3000) dateCreated() comments(blank:true, nullable:true) } String conference Date dateCreated String comments static belongsTo = [type:ConferenceType] }
class ConferenceType{ static constraints = { type(blank:false, nullable:false,maxSize:15) comments(blank:true, nullable:true, maxSize:1000) } static mapping = { sort "type" } String type String comments static hasMany = [conferences:Conference] String toString(){ type } }
产生的表结构如下:
Conference对应的ddl如下:
DROP TABLE IF EXISTS `conference`; CREATE TABLE `conference` ( `id` bigint(20) NOT NULL auto_increment, `version` bigint(20) NOT NULL default '0', `comments` varchar(255) default NULL, `date_created` datetime NOT NULL default '0000-00-00 00:00:00', `type_id` bigint(20) NOT NULL default '0', `conference` longtext NOT NULL, PRIMARY KEY (`id`), KEY `FK1D10CF16AD902` (`type_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
ConferenceType对应的ddl如下:
DROP TABLE IF EXISTS `conference_type`; CREATE TABLE `conference_type` ( `id` bigint(20) NOT NULL auto_increment, `version` bigint(20) NOT NULL default '0', `comments` longtext, `type` varchar(15) NOT NULL default '', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
其中, id,version为所有domain都有的field,grails自动添加
2:ajax支持:
render mydomain as JSON
or:
render mydomain as XML
简短之极的语言(分明就是自然语言), 明确的语意。已经把对象变成json/xml并可供前台js使用了。
3:自定义标签
一个class搞定:
这是g:textArea的源码:
def textArea = {attrs, body -> resolveAttributes(attrs) attrs.id = attrs.id ? attrs.id : attrs.name // Pull out the value to use as content not attrib def value = attrs.remove('value') if(!value) { value = body() } def escapeHtml = true if (attrs.escapeHtml) escapeHtml = Boolean.valueOf(attrs.remove('escapeHtml')) out << "<textarea " outputAttributes(attrs) out << ">" << (escapeHtml ? value.encodeAsHTML() : value) << "</textarea>" }
相对于:jsp/struts/struts2/jsf的自定义标签开发,简单到令人发指。
目前遇到的grails的一些小问题如下:
一:最敏捷的一个scanffold特性,慎用之
此特性在develop环境下可用。
class YourController { def scaffold = YourDomain }
但在生产模式下运行:
1:如下环境下不好使,
tomcat version: version:5.5.27
linux version:
[lcl@team ~]$ cat /proc/version Linux version 2.6.18-53.el5xen ([email protected]) (gcc version 4.1.2 20070626 (Red Hat 4.1.2-14)) #1 SMP Wed Oct 10 16:48:44 EDT 2007
2:在window xp + tomcat 5.5.17上没问题。
不知道是否跟环境有关。
还是老老实实的用grails create-controller生成controller吧, 其实也还蛮“敏捷”的
二:异步提交标签和actionSubmit混用问题
<g:form method="post" > ....... <div class="buttons"> <span class="button"><g:actionSubmit class="save" value="Update" /></span> <g:submitToRemote action="transfer" update="transfermsg" value="Transfer" onComplete="new Effect.Grow('transfermsg');"/> </div> </g:form>
单独用g:actionSubmit或g:submitToRemote 提交都没问题
但是把它们写在一起(如上,同一个form),g:submitToRemote 就不行了,老是调用的save闭包(不调用action="transfer")。
问题有点诡异, 还没深入分析,估计是个bug。
三:部署到如上的linux+tomcat环境后,运行一个比较好性能的操作,报如下错误:
java.lang.OutOfMemoryError: PermGen space异常
估计是用grails的默认 grails war,打的package过大,超过31M导致。
解决方法有两个:
1:在Config.groovy 中定义所需的打包jargrails.war.dependencies
和 grails.war.java5.dependencies
具体实现可看官方文档:
2:比较快速的修复:直接在tomcat的启动脚本增加perm size:
:JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m"
四:domain.list()方法在gsp文件中慎用。
在windows + tomcat5.5下用production模式run没问题
但在如上的linux+ tomcat下, GSP中的domain.list()居然编译不通过。
解决办法:
在controller中, 把domain.list()用[yourList:domain.list()]送到gsp中。
不过这点小问题,相对于它的敏捷,基本就忍了。
现在是时候用grails了。
热切的期盼grails社区能热起来。