Posts Tagged ‘groovy’

GroovyServlet的缺陷

August 7th, 2009

原本希望groovy能以php那种方式工作,但是现在看来不太可能。Groovy发行包里自带的TemplateServlet太弱,GroovyServlet也有致命的缺陷。

GroovyServlet使用GroovyScriptEngine(后面简称GSE)解析groovy文件,解析过程中GSE会智能的自动的到类路径中寻找被引用到的groovy类文件。如果被用作groovyServlet的文件被更新了,GSE会重新解析它,不需要重启服务器,就可以看到效果。可惜的是,如果被引用到的类路径中的其它的文件被更新了,GSE还在使用原来的文件,必须重启服务器才能看到效果,这是在是太令人失望了。据说groovy 1.7 里GSE会这方面增强,很期待呀。TemplateServlet干脆就连GSE也没有用,所以自动引用其他的groovy文件也不可能了。无论是GroovyServlet还是TemplateServlet都不能够像php那样通过include别的php文件来获得别的文件里定义的类,方法和闭包。

看开,在目前,如果不用grails,是没有什么好办法直接用groovy文件写网络程序的,只好把它编译成class文件,就像java生成的class一样来使用。很可气的是,我试用了几个IDE,eclipse, netbeans和idea,其中只有idea支持得还可以,但都是不算很好。看来groovy还有一段路要走。

  • Share/Bookmark

groovy+spring全动态web开发方案

July 14th, 2009

为什么java开发没有php容易?,我在那篇文章了提出了三点原因,利用groovy,我们能在一定程度上做到那三点,从而加快了java web的开发。jsp本身以具有不需要重启就可以生效的能力,但是没有好用的map和动态类型的能力,用在前文 用groovyServlet和TemplateServlet快速开发网页中的方法,可以通过groovy让页面具有好用的map和动态类型的能力,但是 TemplateServlet的局限性 还是很难让我们单凭在页面里编程来构建规模稍大些的应用。引入spring,利用spring对动态语言的支持,我们可以将可重用的逻辑封装到由groovy编写的spring的bean里,这样,就可以最终实现从页面到后台全groovy的效果了,让java的web开发可以达到近似于php的易用度。

看看详细的做法。
把最新版的groovy-all.jar和spring.jar以及spring所依赖的相关包放到/WEB-INF/lib/目录下。

首先,在web.xml里配置好对groovyServlet, TemplateServlet和spring的支持

代码如下:

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
  </context-param>
   
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
 
  <servlet>
    <servlet-name>groovlet</servlet-name>
    <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
  </servlet>
 
  <servlet>
    <servlet-name>gsp</servlet-name>
    <servlet-class>groovy.servlet.TemplateServlet</servlet-class>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>groovlet</servlet-name>
    <url-pattern>*.groovy</url-pattern>
  </servlet-mapping>  
 
  <servlet-mapping>
    <servlet-name>gsp</servlet-name>
    <url-pattern>*.gsp</url-pattern>
  </servlet-mapping>

然后,配置用groovy写spring的bean

如果你要写一个id为foo的bean, 那么要先用java写一个接口,然后用groovy写Bean实现接口,这样不但可以让你以后可以更容易用java重写groovy的bean,也可以避免和spring aop的冲突。

interface Foo.java 代码:

public interface Foo {
    public String shout(String name);
}

groovy实现类 FooImpl.groovy代码:

public class FooImpl implements Foo {
    def sampleProp
    public String shout(String name) {
        def c = {"Groovy : ${sampleProp} ${it}"}
        return c(name)
    }
}

然后在applicationContext中配置

    <lang:groovy id="foo" refresh-check-delay="5000" script-source="classpath:FooImpl.groovy">
        <lang:property name="sampleProp" value="Hello" />
    </lang:groovy>

注意上面的refresh-check-delay=”5000″是让spring每过五秒钟就刷新一下groovy代码,重新编译,当最终部署的时候,可以把它去掉,这样就不会重复刷新了。但是在开发时,我们因此获得了不重启就生效能里。

最后,可以在页面groovy文件中使用这个bean了

使用这个bean和使用其他的spring bean没有什么区别。

import org.springframework.web.context.support.WebApplicationContextUtils;

def spring = WebApplicationContextUtils.getWebApplicationContext(context)
Foo foo = spring.getBean("foo")
foo.shout("sulong")

只要不修改applicationConfig.xml,修改其他的部分都不需要重启或重新部署,这样,你可以通过groovy和spring来达到类似于php那种快速开发的目的。并且在后期,如果有必要,你还可以通过用java重写的bean的方式,来做性能优化。

  • Share/Bookmark

TemplateServlet的局限性

July 10th, 2009

我想利用TemplateServlet,像使用php那样使用groovy。只要设置好了,就可以在web目录下写gsp文件,就像写php那样,即时写即时看到效果。

但是我错了,目前的TemplateServlet非常简陋,远不能达到要求。问题主要发生在include功能。php的inclue require等功能,可以把页面变成方法库,或类库,但是在TemplateServlet的gsp里不行。我无法访问被包含的页面里的方法,闭包等。想想也很自然,每个gsp文件都有自己的名称空间。

另外,不能在gsp里定义类,这个太伤了~~~

如果能解决以上两个问题,TemplateServlet就可以让groovy像php那样使用了。唉,那些做grails的家伙真的应该先把这块搞好,再搞重量级的东西,毕竟不是所有人都想用spring hibernate的。

看了看gails的roadmap,今年9月的1.2版本里将有standalone gsp module,那是真正的gsp,而不是现在的简单的TemplateServlet。Grails里的gsp支持页面片段和非常方便的自定义标签,前者便于共享页面展示,后者便于共享页面行为,那么处理页面的是什么呢?还要写controller吗?到时候看吧,还是很令人期待的。

  • Share/Bookmark

groovy及其TemplateServlet的编码问题

July 9th, 2009

上一篇文章里快速上手使用groovy来写页面了,如果在页面里使用中文的话,可能会遇到中文问题。在1.6.3版本的groovy里,可以设置两个属性来解决:

groovy.source.encoding=UTF-8
file.encoding=UTF-8

groovy在解释脚本时,默认会使用一个叫做groovy.source.encoding的系统属性的值来作为源码的编码,如果这也没有设置的话,就会使用file.encoding这个系统属性,也就是操作系统的默认字符集了。然而TemplateServlet很傻,它只认file.encoding,所以要两个属性都设置上,才能解决问题。而file.encoding属性是在整个jvm下都有效的,可能会带来其他的问题。下个版本中groovy会修正这个问题。如果你等不及了,你可以像我这样,hack一下TemplateServlet,把getTemplate()方法的一段代码改为:

//
// Template not cached or the source file changed - compile new
// template!
//
if (template == null) {
    if (verbose) {
        log("Creating new template from file " + file + "...");
    }
   
    String fileEncoding = System.getProperty("groovy.source.encoding");
   
    Reader reader = null;
    try {
        reader = fileEncoding == null ?
                new FileReader(file) : new InputStreamReader(new FileInputStream(file), fileEncoding);
        template = engine.createTemplate(reader);
    } catch (Exception e) {
        throw new ServletException("Creation of template failed: " + e,
                e);
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException ignore) {
                // e.printStackTrace();
            }
        }
    }
    cache.put(key, new TemplateCacheEntry(file, template, verbose));
    if (verbose) {
        log("Created and added template to cache. [key=" + key + "]");
    }
}

用了如上的代码后就只要设置groovy.source.encoding一个属性就可以了。

  • Share/Bookmark