Grails 1.2参考文档速读(20):终章

不知不觉间已经到了本系列的最后,在这一节里,我们将看到如何在Grails中使用Web服务,了解其与Spring和Hibernate相关的配置,以及关于脚手架和部署有关的内容。
Web服务如今已经成为潮流,不论你是否愿意,只要你还在开发应用,你就得去适应它。Grails支持:
  • REST,针对Controller,通过URL Mapping,每个HTTP方法对应一个Action
  • SOAP,通过plugin完成
  • RSS/ATOM,通过Feed plugin
实现Restful的服务在Grails中简直就是小菜一碟,通过URL Mapping就可以将一个普通的Controller暴露为一个Restful服务:
static mappings = {
   "/product/$id?"(resource:"product")   
}
缺省Http方法和Action的对应关系:
  • GET:show
  • PUT:update
  • POST:save
  • DELETE:delete
如果你不满意,也可以自行调整:
"/product/$id"(controller:"product"){
    action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"]
}
但是该方法不会像前面一样自动进行JSON/XML的Marshalling,除非在映射中指明parseRequest参数:
"/product/$id"(controller:"product", parseRequest:true){
    action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"]
}
客户端调用Restful服务的方法也不复杂:
  • 使用Groovy HTTPBuilder:
    import groovyx.net.http.*
        import static groovyx.net.http.ContentType.JSON
        
        def http = new HTTPBuilder("http://localhost:8080/amazon")
        
        http.request(Method.GET, JSON) {
            url.path = '/book/list'
            response.success = {resp, json ->
                json.books.each { book ->
                    println book.title
                }
            }
         }
  • 从浏览器发起非GET/POST方法:
    <g:form controller="book" method="DELETE">
关于XML Marshalling:
  • 读:可以参见这里
  • 写,步骤1:传入xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
        <product>
            <name>MacBook</name>
            <vendor id="12">
                <name>Apple</name>
            </vender>
        </product>
  • 写,步骤2:数据绑定
    def p = new Product(params['product'])
        p.save()
实现SOAP服务是通过XFire Plugin实现的,它可以把Service暴露为Web服务:
class BookService {  
    static expose=['xfire']
    Book[] getBooks(){
    Book.list() as Book[]
  }
}
如果想知道它的wsdl,可以访问:http://127.0.0.1:8080/your_grails_app/services/book?wsdl
同样,对于RSS/Atom的支持,Grails也是通过插件:Feed Plugin。它底层使用的是ROME库:
def feed = {
    render(feedType:"rss", feedVersion:"2.0") {
        title = "My test feed"
        link = "http://your.test.server/yourController/feed"
        Article.list().each() {
            entry(it.title) {
                link = "http://your.test.server/article/${it.id}"
                it.content // return the content
            }
        }
    }
}
Spring应用中都会使用到ApplicationContext,Grails是一个Spring应用,当然也不例外,其中的ApplicationContext构造过程如下:
  • 从web-app/WEB-INF/applicationContext.xml构造父ApplicationContext,它会构造出GrailsApplication和GrailsPluginManager。
  • Grails利用GrailsApplication分析出惯例,然后构造子ApplicationContext,它作为Web应用的根ApplicationContext。
Grails的配置很多时候都发生在运行时,每个插件会给ApplicationContext注册一些Bean,关于这请查阅相关文档。当然,如果你对其最终的ApplicationContext感兴趣,不妨试试Spy插件,本站对它已有 介绍。
Grails并没有堵塞你自行定义Spring配置文件的道路,如果你想补充进行额外配置:
  • 方法1:grails-app/conf/spring/resources.xml
  • 方法2:grails-app/conf/spring/resources.groovy。这除了享受到groovy语法,还可以结合“环境”。
在配置文件中可以引用Grails中的对象,如dataSource、sessionFactory。Grails还引入了Bean DSL,例子:
import grails.util.*
beans = {
 switch(GrailsUtil.environment) {
  case "production":
   myBean(my.company.MyBeanImpl) {
    bookService = ref("bookService")
   }
  break
  case "development":
   myBean(my.company.mock.MockImpl) {
    bookService = ref("bookService")
   } 
  break
 } 
}
这种DSL一般规则:
  • 方法名为bean名
  • 第一个参数为Bean的类名
  • 闭包定义bean相关的属性
  • 第一个参数和闭包之间是构造函数的参数
  • 通过bean名即可引用Bean
这部分功能,即Bean Builder,亦可单独使用,在参考文档中给出了在Spring MVC应用中使用它的例子,这里就不重点阐述了。
Bean DSL的常见例子:
  • 构造函数
    exampleBean(MyExampleBean, "firstArgument", 2) {
            someProperty = [1,2,3]
        }
  • 工厂方法
    exampleBean(MyExampleBean) { bean ->
            bean.factoryMethod = "getInstance"
            bean.singleton = false
            someProperty = [1,2,3]
        }
  • Factory Bean
    repositoryService(org.jbpm.api.RepositoryService){ bean->
            bean.factoryBean = "processEngine"  
            bean.factoryMethod = "getRepositoryService"  
        }
  • 动态创建
    "${beanName}Bean"(MyExampleBean) {
            someProperty = [1,2,3]
        }
  • 匿名(内部)Bean
    marge(Person.class) {
            name = "marge"
            husband =  { Person p ->
                name = "homer"
                age = 45
                props = [overweight:true, height:"1.8m"]
            }
            children = [bart, lisa]
        }
  • 抽象Bean和父Bean定义
    abstractBean(KnightOfTheRoundTable) { bean ->
            bean.'abstract' = true
            leader = "Lancelot"
        }
        quest(HolyGrailQuest)
        knights("Camelot") { bean ->
            bean.parent = abstractBean  <-注意
            quest = quest
        }
Spring的配置文件中可以使用XML的名字空间,在Bean DSL中也可以:
  • 声明:xmlns context:"http://www.springframework.org/schema/context"
  • 使用(component-scan是context名字空间中定义的标签):context.'component-scan'( 'base-package' :"my.company.domain" )
名字空间使用例子
xmlns aop:"http://www.springframework.org/schema/aop"
aop { 
   config("proxy-target-class":true) { 
       aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { 
          after method:"onBirthday", 
                pointcut: "execution(void ..Person.birthday()) and this(person)" 
       } 
   } 
}
此外,我们还可以在Spring配置文件中使用Grails Config文件中定义的变量,配置文件中定义的脚本变量都可作为grails-app/conf/spring/resources.xml中的占位符
  • Config
    database.driver="com.mysql.jdbc.Driver"
        database.dbname="mysql:mydb"
  • Resources.xml
    <bean id="dataSource" 
       class="org.springframework.jdbc.datasource
                        .DriverManagerDataSource">
       <property name="driverClassName">
           <value>${database.driver}</value>
       </property>
       <property name="url">
           <value>jdbc:${database.dbname}</value>
       </property>
     </bean>
如果你想覆盖缺省的配置,可以按下列格式:
[bean name].[property name] = [value]
Grails中对于Hibernate的处理与Spring的非常类似:
  • 配置文件:grails-app/conf/hibernate/hibernate.cfg.xml
  • 映射文件:grails-app/conf/hibernate
Grails中还考虑到了你的现有代码资产,重用现有Domain Class(Java类):
  • 步骤1:配置文件和映射文件复制到相应目录
  • 步骤2:复制Java代码 => src/java
Grails也支持使用注解创建Domain Class:
  • 在src/java中创建java类,在类中使用注解
  • 注册
    <!DOCTYPE hibernate-configuration SYSTEM
    "http://hibernate.sourceforge.net/
               hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
        <session-factory>
            <mapping package="com.books" />
            <mapping class="com.books.Book" />
        </session-factory>
    </hibernate-configuration>
如果你想改变配置文件的位置,在DataSource.groovy中:
hibernate {
 config.location = "file:/path/to/my/hibernate.cfg.xml"
}
配置文件也可有多个:config.location = ["file:/path/to/one/hibernate.cfg.xml","file:/path/to/two/hibernate.cfg.xml"]
Grails的脚手架提供的功能:
  • 需要的view
  • Controller中与CRUD对应的Action
激活脚手架很简单,设置Controller的scaffold属性:
  • Controller名字和Domain Class名字相同时:def scaffold= true
  • Controller名字和Domain Class名字不同时:def scaffold= domain class name
至于其他需要知道的知识:
  • 可以添加其它Action
  • 覆盖脚手架产生的Action就是定义与之名字相同的Action。脚手架产生的Action有list、show、edit、delete、create、save、update
  • Domain Class的约束会对View产生影响,属性在约束中出现的顺序,也是它们在View中出现的顺序。
脚手架相关的命令:
  • generate-controller DomainClass名
  • generate-views DomainClass名
  • generate-all DomainClass名
如:grails generate-all com.bookstore.Book,建议使用包名。
如果想自定义模板:
  • 先安装模板:grails install-templates
  • 再修改模板:src/templates
跟部署相关的命令有:
  • grails run-app,它有两个环境变量:disable.auto.recompile,关闭检查;recompile.frequency,设置检查的秒数,缺省为3
  • grails run-war,运行的是war,会关闭reload
grails war比较特殊,有必要单独说明:
  • 改变缺省war的目录:方法1:grails war path;方法2:修改grails-app/conf/BuildConfig.groovy中的grails.war.destFile = "foobar-prod.war"
  • 缺省包含的lib:grails必需的lib+工程lib+插件lib
  • 如果你想自行定义相应的lib,那么修改BuildConfig.groovy,相关的属性:grails.war.dependencies、grails.war.copyToWebApp、grails.war.resources

你可能感兴趣的:(职场,grails,web服务,休闲)