`

grails学习笔记

 
阅读更多

配置篇

  • 在config.groovy文件中有名为layer1.prop1的参数。请问,在Controller中如何访问它?在Service中呢?

    访问方式一样,可采用以下任意一种方法:

    1 grailsApplication.config.layer1.prop1
    2 //或者
    3 ConfigurationHolder.config.layer1.prop1
  • 如何编辑Grails应用的web.xml文件?

    先使用命令:“grails install-template”安装Template,之后在AppHome/src/templates/war/目录下找到web.xml,修改之。

  • 请解释一下外部配置。它有什么好处?

    grails-app/conf目录下的默认配置文件Config.groovy在大多数情况下就够用了,但是有可能你希望在应用之外维护配置信 息。比如,数据库链接信息,以避免配置修改时需要重新打包WAR。为了支持这些个部署场景,Grails提供了外部部署。你可以在Config.groovy文件中指定外部配置文件的位置,比如:

    1 grails.config.locations = [ "classpath:${appName}-config.properties" ,
    2 "classpath:${appName}-config.groovy" ,
    3 "file:${userHome}/.grails/${appName}-config.properties" ,
    4 "file:${userHome}/.grails/${appName}-config.groovy" ]
  • 请解释一下Config.groovy和BuildConfig.groovy文件的区别。

    Config.groovy是主配置文件,BuildConfig.groovy则侧重构建环境。

  • 请解释一下Bootstrap.groovy的作用?

    在Bootstrap.groovy中,可以定义应用程序启动和停止时执行的代码。

工具/Shell篇

  • 描述一下Grails的console、shell和交互模式(interactive modes)的区别?
    • console:在初始化的Grails环境中运行的Groovy图形控制台,启动方式:“grails console”;
    • shell:在初始化的Grails环境中运行的Groovy Shell,启动方式:“grails shell”;
    • 交 互模式:以交互方式启动Grails CLI,类似在命令行下执行Grails命令,不同之处在于该模式只启动一次JVM,节省了每次执行Grails脚本时启动JVM的时间,同时它还使用JVM的JIT编译器优化Grails脚本,有效提升了需要反复执行的脚本(如单元测试)的执行速度。启动方式:“grails interactive”;
  • 在Grails console中如何获得Spring bean?

    Grails Console有一个绑定变量ctx,它指向ApplicationContext对象,使用如下代码即可获得Spring Bean:

    1 ctx.getBean(beanId)

    详情可参见本站的《如何在Grails Console中调用GetBean》

  • 在Grails console下有哪些注意事项?

    【没弄明白原题的意思,故参考了Tomás Lin的答案】BootStrap.groovy中的内容不会执行;部分工程文件的改动会使Console重启,如Controller的变动不会引起重 启,而Domain Class的文件则会。同时,Tomás的说重启时会造成原来输入的代码丢失,实际情况似乎不是这样,重启之后,原来输入的代码会被加载。但为了保险起 见,如果代码太长了,最好还是保存在外部。

  • 当执行“grails bug-report”,会发生什么事情?

    bug-report用于报告Bug,它仅将应用的源文件打包(不包括Jar文件、静态资源等)生成带有时戳的ZIP文件,它向Grails JIRA报告问题非常有用。

  • Grails中自带的环境有哪些?

    Grails中自带的环境有:开发环境:development;产品环境:Production,测试环境:Test。

    同时,Grails还允许自定义环境,在运行时则需要通过grails.env参数来告知当前环境。详情请参见本站Grails 1.2参考文档速读(2):配置基础和环境

  • 如何改变应用程序使用的服务器端口?

    grails run-app -Dserver.port=port number或者使用grails.server.port配置。

  • 请讲述run-app和run-war的区别?

    run-war:将当前的应用程序打包成WAR,并在Jetty容器的8080端口运行应用。

    run-app:在Jetty容器的8080端口运行应用。

  • Grails中,如何创建自定义脚本?

    使用create-script命令创建,比如:

    1 //创建scripts/ExecuteReport.groovy
    2 grails create-script execute-report
  • 什么是_Events.groovy?它是干什么用的?

    _Events.groovy中可定义事件处理函数,它可以存放在插件的scripts目录下,或者用户目录的.grails/scripts/下。当事件发生时,会调用所有的_Events.groovy文件。详情请参见本站Grails 1.2参考文档速读(5):第4章

  • 假如,我的应用程序处于编译循环中,我猜是因为一个类名跟文件名不一致造成的。我该怎么进行调试?

    使用verboseCompile:“grails compile -verboseCompile”,或者将grails.project.compile.verbose设置为true。

GORM / 数据库

  • 请解释一下dbCreate参数的不同值的区别?

    可用值有create-drop、create、update和validate:

    • create:启动时重新建表;
    • create-drop:启动时重新建表,停止时,drop所有表;
    • update:启动时更新当前的schema,相当于alter table。
    • validate:检查当前的Schema是否跟Domain匹配,不会对数据库做任何修改。
    • null:什么也不干
  • 什么是动态查找器?

    动态查找器是根据Domain Class属性生成的查找方法,这些方法由前缀为findBy和findAllBy的构成,构造规则(以findBy为 例):DomainClass.findBy([Property][Comparator] [Boolean Operator])?[Property][Comparator]。详情可参见本站Grails 1.2参考文档速读(8):GORM中的查询

  • 动态查找器最多有几个参数?

    3,其中2个是属性,另一个是操作符。比如:

    Book.findBy([Property][Comparator][Boolean Operator])
  • 衣柜里有许多鞋。我想保持衣柜对象中鞋子的插入顺序。该怎么办?

    将鞋子属性设置成List,比如:

    1 class Closet {
    2 List shoes
    3 static hasMany = [shoes:Shoe]
    4 }
  • 请解释一下GORM的joinTable。

    joinTable,顾名思义,指的是“关联表”,如多对多中用来保存关系的“中间表”。但是关联表不是多对多的专利,在一对多时,若只有hasMany,而没有belongsTo,同样也会GORM创建关联表。因为此时表示,多端不一定有一端对应的类,即多端的一端可能为null。这句话 有点绕口不是吗?简单点,就是外键可能为null。这对于关系数据库来讲可不是一个好的实践。所以对于只有hasMany的Domain Class来讲,在它们之间创建关联表最合适。可视为退化的“多对多”。

    关于关系的详情,请参见Grails 1.2参考文档速读(6):GORM基础和关系建模 。这部分内容可是本站独家,参考文档上是没有的哦!

  • 请解释一下GORM的lock(),什么情况下会使用它?

    想获得悲观锁时,详情请参见Grails 1.2参考文档速读(7):GORM建模的其余事项及持久化基础

  • GORM中read()和get()的区别是什么?

    都是根据指定ID获得Domain Class。但read的目的是读出来的对象用于只读 ,而get则没有这个限制。

  • Domain对象中的removeFrom()是什么意思?

    跟addTo方法相对,在多端的关联中移除实例。

  • 什么是命名查询?在哪里定义它们?

    即可重用的Criteria,使用namedQueries定义。

  • 动态查找器、HQL和Criteria的不同点是什么?

    动态查找器是根据Domain Class的属性生成的查找方法,诸如findBy**、findAllBy**。最多应用于2个属性;返回结果集是以Domain Class为单位的,无法返回任意结果集,如只包含部分Domain Class的属性的结果集;无法用于任意类之间的关联,关联的类之间需存在关系。

    HQL,类似SQL,通过executeQuery使用。可以返回任意的结果集,可以实现任意类之间的关联。

    Criteria,即Hibernate的Criteria在GORM中的DSL,通过createCriteria或withCriteria方法使用。无属性个数限制,可以实现复杂的关系操作。

  • Grails中的projection什么意思?

    即关系代数中的投影概念,可用于自定义返回的结果,如select中指定返回的列,就是一种投影操作。在HQL和Criteria中均可使用。

  • Grails中如何直接运行SQL?
    1 new Sql(dataSource).execute sqlstr
  • Gorm提供了两个自动时间戳的变量,是什么?

    lastUpdated和dateCreated

  • 解释一下GORM的事件,并举2例。

    可视为GORM的触发器,其作用跟数据库的触发器类似,通过在Domain Class中定义闭包实现,在Domain对象保存之前或之后执行。例如:beforeInsert、afterUpdate。

  • Domain Class中有一个属性,不想持久化。如何保证这个属性不会在数据库中生成一个字段?

    在Domain Class中使用“transients”,例如:

    1 class User {
    2 String address
    3 ......
    4 static transients = [ 'address' ]
    5 }
  • 我想在Grails应用中包含一个Hbernate的HBM文件,该怎么做?

    在grails-app/conf/hibernate目录下,创建hibernate.cfg.xml,并把HBM文件也防置在这个目录下。

  • 如何查看Grails的内置HSQL数据库?

    可以将代码:

    1 org.hsqldb.util.DatabaseManager.main()

    在应用内的任何地方或者Grails Console中,运行上述代码会启动HSQLDB的Console连接界面。在这个界面中,将URL属性值jdbc:hsqldb:mem:* 中的“*”更换成devDB或者你自己定义的数据库名,如“jdbc:hsqldb:mem:devDB”,之后单击OK,就能够看到该数据库中的表结构 了。

    或者直接使用:

    1 org.hsqldb.util.DatabaseManagerSwing.main( [ '--url' , 'jdbc:hsqldb:mem:devDB' ] as String[] )
  • Grails如何使用多个数据库?

    使用Datasources插件

  • 如何根据数据库生成Domain Classe?

    可以使用Grails逆向工程插件 实现,具体使用可参见本站《使用Grails进行数据库逆向工程》

    或者使用GRAG

关于Hibernate的内容不可不读,尤其是《Java Persistence with Hibernate》这本书。

验证篇

  • Grails中的约束是什么意思?请给出3个示例。

    跟数据库中的约束类似,在保存前,Grails会先使用它来验证Domain Class的各个属性,若不能通过,则无法保存或修改,例如:

    1 static constraints = {
    2 login( size : 5 .. 15 ,blank:false,unique:true)
    3 password( size : 5 .. 15 ,blank:false)
    4 email(email:true,blank:false)
    5 age( min : new Date(),nullable:false)
    6 }

    详情可参考本站的《Grails 1.2参考文档速读(15):验证 》。

  • 请给出两个影响视图脚手架显示的约束。

    display:如果true(缺省值),属性将显示;
    editable:如果false,相关表单字段只读。

  • 请给出两个影响数据库生成的约束。

    maxSize(minSize):限制属性值大小,对应列大小;
    size:限定属性值大小范围。

  • 如果验证失败,我希望Domain对象抛出异常,该怎么做?

    Grails提供了配置项:grails.gorm.failOnError,如果设置成true,验证失败时,save()就会抛出grails.validation.ValidationException异常。

  • 什么是Grails命令对象?在验证中如何使用?

    对于不想直接暴露Domain Class的场合,可以使用Command Object来代替。Grails的Command Object跟Spring MVC中的没什么区别,是一个View Object。

    01 class LoginController {
    02 def login = { LoginCommand cmd -<
    03 if (cmd.hasErrors()) {
    04 redirect(action: 'loginForm' )
    05 } else {
    06 // do something else
    07 }
    08 }
    09 }
    10 class LoginCommand {
    11 String username
    12 String password
    13 static constraints = {
    14 username(blank:false, minSize: 6 )
    15 2011 - 2 - 9 ·password(blank:false, minSize: 6 )
    16 }
    17 }

    详情可参考本站的《Grails 1.2参考文档速读(10):Controller 》。

  • validate()和save()的区别?

    validate用于验证;save()用于保存。在进行实际的保存前,save会调用validate,失败则不保存;反之,保存。

  • 有一个类存于src/groovy下,我想为其加入验证,该怎么做?

    方法1:

    1. 将类用@Validateable注解
    2. 在类中定义constraints静态属性
      01 import org.codehaus.groovy.grails.validation.Validateable
      02 @Validateable
      03 class User {
      04 ...
      05 static constraints = {
      06 login( size : 5 .. 15 , blank:false, unique:true)
      07 password( size : 5 .. 15 , blank:false)
      08 email(email:true, blank:false)
      09 age( min : 18 , nullable:false)
      10 }
      11 }
    3. 在Config.groovy中定义要查找@Validateable的包名:grails.validateable.packages
      1 grails.validateable.packages = [ 'com.mycompany.dto' , 'com.mycompany.util' ]

    方法2:

    1. 在类中定义constraints静态属性
      1 class User {
      2 ...
      3 static constraints = {
      4 login( size : 5 .. 15 , blank:false, unique:true)
      5 password( size : 5 .. 15 , blank:false)
      6 email(email:true, blank:false)
      7 age( min : 18 , nullable:false)
      8 }
      9 }
    2. 在Config.groovy中注册类名: grails.validateable.classes
      1 grails.validateable.classes = [com.mycompany.myapp.User , com.mycompany.dto.Account]

      详情可参考《Grails 1.2参考文档速读(15):验证

控制器篇

  • 请解释一下Grails中,Controller与Service的区别。
    • Controller属于Web层的范畴,主要作用是为View的显示做好准备工作,或是针对请求准备好响应的数据。每次请求创建新实例
    • 服务层的作用是封装复杂业务逻辑,尤其是这种逻辑涉及到多个Domain Class的时候。
  • 什么是flash对象?在Grails应用中,flash对象有替代用法么?

    Flash对象是在会话中临时保存的map,可用于下一次请求。在下一次请求结束后,该对象会自动清除。
    可以使用chain代替flash,用法:

    1 chain(action: "a" , model:[one: 1 ],params:[p: "v" ])
  • 表单中有6个朋友的名字,均使用名为‘friendName’的text输入框。在Controller中如何获得它们的list?
    1 params.list(friendName)
  • 我想在Controller的Action中给一些请求返回XML文件,而另一些请求返回一个HTML文件。该如何做?

    首先在grails-app/conf/Config.groovy中,使用grails.mime.types告诉Grails需要支持哪些HTTP请求类型,这个属性缺省已经配置:

    01 grails.mime.types = [
    02 html: [ 'text/html' , 'application/xhtml+xml' ],
    03 xml: [ 'text/xml' , 'application/xml' ],
    04 text: 'text/plain' ,
    05 js: 'text/javascript' ,
    06 rss: 'application/rss+xml' ,
    07 atom: 'application/atom+xml' ,
    08 css: 'text/css' ,
    09 csv: 'text/csv' ,
    10 all: '*/*' ,
    11 json: [ 'application/json' , 'text/json' ],
    12 form: 'application/x-www-form-urlencoded' ,
    13 multipartForm: 'multipart/form-data'
    14 ]

    在Controller中可根据HTTP请求的类型,确定返回的内容:

    01 import grails.converters.*
    02
    03 class BookController {
    04 def books def list = {
    05 this.books = Book.list()
    06 withFormat {
    07 html bookList:books
    08 js { render "alert('hello')" }
    09 xml { render books as XML }
    10 }
    11 }
    12 }
  • 我想把Domain对象转换成XML。怎么样能够保证Domain对象的所有子项都完整的转换到了XML中?

    可以使用grails.converters.XML或者grails.converters.deep.XML。

  • Grails中的redirect()使用的是哪种重定向?如何改变?

    缺省情况下,redirect()方法是用的是302重定向。但是如果要修改可使用如下方法:

    1 redirect(action: "list" )
    2
    3 //变更为
    4 response.setStatus( 301 )
    5 response.setHeader( "Location" , "list" )
  • 什么是Filter?

    请记住:Grails Filter != JEE Filter。Grails实际上就是grails-app/conf下以Filters结尾的Groovy类。Grails的Filter同样有Filter链的概念,它本质上是由多个filter定义组成,定义顺序=执行顺序。Filter应用的范围可以是针对Controller和Action。

视图篇

  • 布局、视图和模板的区别是什么?
    • 布局确定页面结构,用于装饰视图,布局文件位于grails-app/views/layouts。
    • 视图用于前端展现,给用户提供应用程序的使用界面,视图文件位于grails-app/views中。
    • template是可重用的页面片断。名字以下划线开始,如“_bookTemplate.gsp”,其定位规则同View。
  • 什么是命名URL Mapping?它跟一般的URL mappings有什么不同?

    命名URL Mapping即有名字的URL Mapping。在使用该映射时,需要指定其名字。而一般的URL mappings在使用时不需指定名称即可自动匹配。

    1 //定义方式如下
    2 static mappings = {
    3 name <mapping name>: <url pattern> {
    4 // ......
    5 }
    6 }
    7 //用法如下:
    8 <g:link mapping= "mapping name" >List People</g:link>
  • 在Grails中如何使用不同的布局?

    在grails-app/views/layouts下创建布局mylayout.gsp,在需要使用的GSP中调用:

    1 < meta name = "layout" content = "mylayout" ></ meta >

    其中mylayout就是mylayout.gsp的文件名。

  • pageProperty标签是干什么用的?如何使用?

    在布局文件中使用,用于输出被装饰页面的某个属性,等同于SiteMesh的<decorator:getProperty/>标签。

  • 请解释一下<g:form>与<g:formRemote>的区别。

    <g:form>:创建一个用于提交的form。
    <g:formRemote>:触发一个Ajax调用。

  • 我创建了自己的标签库,想在form中以如下方式:<mylib: * >使用,该怎么做?

    为你的标签库指定一个名为“mylib”的命名空间:

    1 class SimpleTagLib {
    2 static namespace = "mylib"
    3
    4 def example = { attrs ->...... } }
    5 //用法:
    6 <mylib:example name= "..." />
  • 在<g:form>中,希望单击按钮时进行一个Ajax的调用,该怎么做?
    1 < g:submitToRemote />
  • 请解释一下remoteLink标签中的update属性。

    update:成功和失败时,显示结果的<div>的id。update还可以只指定一个:update="message",其值是<div>的id。例如:

    1 < div id = "message" ></ div >
    2 < div id = "error" ></ div >
    3 < g:remoteLink action = "delete" id = "1"
    4 update = "[success:'message',failure:'error']" >
    5 Delete Book
    6 </ g:remoteLink >
  • <tmpl:>是做什么用的?

    Template由于使用频繁,因此Grails给它建立单独的名字空间:tmpl。如:

    1 < g:render template = "bookTemplate" model = "[book:myBook]" />
    2 //可简写成:
    3 < tmpl:bookTemplate book = "${myBook}" />
    4
  • 为Ajax调用指定Javascript库的两种方式是什么?
    1 <g:javascript src= "yui***.js" />
    2 <g:javascript library= "yui" />
  • 请解释一下<g:include>标签。

    在当前页面中包含另一个Controller/Action的响应或者视图。

脚手架篇

  • 能解释一下Grails中的静态脚手架和动态脚手架的区别么?

    在Controller不含CRUD action,而是使用scaffold属性,所有的CRUD接口将在运行期间动态生成,这就是动态脚手架。
    而静态脚手架则是通过generate-controller或者generate-all命令生成Controller,在Controller中有CRUD action。

  • 如何修改Grails提供的缺省脚手架?

    运行:grails install-templates,在grails-app\src\templates\scaffolding目录下是缺省的脚手架,可以自行修改。

  • 什么是renderEditor.template文件?它干什么用的?

    该文件位于grails-app\src\templates\scaffolding目录下。它是同目录下的create.gsp和edit.gsp文件使用的模板文件,该模板根据不同的属性类型返回不同的grails的formtaglib

  • generate-views和generate-all的区别是什么?

    generate-views用于生成Domain Class的视图;
    generate-all用于生成Domain Class的控制器及视图。

  • 如果我想重新生成所有Domain Class的脚手架,该运行哪个命令?
    1 grails generate-all *

服务

  • 有两个服务,服务A中有“static transactional = true”,而服务B中没有,这两个服务有什么区别?

    服务A具有事务性,而服务B不具有。

  • 什么是服务的范围?能提供三中不同的服务范围么?

    用过Spring的读者应该对Spring的scope不会陌生,它决定了bean的创建方式和生命周期,跟并发性不无联系。一般状况,服务的缺省scope是Singleton,scope的值包括:

    • prototype:新实例/注入时
    • request:新实例/request
    • flash:新实例/flash
    • flow:新实例/flow
    • conversation:新实例/conversation
    • session:新实例/session
    • singleton(缺省):自始至终一个实例

    改变缺省的Scope(在服务定义中)增加:static scope = "以上之一"。

  • 在Domain Class中如何注入一个服务?Servlet中如何做呢?

    用法:

    1 def bookService //对应BookService

    在Servlet中,可以通过Spring ApplicationContext的getBean方法获取到Service的实例:

    1 //以BookService为例
    2 BookService sc= (BookService)ApplicationHolder.getApplication()
    3 .getMainContext().getBean(bookService);
  • 我想在服务中使用Grails的createLink方法,该如何做?

    在Service中可以这样做:

    1 def g = new org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib()
    2
    3 //获得绝对link为:http://localhost:8080/jqac/role/index
    4 def absoluteLink = g.createLink(controller: 'role' , action: 'index' ,absolute: "true" )
    5
    6 //获得相对link为:/jqac/role/index
    7 def relativeLink = g.createLink(controller: 'role' , action: 'index' )

测试

  • 在单元测试中如何添加配置项?
    1 import org.codehaus.groovy.grails.commons.ConfigurationHolder
    2 //添加配置项
    3 mockConfig '' '
    4 you.test.configitem = "groovyq"
    5 '' '
    6 //获取配置项
    7 ConfigurationHolder.config.you.test.configitem
  • 请解释一下单元测试中mockDomain()的作用。还有其他做法可以替代这个方法么?

    在单元测试时,可以使用这个方法对Domain Class 进行Mock,用于模拟Domain Class。替代用法是使用mockFor。

  • Grails支持4中测试类型,请简单描述一下。
    • unit:单元测试类型
    • integration:集成测试类型
    • spock:这是Spock插件 添加的测试类型,可用于unit、integration和functional测试阶段。
    • 自定义:可自定义测试类型,具体参见Custom Grails Test Types/Phases
  • 我想在测试中模拟一个发送给Controller的XML文件,该怎么做?
    1 controller.request.contentType = 'text/xml'
    2 controller.request.contents = '' '
    3 <?xml version= "1.0" encoding= "ISO-8859-1" ?>
    4 <book>
    5 <title>The Stand</title>
    6 ...
    7 </book>
    8 '' '.getBytes()
  • applyTemplate方法是干什么用的?在测试中使用它的目的是什么?

    该方法可以直接获得标签库的结果,可对页面元素进行测试,通常用于集成测试。

  • 什么是页面对象?哪个Grails插件提供了页面对象的支持?

    页面对象表示应用中特定的页面,其中定义了方法和属性,以便于测试与页面进行交互。

    Selenium RC插件 提供了页面对象的支持。关于它的使用,请参见本站的用Selenium RC插件测试远程应用

  • 我想将测试结果显示在Console中,该怎么做?

    缺省况下,Grails不会在控制台上输出测试类中的log.info/print/println,如果希望显示,可以使用-echoOut和-echoErr参数,用法如下:

    1 grails test-app -echoOut -echoErr
  • 假如,我想在测试中执行one single method ,该怎么做?
    1 //测试SimpleControllerTest中的testLogin方法
    2 grails test-app SimpleController.testLogin

    『编者注』:one single method 这里提供的用法有误。

关于Grails的测试细节,亦可参见Grails 1.2参考文档速读(17):测试

插件

  • 请解释一下Grails应用跟Grails插件的区别。

    Plugin是Grails的主要扩展点,其工程跟普通Grails工程并无区别,只是多了一个描述文件。描述文件位于位于工程根目录,是以 GrailsPlugin结尾的Groovy文件。同时,工程中缺省没有URL Mappings,因此Controller无法马上工作,如果需要则必须手工添加该文件。

  • 什么是in-place插件?哪里定义它?

    in-place插件就是无需更新,直接生效的插件。在主工程的BuildConfig.groovy中添加:

    1 grails.plugin.location. "my-plugin" = "../my-plugin"

    亦可参见本站的《如何把应用划分成插件?》

  • 如何获得Grails中所有插件的列表?

    使用命令:grails list-plugin

  • 我想用插件来维护数据库结构的一个记录。我应该考虑哪些插件?你会选择哪个?

    可以考虑LiquiBase 或者Autobase ,推荐使用LiquiBase,这是数据库迁移的官方插件。

  • 我想用插件来帮我管理CSS和javascript文件。你的选择是什么?

    可以使用resources 插件。

  • 我想通过插件来设置可运行的浏览器测试,你的建议是什么?

    建议使用Geb

  • 我已经创建了世上最酷的的插件,请问该怎么将这个插件提交到Grails资源库中?

    使用命令:grails realse-plugin

  • 如何提交一个位于Github上的插件,这个插件在Grails插件SVN中没有拷贝。

    使用zipOnly参数,仅在SVN中保存插件的zip文件以及元数据(plugin.xml):

    grails release-plugin -zipOnly 
  • 你如何测试Grails应用的代码质量以及覆盖率?

    使用GMetrics 对代码质量进行分析,使用Clover Code Coverage for GrailsCobertura 分析代码覆盖率。

  • 你熟悉的哪些RIA技术在Grails中可以使用?

    Flex插件ULC插件ZK插件

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics