`
friendsys
  • 浏览: 339186 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Groovy_and_Grails_Recipes Grails部分

阅读更多
Grails部分

在定义action时候.
def index={render "Hello World"} 将会被输出到请求的返回结果页面上.类似在Servlet的Response流里面写入
其中index是url中的action为空时候 默认的action

修改默认主页跳转的两种方法,分为客户端和服务端

1:客户端<meta http-equiv="refresh" content="0;URL=main"> 表示页面自动跳转到URL
2:服务端 修改URLMappings.groovy  加入"/"(controller:'main',action:'index')

在Gsp中 也可以使用<%%>包含Groovy代码,输出到页面的时候可以使用out<<内容, 用于显示到页面上
也可以使用<%= %> 以及<%@page %>等属性

不建议使用上面的标签,会导致页面上代码过多,还是使用gsp标签,以及后台逻辑好些

action可以传递值给view的Gsp
[date:new Date()]   gsp中 ${date} 进行访问

如果没有明确的返回一个对象,那么view中将可以访问到Controller中的属性(这里并不明确,例子里面的格式和上面相同,

区别在于,一个使用了map的方式返回,一个没有明确的使用map,而是简单的使用一个闭包的最后一行的方式返回)

标签中的方法也可以直接在Controller中使用
def date = g.formatDate(format:"yyyy-mm-dd",date:new Date())

Controller中的默认URL请求处理规则(即:url中的action部分为空)

1:如果只有一个action,那么默认请求将会使用这个action
2:如果index已经定义,那么将会使用index该action
3:如果有def defaultAction="listGroovyTopics" 这个属性定义,那么将会跳转到该action

Controller或者Gsp中可以访问的域
ServletContext,session,request,params,flash. 其中应该都是使用map的键值对保存值,所有可以直接用.key或者[""]

访问

在action可以通过 def topics = session."$params.for"

redirect 用于在action中发起页面跳转,包括的参数如下

uri 完整的url地址去跳转
url 相对的url地址去条状
controler 指定的Controller条状,默认是当前
action 跳转的action
id 使用的ID属性
params 传递的参数
fragment 使用#号所代表的锚点

render方法,可以不使用Gsp去渲染页面,而是直接使用返回的数据流,可以用于Ajax部分,参数列表如下
text: 代表要输出的内容
Builder:要使用的Builder
view:用于显示的view
template:用于显示的模板
var:传递到模板的参数
bean:在显示时用到的bean
model:作用同上
Collection:传递到模板的集合
contentType:Response的类型
encoding:Response的编码
converter:
plugin:..

使用chain用于连接多个action,参数列表如下
uri: 一个完整的URL去转发
action :一个action转发, action和uri需要存在一个
model:用于传递的参数 必须的
id:用于设置ID属性 可选的
params:用于传递的Parameters
Controller:用于转发的Controller,可选的

在Controller中建立Interceptor拦截器,区别于Filters,只作用于一个Controller

使用beforeInterceptor属性定义一个Before拦截,可以使用only的key指定一个方法名的list用于作用拦截,也可以用

except单独指定一组例外,默认是作用全部action

使用afterInterceptor用于定义后拦截,其他属性类似,不过指定的方法中,可以有一个参数用于接受返回结果map形式

例子如下
                       //用于拦截的方法           //被拦截的方法
def beforeInterceptor=[action:this.&authenticate,only:['compose','subie']]
def authenicate={...}
这里需要注意的是,afterInterceptor使用的是方法,而&符号却又是将方法做成closure使用的,所以BeforeInterceptor也

可以使用方法的格式进行定义...以后使用的时候可以关注下

Command Object class 类似Domain class, 可是却不保存到数据库中,类似以前Struts1中的formBean

使用Json格式返回数据
render(contentType:"text/json"){
  forum{
     post(key:value,key1:value1)
}}
返回的格式将是会 {"forum":[{"key":"value","key1":"value1"}]}

将Domain Class转换成Json返回 直接在Domain的实例上 post, 返回的时候 render post as XML 或者JSON 也可以使用

动态的方法encodeAsXml 和encodeAsJSON

上传文件的设置 
<g:form action="submit" method="post" enctype="multipart/form-data"> 关键还是最后一个的参数
<input type="file" name="post.myFile"> //这里就是普通的html,其中post为Command object myfile使用def声明

服务端保存的时候,
if(!post.myFile.empty){
post.myFile.transferto(new File("path...."+post.myFile.originalFilename))
}

下载的话
def download={
def file = new File("c:/...pdf") //服务端路径
byte[] bytes = file.readByte()
response.contentType="application/pdf"
response.outputStream << bytes
}

Templates模板,主要指可重用的页面部件,一般以_开头的文件名
在页面上使用的时候
<g:render template="displayTopics" var = "topic" collection='${session."${params.forumName}"}'>

如果将template都移动到一个文件夹中,其他地方进行引用的时候需要注意以/开头,如/template/displxxx
也可以在Controller中使用模板,常用于Ajax的操作(类似Asp.net的Ajax)
def index={render(template:"displayTopics",var:"topic" collection:session."${params.forumName}")}

Grails使用SiteMesh用于控制页面的布局,都放置在views/layouts文件夹下,默认使用main.gsp作为模板
最重要的几个属性
layoutTitle: <title>标签
layoutHead:<head>标签
layoutBody <body>标签

在其他页面需要使用这个布局的时候
<meta name="layout" content="main">

如果建立layout在views/layouts/文件夹下,那么所有的Controller都可以使用,如果在专门的Controller对应的

views/layout/Controller_Name/的文件夹就只能该Controller使用

意思就是会自动将对应的html块的内容添加到layout页面的指定标签处

创建用户自定义标签
使用Create-tag-lib  建立在 taglib文件夹下,使用的方式也是closure

def editor = {attrs, body ->
out << render(template:"/editor",model:[key:attrs.key..])
}
使用的时候<g:editor> 传入的属性都可以用上面的attrs进行访问,
这里的例子是使用模板生成html元素
g是指默认的命名空间,如果要使用新的NameSpace,可以在lib类里面定义一个
static namespace = "custom"  然后使用的时候就可以代替g

过滤器,创建会生成与grails-app/conf文件夹下(Intellij下似乎没有直接的生成方式)
生成的格式
class fourmFilters{
  def filters={}  //过滤器都写在这个闭包之中
}
过滤器类型分为三种 before after afterView, 使用时候,都使用关键字进行定义
def filter = {
compose(controller:'*',action:'compose')
{
before = {...}
}}
注意filter中可以访问到绝大多数的域

Ajax的使用 ,内嵌了prototype
添加脚本到页面上可以直接使用 <g:javascript library="prototype">

使用的时候可以用<g:formRemote>标签,例子如下
<g:formRemote name="myForm" url="[action:'submit']" enctype ="mulipart/form-data"

update="[success:'message',failure:'error']">

Command Object的赋值操作
PostCommand post = new PostCommand(params['post']) //用于将页面元素的post.x属性封装成PostCommand对象

会异步的提交数据,成功后会显示信息在message 的div中

render "xxx message" 用于在服务端返回结果

还有其他的Ajax标签
g:rmoteLink 用于创建一个异步的http请求 action
g:submitToRemote 用于创建一个异步的提交按钮

标签中都可以指定回调事件监听函数,用于在不同结果时候进行调用,方式和普通的html标签相同
<g:remoteLink action="..." onLoading="showP(e)"> //这里可以创建一个参数给JavaScript函数,不知道其他的参数

在运行和打包的时候,需要注意加入环境的类型,用于区别不同的环境,默认是dev开发环境
grails prod run-app 表示生产环境  dev为开发 test为测试

也可以使用自己的环境运行
grails -Dgrails.env=staging run-app  其中staging为自定义环境

一些连接的属性
polled为 是否使用连接池,默认为true
logSql为 开启去显示Sql日志
dialect 为设置Hibernate的dialect属性

使用GrailsUtil类输出环境属性
println grails.util.GrailsUtil.environment

在Domain Class中

mapping 用于修改默认的表和Bean   主要是自定义映射的表名和列名或者类别
static mapping={
table 'forums'
name cloumn:'forum_Name'
lastPost type:'timestamp'  // 第一个:属性 第二个:类别 第三个:数据库属性
}

static constraints={} 用于设置验证用途,非空等属性

static transients=[] 属性用于设置不保存到数据库的属性Set

配置映射关系
主要就是hasMany和belongsTo
static hasMany=[topics:Topic] 后者为类名,前者为会生成的List集合,用于表示拥有多个改对象,放在一方
static belongsTo=[forum:Forum] 表示属于Forum类型对象,实例名为forum 放在多方

设置级联 在mapping中
static mapping = {
topic cascade:"all,delete-orphan" //其中这里的topic为Set 即一方中多方的集合
}

如果需要排序 可以使用SortedSet 并且在多方的bean中实现Comparable接口

这里也涉及到一点,定义在一方属性中
SortedSet topics
static hasMany=[topics:Topic]
替换掉默认的Set类型的集合

也可以使用同样的方式,用List代替set

默认情况下,都使用延迟加载集合对象,每次查询集合中的对象的时候,都会生成一条新的SQl语句
访问Bean中集合属性的方法  bean.each.topics{ println it.属性}

使用批量查询等同于关闭延迟加载
批量设置 static fetchmode=[topics:'eager']
延迟设置 static mapping={topics lazy:false}

设置一对一的话,只要在任意一方约束对象属性唯一即可
static constraints={bean(unique:true)}

不过这样设置,级联默认为关闭着

如果需要设置开启的话,需要在另一方进行而外的设置,不直接设置实体Bean,而是使用belongsTo
static belongsTo=[user:User]

建立多对多关系,就是在两遍都是用hasMany声明对方的属性,并且在一方设置belongsTo属性

使用内嵌的Embed的类,用于减少一个类的大小,这个额外的属性,并不会去创建一张新表
在主类中使用
Address address //其中address为附表的实例
static embedded=['address']

如果需要设置显示Hibernate生成的SQl语句,那么可以在使用console命令,显示控制台,并且在DataSource.groovy文件中

设置logSql=true

如果要接受执行Gorm操作的过程中抛出的错误,可以通过判断.save()等方法的返回值来进行判断

if(!bean.save()){
   bean.errors.each{println it} //用于进行错误的输出
}

也可以给sava方法传入参数,保证马上就刷新操作
forum.save(flush:true)

可以使用addToXX在新建对象的时候,同时新建其中的Set外表Bean

可以使用forum.topics.find{it.xx=="xx"}的方式,用于执行Sql查询,//topic为一个Set集合对象
        forum.removeFromTopics(topic1) 不过将不会从数据库中移除该对象,只会在查询结果中设置为null,需要额外 

      的设置
static constraints = {
  forum(nullable: true)
}

执行查询,比较常用的就是list,可以使用在方法的参数里面使用键值对的方式传入不同的查询条件
max: 返回的最大条数
offset:在结果中开始位置
order:结果排序的类型: desc or asc
sort:用于排序的属性
ignoreCase: 默认为true.用途暂时未知
fetch: 默认lazy, 可选为eager,用于设置延迟加载的策略
类级别的方法
def list = Topic.list(offset:5,max:10,sort:"date")

也可以使用listOrderBy* 来用某个属性代替*表示根据指定属性排序返回结果
Forum.listOrderByName()

也可以使用getAll返回指定id主键的对象
def topics = Topic.getAll([1,2,3])

Forum.exists(1) 其中1是id属性来判断对象是否存在
Forum.count() 查询数据库中实例的数量

动态查询.使用动态的方法名执行查询,注意语法的顺序 固定的部分主要为findBy 和findbyall, 用于返回一个或者多个

结果的区别,都是类级别的查询

Domain_class.findBy<属性1><比较语句><布尔操作(or,and)><属性2><比较语句>("具体参数",[其他参数max等])

其中的语句为固定的12个 基本就是< > >= 此类的操作符的E文格式
LessThan  lessThanEquals GreaterThan

GreaterThanEquals,Between,Like,Ilike,IsNotNull,IsNull,Not,Equal,NotEqual
其他的参数都是[]原有的条件,对于结果的约束
例:
Topic.findAllByMessageIlikeAndDateGreaterThan("%abc%",date) 

比较特殊的还有countBy*,只返回符合结果的数量
例:
Forum.countByNameIsNotNull()....

GORM使用HibernateCriteriaBuilder 的方式去构建Criteria的查询

通过使用很多不同类型的Nodes来提供条件,生成查询语句
例:
def c = Forum.createCriteria()
def results = c{
ilike("description","%gg%")
and{
  between("lastPost", new Date()-7,new Date())
  isNotNull("name")
}
maxResults(10)
order("name","desc")
}

就是通过类似方法调用的形式,去生成SQl语句

看demo ,都需要先创建一个Criteria,然后在对象上执行查询
def c = Forum.createCriteria() //用于生成一个对象

def results = c.scroll{}
这里的scroll操作起来类似ResultSet

执行HQl的方式
可以直接使用 Forum.findAll(HQL) 方式执行查询 其中HQL的语法照常
也可以使用def results = Forum.executeQuery("HQL",[date:new Dae],[max:10,offset:0])
用于执行带参数的HQL,第一个为带:参数的HQL语句,第二个为指定命名参数的值,注意map格式,第三个查询结果的条件

使用继承
如果简单的使用继承建立两个类的关系
那么在数据库中只会自动生成一张表,然后通过一个专门的列(Class)来保存类名,用于辨别不同的类型,而自动
生成的表名为父类的名称
进行保存的时候,需要用子类开始
new Topic(subJect:"..." //子类属性).addToPosts(new Post(message:"ass")//父类完整对象).save()
用于生成对象

查询的时候,会根据查询发起类的不同,而查询不同的结果,父类包含了子类

如果要创建两张表的形式,可以使用建立映射关系管理
在父类表中,配置mapping
static mapping = {tablePerHierarchy false}
子类表中
static hasMany = [posts : Post]

使用乐观和悲观锁

在GORM中默认使用了乐观锁,也就是默认创建的version列,在进行更新操作的时候,Hibernate会自动进行version
的验证,如果不符合,就会抛出异常,同时将数据roll back,并且抛出一个异常.

可以在mapping中设置 version false 用于关闭检查

悲观锁, 直接在查询结果的对象上 forum.lock() 锁定对象,默认使用LockMode.UPGRADE的锁类型,指导事务提交,才会自

动解锁 (PS:内嵌的数据并不支持悲观锁)

Domain的event事件
1:beforeInsert
2:beforeUpdate
3:beforeDelete
4:onLoad

比如可以用于自动生成更新的时间
用闭包设置在Domain Class中
def beforeInsert= {...//可以直接操作属性,进行修改}

需要注意 在执行操作的时候,GORM会先执行验证对象是否符合constraints设置,然后再执行事件方法,如果不能为

nullable的对象,将会执行失败,可以设置nullable:true,也可以在执行方法的(validate:false)

如果在Domain Class中定义
Date dateCreated
Date lastUpdated
那么GORM将会在执行insert和Update自动进行更新
可以通过设置 mapping中的autoTimestamp false

使用默认的设置就可以,然后在需要的Domain class设置 mapping里cache true,也可以设置其他更多相关属性

class Forum{
  static mapping = {
cache usage:'read-only',include:'non-lazy'
topic cache:false //用于设置cache不保存该集合
}}

自定义不同的主键策略,在类中重写id,以及Mapping,默认为native
String id
static mapping={id generator:'uuid'}

可以使用关键字输出主键,而不用关心主键名称
例: forum.ident()

可以通过mapping 里面设置 id composite:['属性1','属性2'] 建立复合主键,不过不建议使用

创建index索引 给指定的属性
例:
String name
static mapping = {name index:'name_index'}

自定义验证,在Domain Class中,其中message是属性
static constraints = {
message(blak:false,maxSize:1000,vilidator:{val,obj -> return val!=obj.subject})
}
如果要设置对应的错误信息可以在Properties文件中
topic.message.validator.error=....  //类名.属性.验证类型.error..

其中验证类型包括了blank等

测试国际化的时候,可以在url里面进行修改,用于模拟专门的国际化
http://127.0.0.1:8080/Forum/?lang=de  //模拟德语
只需要传递一次lang,因为数据将会保存在Session中

可以使用在constraints中设置不同的属性,改变views自动生成的视图(包括了属性顺序以及编辑器类型)
比如 inList 和 range就会使用下拉列表select来生成html组件
设置maxSize 就会生成合适大小的TextArea
日期Date 就会使用Grails的日期组件生成

Grails的Domain class使用constraints属性设置的验证
Blank:非空白""
creditCard:信用卡号码
email:Email
inList:使用List保存
matches:必须匹配给定的正则
max:最大值
maxSize:最大长度
min:最小值
minSize:最小长度
notEqual:不等于
nullable:不能为null
range:必须在指定的范围
scale:设置带小数点的数字
size:限制大小,可以作用与集合,数字,字符串
url:必须是URL
Validator:自定义约束,传入两个参数,返回一个Boolean值,用于判断是否通过,第一个参数为当前值,第二个对当前对象

错误的消息都会保存在error中,可以使用指定的Gsp标签进行输出
renderErrors : hasErrors,eachError

注意的是错误信息会附加在Domain Bean中
例:
<g:hasErrors bean="${forum}">
  <div class="errors">
<g:renderErrors bean="${forum}" as="list">
  </div>
</g:hasErrors>

如果要在页面上保留旧的值  可以在HTMl元素中设置
value="{fieldValue(bean:forum,field:'name')}"

可以通过任意Controller中设置动态Scaffold生成Controller,区别在于自动生成
def scaffold=Domain //主要还是scaffold属性, Domain为类名 无需扩展名

如果要在Controller中自定义错误信息
topic.errors.reject("资源文件中的key")
捕获的方式还是直接的使用hasErrors

Controller提供的action
list,show,edit,delete,create,save,update
也会自动生成四个页面 create,edit,list,show

修改自动生成的Scaffold模板
首先需要使用grails install-templates 加载模板

RichUI插件,提供了一些很漂亮的UI插件

如果需要使用Annotation的配置domain class, 需要在DataSource.groovy中进行设置
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
dataSource{
  configClass = GrailsAnnotationConfiguration.class
}

然后和设置普通的Hibernate的Annotation风格一样进行配置class

在grails-app/conf/hibernate去添加hibernate.cfg.xml
最后一步,通过命令,创建对应类的Controller和View部分
grails generate-all com.apress.groovygrailsrecipes.entities.User //其中user为类名

Grails不支持Hibernate的类与GORM的类进行关联
在Controller进行数据库操作的时候,需要注意防止SQl注入,其中之一就是主要生成HQL语句的模式,不能
直接使用字符串的拼接来进行,推荐使用
def user = User.find("from suer as u where u.pwd = : pwd",[pwd:params.password])
通过两个参数的重载,用于生成SQL语句

为了防止对跨站点的脚本注入(XSS attacks),在页面进行内容输出的时候,推荐使用
render topic.message.encodeAsHTML()  进行特殊字符的转译成&开头的字符

Grails内嵌了一些编码转成方法 使用encodeAs<编码类型>和decode<编码类型>
编码类型包括 HTML URL Base64 JavaScript

也可以创建的编码类型,放置在grails-app/utils
其中类名必须以Codec为结尾,而且需要实现static encode={} 或者 static decode={}
使用的时候,直接使用 xx.encodeAs类名()  //其中这里的类名部分可以去掉Codec

在Acion中限制能够访问的Http请求,并且返回指定的http错误码(403 禁止访问)
例:
if(request.method == 'GET'){
response.sendError(403)
}

或者使用Controller中的配置allowedMethods属性
def allowedMethods=[delete:['POST','DELETE']] //这里限制delete的action只能通过后面的两种http请求
也会自动返回403错误

可以在UrlMappings.groovy中配置指定的403错误页面

可以使用Interceptors 或者 filters实现简单的安全机制

在action进行redirect后,注意使用return防止进行执行,尤其使用filter时候,return false

使用Acegi (Spring Security),以及添加CAPTCHA(验证码)

1: grails install-plugin acegi  下载并且安装插件
2: grails create-auth-domains User Role  //这里一直会提示需要多一个参数
上面操作会生成四个新类,介绍如下

User.groovy  默认的用户类型,可以自定义添加属性,与Role有many to many 关系
默认属性: username 用户名
  password 密码
  realname 真实姓名
  email    Email地址
  enabled  表示用户状态(禁用否)
  emailShow 是否显示Email地址
 
Role.groovy 角色,比如管理员,会员等...

Requestmap.groovy 指定URL和角色映射,也就是指定用户才允许访问的URL,如/admin/**..

然后使用创建相关的管理组件,建立上面三个类对应的Controller和view
grails generate-manager

建立注册相关的组件,包括了验证码和Email验证激活用户
grails generate-registration

上面命令会创建两个Controller,用于注册和验证码,一个Service,用于创建EmailerService

然后使用clean清理资源后,开始run-app

//这里出现过包找不到的问题,不过重建工程后,使用控制台run-app就正常

可以在浏览器中创建Role角色,以及Role与URL的对应关系(Requestmap)
例: /user/** admin,moderator,user  用,隔开多个角色

Acegi下提供了一些Gsp标签

g:ifAllGranted  表示如果当前是允许的角色
g:ifAnyGranted  表示当前是任意一个允许的角色
g:ifNotGranted  如果不允许当前角色
g:loggedInUserInfo  当前登陆用户信息
g:isLoggedIn  只有用户登陆才显示
g:isNotLoggedIn 表示没有用户登陆

可以使用Acegi提供的AuthenticateService用于在自定义的Controller中判断用户信息
例:
class CheckController{
   AuthenticateService authen
   def index={
def user = authen.userDomain()
if(user == null){
...
}else{
user.getAuthorites()
}}}

OpenID  用于在多个网站之间共享用户名的方法

可以下单独的插件,也可以选择使用Acegi,已经内嵌了对OpenId的支持
如果要开启支持,需要修改conf/SecurityConfig.groovy
添加 useOpenId = true

然后在创建用户的地方使用在url中加入用户名 https://me.yahoo.com/<username>  然后输入id就可以进行直接登陆

Testing

Grails提供了三种测试方法
1:Unit tests: 单元测试
2:Integration tests: 集成测试 和内存数据库一起进行测试
3:Functional: 逻辑(功能)测试,使用Cannoo WebTest plug-in进行浏览器内的测试

建立单元测试,会保存在test/unit 文件夹中,文件名以test开头
grails test-app -unit  //执行单元测试,也可以在后面指定Domain Class名用于单个单元测试 空格分开

使用MetaClass 去模拟对象,进行测试 如果是static的需要在方法名之前加上
Topic.metaClass.static.delete={....} //注意最后一行返回 ,这个修改也可以使用在实例上

测试后将会在test/reports/html/index,html 查看测试结果,以及错误内容

建立集成测试(包括了使用数据库,以及使用到了Grails环境)
大体个Unit测试一样,就是命令 -integration的区别

测试render和redirect方法
通过Controller类的实例,直接调用对应的action,然后判断实例的固定属性

vfc.response.redirectedURL //vfc为Controller实例,测试redirect方法
vfc.response.contentAsString //判断返回值 render方法,只适用简单的render "xxx"

当复杂的 render (view:"success",model:[message:"Topic ps"])
测试时候判断 vfc.modelAndView.model.message 进行判断返回值内容

测试Tag Libraries 标签库
使用继承grails.test.GroovyPagesTestCase 进行测试
其中需要测试的方法名也需要以test开头
例:
void testConvertTemperature(){
def template = '<g:converTemp temperature="${temp}" from="${from}" />'
def fromFahrenheit = applyTemplate(template,[temp:'75',from:'f'])
}
fromFahrenheit 的值就是会在页面上进行输出的值,从而进行判断

使用DomainBuilder构建Domain class的测试,可以很方便的创建复杂类型的Domain class 实例

def builder = new DomainBuilder()
def groovyForum = builder.forum(name:"xx",desc="00"){
topic(subject:"aa",...)
}
这里forum为Domain class 使用{进行集合的设置}

需要注意的是,这样并不能测试Validator的验证信息,以及不会在控制台输出测试过程,如果需要查看结果
需要看生成的html和txt文件

安装 grails install-plugin webtest

建立测试用例 grails create-webtest forum //forum为Domain Class名
这种测试的代码量比较多, 可以使用Firefox的插件WebTestRecorder来进行辅助

使用Service 保存在grails-app/Services中
创建 grails create-Service <Service_name>

比如创建一个AuthenticationService后
只要在需要用到的地方 def authenticationService 就会自动注入 (byName)

默认使用singletons,可以通过static scope=<scope_name>进行修改

transactional用于设置时候开启事务,方法级

Service主要作用就是将与Domain类无关的代码,移除到外部,从而减少Domain Class的大小

有两种方法可以在Grails中使用Spring的bean(DI)

1:直接配置grails-app/conf/spring下的resources.groovy
2:使用Grails的BeanBuilder 插入到上面的resources.groovy文件中

原来上传文件的代码
Topic topic = new Topic(params['topic'])
if(!topic.myFile.empty){
topic.myFile.transferTo(new File("/home/"+topic.myFile.originalFilename))
}
需要在Topic这个Domain Class中声明
def myFile

不过这样定义在单独的Controller并不合适,因为保存地址硬编码在类中,可以使用Service实现
class UploadService{
def uploadLocation  //这里定义为保存路径,使用Spring注入
def upload(def file){
file.transferTo(new File(uploadLocation + file.originalFilename))
}}

在resources.groovy中
beans={
uploadService(UploadService){
uploadLocation=config.upload.location
}}

然后在conf/Config.groovy中配置对应的属性
upload.location = "/home/bjawad/Desktop/"

在Controller中使用的时候
def uploadService
Topic topic = new Topic(params['topic'])
if(!topic.myFile.empty){
uploadService.upload(topic.myFile)
}

Grails中使用Log4j来管理日志记录 可以在grails-app/conf/Config.groovy来进行配置
默认会保存在stacktrace.log中

所有的Controller,domain classes Service,tag lib中都可以访问一个log方法,用于记录日志信息
log.debug "debug message" 
这里设置debug级别的信息,同时也可以设置其他级别 warn.

也可以在设置在不同环境下设置log4j的日志级别
在Config.groovy中
environments {
    development{}
    production {
        log4j.logger."grails..formCo"="all" //用于指定Controller的日志级别信息被记录到log文件中
    }
}

可以使用Grails下的Maven的插件提供支持

在action中可以使用 render xx as JSON (or XML) 进行数据格式的转换

CXF可以用于SOAP的搭建,不过目前没有直接的plugin,可以使用Service实现




















































分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics