锘??xml version="1.0" encoding="utf-8" standalone="yes"?>
class Something{
byte[] image
}
鎺у埗鍣ㄤ腑灞曠ず鍥劇墖鐨勬柟娉?/p>
def image= {
def something = Something.get( params.id )
byte[] image = something.image
response.outputStream << image
}
欏甸潰灞曠ず
<img src="${createLink(controller:'something', action:'image', id: something.id)}"/>
鍒?a >https://rome.dev.java.net/涓嬭澆Rome錛屼箣鍚庢妸rome-xxx.jar鏀懼埌浣犵殑grails欏圭洰鐨刲ib鐩綍涓嬨傝繖閲寈xx鏄増鏈彿銆傛瘮濡傛垜鐨勬槸rome-1.0RC1.jar
鍐嶅埌http://www.jdom.org/涓嬭澆JDom銆備箣鍚庡悓鏍鋒槸鎶妀dom.jar鏀懼埌lib鐩綍涓嬨?/p>
鍒涘緩涓涓猚ontroller錛屽綋鐒朵綘涔熷彲浠ュ湪浣犲凡緇忔湁鐨刢ontroller閲岄潰澧炲姞鐩稿簲鏂規硶銆傝繖閲屾垜浠垱寤轟竴涓彨鍋欶eedController鐨勭被銆?br />
涔嬪悗璁塊棶鐩稿簲鐨勯〉闈紝姣斿璇?a >http://www.ondev.net/feed/rss灝卞彲浠ヤ簡
鍘熻創鍦板潃錛?http://www.ondev.net/story/show/75
To install the YUI plugin type this command from your project's root folder:
grails install-plugin yui
To use Grails' adaptive AJAX support just add the folowing line in the head section:
<g:javascript library="yui" />
<yui:javascript dir="calendar" file="calendar-min.js" /> <yui:javascript dir="calendar" file="calendar-min.js" version="2.5.2" /> // version to be used in case multiple version installed <yui:stylesheet dir="calendar/assets" file="calendar.css" />
By default only yahoo-dom-event.js and connection-min.js are included when using <g:javascript library="yui" />. Adding additional libraries to the default list can be done in a BootStrap (+) class:
import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLibclass BootStrap { def init = { servletContext -> JavascriptTagLib.LIBRARY_MAPPINGS.yui += ["yui/2.5.2/calendar/calendar-min", "yui/2.5.2/container/container-min"] } def destroy = { } }
import grails.util.GrailsUtil import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLibclass BootStrap { def init = { servletContext -> if (GrailsUtil.isDevelopmentEnv()) { JavascriptTagLib.LIBRARY_MAPPINGS.yui = ["yui/2.5.2/yahoo/yahoo-debug", "yui/2.5.2/dom/dom-debug", "yui/2.5.2/event/event-debug", "yui/2.5.2/connection/connection-debug"] } } def destroy = { } }
It's also possible to serve the javascript from the Yahoo! servers. First delete the yui folder from web-appjs after installing the plugin. Then, in a BootStrap class, override the mapping which contains the javascript files to include by default:
import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLibclass BootStrap { def init = { servletContext -> JavascriptTagLib.LIBRARY_MAPPINGS.yui = [] } def destroy = { } }
If you want to upgrade:
class BootStrap {
def init = { servletContext ->
def user = new Users(id:1,username:'rain'
,password:'1102')
user.password = user.password.encodeAsPassword()
user.save()
}
def destroy = { }
}Between those three, you should have enough to figure things out. I still found it hard, despite those instructions and so to avoid having to figure things out again some time in the future, I'll write absolutely everything here.
Creating the Plugin
grails create-plugin SamplePlugin
Now you have a Grails plugin. However, at the same time it is just another Grails application, which means you can simply open it in NetBeans IDE. (I.e., there is no import process and no NetBeans artifacts are added to the plugin in order to be able to open it in the IDE.)
The Files window (Ctrl-2) however, shows a lot more:
Open the "SamplePluginGrailsPlugin.groovy" file and there you see the following:
class SamplePluginGrailsPlugin { def version = 0.1 def dependsOn = [:] def doWithSpring = { // TODO Implement runtime spring config (optional) } def doWithApplicationContext = { applicationContext -> // TODO Implement post initialization spring config (optional) } def doWithWebDescriptor = { xml -> // TODO Implement additions to web.xml (optional) } def doWithDynamicMethods = { ctx -> // TODO Implement registering dynamic methods to classes (optional) } def onChange = { event -> // TODO Implement code that is executed when this class plugin class is changed // the event contains: event.application and event.applicationContext objects } def onApplicationChange = { event -> // TODO Implement code that is executed when any class in a GrailsApplication changes // the event contain: event.source, event.application and event.applicationContext objects } }
I.e., you have hooks for integrating your code into meaningful places in the plugin.
import org.codehaus.groovy.grails.validation.AbstractConstraint import org.springframework.validation.Errors class BestFrameworkConstraint extends AbstractConstraint { private static final String DEFAULT_MESSAGE_CODE = "default.answer.invalid.message"; public static final String NAME = "oneCorrectResponse"; private boolean validateConstraint //The parameter which the constraint is validated against: @Override public void setParameter(Object constraintParameter) { if (!(constraintParameter instanceof Boolean)) throw new IllegalArgumentException("Parameter for constraint [" + NAME + "] of property [" + constraintPropertyName + "] of class [" + constraintOwningClass + "] must be a boolean value"); this.validateConstraint = ((Boolean) constraintParameter).booleanValue() super.setParameter(constraintParameter); } //Returns the default message for the given message code in the current locale: @Override protected void processValidate(Object target, Object propertyValue, Errors errors) { if (validateConstraint && !validate(target, propertyValue)) { def args = (Object[]) [constraintPropertyName, constraintOwningClass, propertyValue] super.rejectValue(target, errors, DEFAULT_MESSAGE_CODE, "not." + NAME, args); } } //Returns whether the constraint supports being applied against the specified type: @Override boolean supports(Class type) { return type != null && String.class.isAssignableFrom(type); } //The name of the constraint, which the user of the plugin will use //when working with your plugin. @Override String getName() { return NAME; } //Validate this constraint against a property value, //In this case, ONLY "Grails" is valid, everything else will cause an error: @Override boolean validate(target, propertyValue) { propertyValue ==~ /^Grails$/ } }
def doWithSpring = { org.codehaus.groovy.grails.validation.ConstrainedProperty.registerNewConstraint( BestFrameworkConstraint.NAME, BestFrameworkConstraint.class); }
grails package-plugin
Back in the IDE, examine the ZIP file that the above command created:
That ZIP file is your Grails plugin.
Installing the Plugin
Now we will install our plugin in a new application.
Thanks to "convention over configuration", Grails knows exactly where everything is鈥攕o that, for example, the "plugin.xml" file that you see above, if found within the folder structure you see above, is the indicator to Grails that a plugin is available for use.
Using the Functionality Provided By the Plugin
Note: The "oneCorrectResponse" constraint that you see above is the name of the constraint defined in the plugin.
Congratulations, you've created, installed, and used your first Grails plugin!
static constraints = {
login(length:5..15,blank:false,unique:true)
password(length:5..15,blank:false)
email(email:true,blank:false)
age(min:new Date(),nullable:false)
}
}
constraints蹇呴』澹版槑涓簊tatic銆?/p>
鍚屾椂錛屾瘡涓睘鎬х殑綰︽潫灞炴ч兘鏈変笌涔嬪搴旂殑閿欒娑堟伅錛圗rror message code錛夛紝褰撹〃鍗曟湭鑳介氳繃楠岃瘉鐨勬椂鍊欙紝灝嗕細榪斿洖榪欎簺閿欒娑堟伅銆?br />
榪欎簺閿欒娑堟伅鍦?strong>grails-app/i18n/message.properties閲屽畾涔夈?br />
渚嬪鎴戜滑瑕佽User鐨別mail涓虹┖鏃惰繑鍥?Please enter your email"錛屽垯鍙互鍦╩essage.properties瀹氫箟錛?br />
user.email.blank=Please enter your email
濡傛灉鐢ㄦ埛娌℃湁鑷畾涔夐敊璇秷鎭紝緋葷粺鍒欎細鐢ㄩ粯璁ょ殑璁劇疆銆傚綋鐒墮粯璁ょ殑娑堟伅鑲畾涓嶄細鏄綘鎯寵鐨?#8230;…
Grails鎻愪緵寰堝楠岃瘉灞炴э紝鍙互婊¤凍涓浜涘熀鏈殑楠岃瘉闇姹傦細
blank
楠岃瘉灞炴ц兘鍚︿負絀猴紝涓嶅厑璁鎬負絀哄垯璁句負false銆?br />
Note: 濡傛灉鍦╢orm閲屼負絀鴻屾彁浜わ紝鍒欏睘鎬х殑鍊兼槸涓涓┖瀛楃涓詫紝鑰屼笉鏄痭ull銆?br />
Example: login(blank:false)
Error message code: className.propertyName.blank
creditCard
濡傛灉瑕佹眰灞炴т負淇$敤鍗″彿鐮侊紝鍒欒涓簍rue銆?br />
Example: cardNumber(creditCard:true)
Error message code: className.propertyName.creditCard.invalid
email
濡傛灉瑕佹眰灞炴т負emial鍦板潃錛屽垯璁句負true銆?br />
Example: contactEmail(email:true)
Error message code: className.propertyName.email.invalid
inList
濡傛灉瑕佹眰灞炴х殑鍊煎繀欏諱負瑙勫畾鐨勫鹼紝鍒欏畾涔夎瀹氱殑鍊箋?br />
Example: name(inList:["Joe", "Fred", "Bob"] )
Error message code: className.propertyName.not.inList
length
綰︽潫瀛楃涓叉垨鑰呮暟緇勭殑闀垮害銆?br />
榪欎釜綰︽潫灞炴у湪0.5鐗堟湰鏄鍙栨秷錛岀敤size浠f浛銆?/font>
Example: login(length:5..15)
Error message code:
className.propertyName.length.toolong
className.propertyName.length.tooshort
matches
搴旂敤姝e垯琛ㄨ揪寮忓瀛楃涓茶繘琛岄獙璇併?br />
Example: login(matches:"[a-zA-Z]+")
Error message code: className.propertyName.matches.invalid
max
璁懼畾灞炴х殑鏈澶у鹼紝鍊肩殑綾誨瀷蹇呴』璺熷睘鎬т竴鏍楓?br />
Example:
age(max:new Date())
price(max:999F)
Error message code: className.propertyName.max.exceeded
maxLength
璁懼畾瀛楃涓叉垨鑰呮暟緇勭殑鏈澶ч暱搴︺?br />
鍦?.5鐗堟湰涓鍙栨秷錛岀敱maxSize浠f浛銆?/font>
Example: login(maxLength:5)
Error message code: className.propertyName.maxLength.exceeded
maxSize
璁懼畾涓涓暟瀛楁垨鑰呴泦鍚堢殑鏈澶уぇ灝忋?br />
鍦?.5鐗堟湰涓笉琚緩璁敤鍦ㄦ暟瀛椾笂錛屾敼鐢╩ax銆?/font>
Example: children(maxSize:25)
Error message code: className.propertyName.maxSize.exceeded
min
璁懼畾灞炴х殑鏈灝忓箋傜被鍨嬪繀欏昏窡灞炴т竴鑷淬?br />
Example:
age(min:new Date())
price(min:0F)
Error message code: className.propertyName.min.notmet
minLength
璁懼畾瀛楃涓插睘鎬ф垨鑰呮暟緇勫睘鎬х殑鏈灝忛暱搴︺?br />
鍦?.5鐗堟湰涓鍙栨秷錛岀敱minSize浠f浛銆?/font>
Example: login(minLength:5)
Error message code: className.propertyName.minLength.notmet
minSize
璁懼畾涓涓暟瀛楁垨鑰呴泦鍚堢殑鏈灝忓ぇ灝忋?br />
鍦?.5鐗堟湰涓笉琚緩璁敤鍦ㄦ暟瀛楀睘鎬т笂錛屾敼鐢╩in銆?/font>
Example: children(minSize:5)
Error message code: className.propertyName.minSize.notmet
notEqual
楠岃瘉灞炴х殑鍊兼槸鍚﹁窡鎸囧畾鐨勫肩浉絳夈?br />
Example: login(notEqual:"Bob")
Error message code: className.propertyName.notEqual
nullable
濡傛灉灞炴т笉鍙互涓簄ull錛屽垯璁句負false銆?br />
Note: 濡傛灉鍦ㄨ〃鍗曢噷鏈~浠諱綍涓滆タ鑰屾彁浜ゆ椂錛屽垯浣滀負request parameter錛屽睘鎬х殑鍊間負涓涓┖瀛楃涓詫紝鑰屼笉鏄痭ull銆?br />
Example: age(nullable:false)
Error message code: className.propertyName.nullable
range
闄愬埗灞炴х殑鍊煎湪鎸囧畾鐨勮寖鍥撮噷銆?br />
Example: age(range:minAge..maxAge)
Error message code:
className.propertyName.range.toosmall
className.propertyName.range.toobig
scale
鐗堟湰0.4鎵嶅紑濮嬪嚭鐜扮殑綰︽潫灞炴с?br />
鏍規嵁璁懼畾鐨剆cale鏁板鹼紝鑷姩鎶婃誕鐐瑰瀷鏁板瓧灝忔暟鐐瑰悗鐨勪綅鏁拌皟鏁翠負璁懼畾鐨勫箋?br />
閫傜敤浜庝互涓嬫暟鍊肩被鍨嬶細java.lang.Float, Java.lang.Double, and Java.math.BigDecimal (and its subclasses)銆?br />
Example: salary(scale:2)
Error message code: 涓嶈繑鍥為敊璇俊鎭?/p>
size
瑙勫畾涓涓暟鍊鹼紝闆嗗悎鎴栬呭瓧絎︿覆闀垮害鐨勫ぇ灝忋?br />
鍦ㄧ増鏈?.5涓笉琚緩璁敤鍦ㄦ暟瀛楃被鍨嬬殑灞炴т笂錛屾敼鐢╮ange銆?/font>
Example: children(size:5..15)
Note: 涓嶈兘浣跨敤榪欎釜綰︽潫灞炴у鏋渂lank璁句負true鎴栬卬ullable璁句負true銆?br />
Error message code:
className.propertyName.size.toosmall
className.propertyName.size.toobig
unique
濡傛灉灞炴у繀欏諱負鍞竴錛屽垯璁句負true銆?br />
Example: login(unique:true)
Note: 鏈夊彲鑳戒細鍙戠敓閫氳繃unique楠岃瘉浣嗘槸鍦ㄩ殢鍚庣殑鏁版嵁搴撳偍瀛樺嚭鐜伴敊璇殑鎯呭喌銆傞闃茶繖縐嶆儏鍐靛彂鐢熺殑鏂規硶鏄嬌鐢ㄨ繛緇簨鍔¢殧紱葷駭鍒垨鑰呰繘琛宔ception鐨勫鐞嗐?br />
浠庣増鏈?.5寮濮嬶紝unique鐨勮寖鍥達紙Scope錛夊彲浠ヨ鎸囧畾銆?Scope"鏄悓涓涓被閲屽叾浠栧睘鎬х殑鍚嶅瓧錛屾垨鑰呰繖浜涘睘鎬у悕瀛楃殑涓涓猯ist銆?br />
Example: group(unique:'department')
涓婇潰鐨勪緥瀛愰噷group鍚嶅湪涓涓猟epartment閲屾槸鍞竴鐨勶紝浣嗘槸鍙兘鍦ㄥ叾浠杁epartment閲屾湁鐩稿悓鍚嶅瓧鐨刧roups銆?br />
Another Example: login(unique:['group','department'])
鍦ㄨ繖涓緥瀛愶紝login鍦╣roup鍜宒epartment閲屽繀欏繪槸鍞竴鐨勩傚彲鑳藉湪涓嶅悓絳塯roup鍜宒epartment閲屼細鏈夌浉鍚岀殑login銆?br />
Error message code: className.propertyName.unique
url
濡傛灉灞炴т負涓涓猆RL鍦板潃錛屽垯璁句負true銆?br />
Example: homePage(url:true)
Error message code: className.propertyName.url.invalid
validator
鍦ㄩ棴鍖呴噷璁懼畾鑷畾涔夌殑楠岃瘉銆?br />
Example:
even( validator: {
return (it % 2) == 0
})
Error message code (default): className.propertyName.validator.invalid
灝嗕細鍦ㄥ彟澶栫殑鏂囩珷閲岃繘琛屼粙緇嶃?/p>
class UserService {
boolean transactional = true
public boolean register(User user, UserInfo userInfo) throws RuntimeException {
if (user.save()) {
userInfo.user = user
if (userInfo.save()) {
return true
} else {
throw new RuntimeException ('ServiceException: UserService.register()...');
}
} else {
throw new RuntimeException ('ServiceException: UserService.register()...');
}
}
}
class User {
...
static constraints = {
userName(size:5..15, blank:false, unique:true)
password(size:5..15, blank:false)
email(email:true, blank:false)
age(min:18, nullable:false)
}
}
榪欐牱鍦ㄤ綘姣忔淇濆瓨涓涓璞$殑鏃跺欓兘鍥炲幓璋冪敤validate鏂規硶鏉ラ獙璇?
褰撶劧浣犲彲浠ュ湪浠諱綍瀹炰緥涓婅皟鐢ㄥ叾validate鏂規硶鍘婚獙璇侀鍩熺被.
def user = new User(params)
if(user.validate()) {
// do something with user
} else {
user.errors.allErrors.each {
println it
}
}
濡傛灉浣犲湪娉ㄥ唽鐨勬椂鍊? 姣斿瑕佽緭鍏ヤ袱嬈″瘑鐮? 榪欐椂鍊欐兂鎶婇敊璇秷鎭篃鏀懼叆棰嗗煙綾葷殑errors灞炴ч噷闈? 鐢變簬棰嗗煙綾葷殑 errors灞炴ф槸Spring鐨凟rrors鎺ュ彛瀹炰緥錛?/span>
Errors鎺ュ彛鎻愪緵浜嗚闂繖浜涢獙璇侀敊璇殑鏂規硶錛屽茍涓旇繕鍙互鍙栧緱鍘熷鐨勫箋?/span>
鍏蜂綋浣跨敤鐨勫疄鐜扮被鏄疊eanPropertyBindingResult
Java.lang.Object
org.springframework.validation.AbstractErrors
org.springframework.validation.AbstractBindingResult
org.springframework.validation.AbstractPropertyBindingResult
org.springframework.validation.BeanPropertyBindingResult
姣忎竴涓秷鎭搴斾竴涓?span style="color: green">org.springframework.validation.ObjectError瀵硅薄.鎵鏈夊彲浠ユ兂棰嗗煙綾葷殑errors灞炴ч噷闈㈢洿鎺ユ坊鍔燨bjectError瀵硅薄灝卞彲浠ヤ簡.
def error = new ObjectError('password', message(code:'pinpin.register.valid.password.notequal'))
user.errors.addError(error)
def dataSource
def list = {
def template = new JdbcTemplate(dataSource)
def userList = template.queryForList("select ui.name as name, u.password as password, ui.age as age, ui.email as email, ui.address as address from user u, user_info ui where u.id = ui.id");
def map = [userList : userList]
render(view:"list", model:map)
}
<table>
<thead>
<tr>
<g:sortableColumn property="name" title="Name" />
<g:sortableColumn property="password" title="Password" />
<g:sortableColumn property="email" title="Emial" />
<g:sortableColumn property="age" title="Age" />
<g:sortableColumn property="address" title="Address" />
</tr>
</thead>
<tbody>
<g:each in="${userList}" status="i" var="user">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td>${user.name}</td>
<td>${user.password}</td>
<td>${user.email}</td>
<td>${user.age}</td>
<td>${user.address}</td>
</tr>
</g:each>
</tbody>
</table>
鍦ㄧ壒孌婃儏鍐典笅錛?/span>grails搴旂敤闇瑕佽皟鐢ㄦ暟鎹簱鐨勫瓨鍌ㄨ繃紼嬶紝榪欏湪grails鐨勫畼鏂規枃妗i噷杈瑰ソ鍍忔病鏈夋彁鍒拌繃錛屽湪james鐨?/span>blog閲屼粙緇嶅浣曡В鍐寵繖涓棶棰樸?/span>
浠g爜杞創濡備笅
Java 浠g爜
闇瑕佽鏄庣殑涓浜涙槸錛?/span>grails鏈韓娌℃湁鎻愪緵璁塊棶瀛樺偍榪囩▼鐨勪究鎹鋒柟娉曪紝鑰?/span>groovy鐨?/span>GSQL鎻愪緵浜嗭紝鍥犳grails鍙互鐩存帴鎷胯繃鏉ョ敤浜嗭紝褰撶劧涔熷彲浠ョ敤spring鐨?/span>JdbcTemplate銆?/span>
甯屾湜瀵?/span>grails鐢ㄦ埛鏈夌偣鐢ㄣ?/span>
鍘熸枃鍦板潃錛?/span>http://grails.group.javaeye.com/group/blog/86666
My experience with grails is getting richer the longer I use it for web application developing. It's very nice that grails is built on top of spring framework which we can take advantage of. I am not a spring user before but with a help from the nice people at the grails forum I was able to achieve what I want to do.
Calling a stored procedure from a MySQL database or any other database is simple. First we need a datasource which spring could provide for us. I have the following code place in the resources.xml found in the spring folder in your grails folder.
<bean id="dataSource" class=" org.apache.commons.dbcp.BasicDataSource ">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:hsql://localhost</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
I use connection pooling for better performance. In my controller here is how I use the datasource to call a store procedure.
class MainController {
def dataSource // using the datasource we define in the spring's resources.xml
def index = {
Sql sql = new Sql(dataSource)
def row = sql.execute("call create_daily_hours(${new Date()+1})")
}
}
That's it! Notice that I am using Groovy SQL instead of Spring JDBCTemplate. It's a lot more friendlier for a beginner.
Grails really makes everything easy here and provides a lot of flexibility thanks to it's nice integration with spring. From here everything is possible.
鍘熸枃鍦板潃錛?/span>http://james-says.blogspot.com/2007/03/grails-little-of-spring-framework.html
鍏堣涓涓媑rails鐨剋eb.xml鐨勪駭鐢熻繃紼?/p>
Grails鐨剋eb.xml鏄湪Package.groovy鐨刧enerateWebXml target涓敓鎴愮殑銆傚彲浠ュ湪%Grails_Home%/scripts涓嬫壘鍒板畠銆傚叾瀹炲湪榪愯grails war鏃朵篃鏄厛璧扮殑榪欎竴姝ャ?/p>
鍦╣enerateWebXml閲?/p>
1.鍏堝垽鏂湁娌℃湁config.grails.config.base.webXml灞炴э紝濡傛灉鏈夛紝鍒欎嬌鐢ㄦ寚瀹氱殑config.grails.config.base.webXml鍊間綔涓烘渶緇堢殑web.xml
2.濡傛灉娌℃湁config.grails.config.base.webXml灞炴с傚啀鍒ゆ柇鏄惁瀛樺湪%Project_Home%/src/templates/war/web.xml錛屽鏋滃瓨鍦ㄥ氨浣跨敤榪欎釜浣滀負鏈緇堢殑web.xml
3.濡傛灉涓婇潰涓や釜閮芥病鏈夛紝灝變嬌鐢?Grails_Home%/src/war/WEB-INF/web${servletVersion}.template.xml浣滀負鏈緇堢殑web.xml
鏍規嵁涓婇潰鐨勯『搴忥紝鎴戜滑鏈?涓柟娉曟潵鎸囧畾web.xml
絎竴錛屽彲浠ヤ慨鏀?%Project_Home%/grails-app/conf/Config.groovy 鏂囦歡錛屽湪鏂囦歡涓坊鍔?br />
grails.config.base.webXml = "file:${basedir}/web.xml"
鍏朵腑${basedir}浠h〃%Project_Home%錛屽氨鏄浼氬皢%Project_Home%/web.xml浣滀負鏈緇堢殑web.xml銆?/p>
絎簩錛屼嬌鐢?grails install-templates 鍛戒護錛屽畠浼氬垱寤?Project_Home%/src/templates/war/web.xml 鏂囦歡銆傝繖鏍峰彧瑕佷慨鏀硅繖涓獁eb.xml灝辮浜嗐?/p>
絎笁錛屼慨鏀?Grails_Home%/src/war/WEB-INF/web${servletVersion}.template.xml鏂囦歡錛屼絾鏄渶濂戒笉瑕佽繖鏍峰仛銆?/p>
榪欓噷浣跨敤Grails 1.0.1
static mapping = {
id generator:'uuid.hex', params:[separator:'-']
}
}
class Country {
String id
String name
Boolean active = true
static mapping = {
id generator:'uuid.hex'
}
}
榪欐牱灝辯敓鎴愭牸寮忎負: 2c9d004d1b247311011b2473ebf90003
Grails鏀寔涓浜涗笉鍚岀殑鏂規硶鏉ヤ駭鐢焁ML鍜孞SON鍝嶅簲銆傜涓涓槸闅愬紡鐨勯氳繃render鏂規硶銆?
render
鏂規硶鍙互浼犻掍竴涓唬鐮佸潡鏉ユ墽琛屾爣璁扮敓鎴愬櫒浜х敓XML
def list = { def results = Book.list() render(contentType:"text/xml") { books { for(b in results) { book(title:b.title) } } } }
榪欐浠g爜鐨勭粨鏋滃皢浼氬儚榪欐牱錛?
<books> <book title="The Stand" /> <book title="The Shining" /> </books>
娉ㄦ剰錛屽綋浣犱嬌鐢ㄦ爣璁扮敓鎴愬櫒鏃訛紝蹇呴』灝忓績閬垮厤鍛藉悕鍐茬獊銆備緥濡傦紝榪欐浠g爜灝嗕駭鐢熶竴涓敊璇細
def list = { def books = Book.list() // naming conflict here render(contentType:"text/xml") { books { for(b in results) { book(title:b.title) } } } }
鍘熷洜鏄紝榪欓噷鐨勪竴涓湰鍦板彉閲?code>books浼佸浘浣滀負鏂規硶琚皟鐢ㄣ?
render
鏂規硶鍙互鍚屾牱琚敤浜庤緭鍑篔SON:
def list = { def results = Book.list() render(contentType:"text/json") { books { for(b in results) { book(title:b.title) } } } }
鍦ㄨ繖縐嶆儏鍐典笅錛岀粨鏋滃氨浼氭槸澶ц嚧鐩稿悓鐨勶細
[ {title:"The Stand"}, {title:"The Shining"} ]
鍚屾牱鐨勫懡鍚嶅啿紿佸嵄闄╅傜敤浜嶫SON鐢熸垚鍣ㄣ?
錛堣瘧鑰呮敞錛氬湪姝ら檮涓婂浜庡垪闆?Marshalling)瑙i噴錛氬鍑芥暟鍙傛暟榪涜鎵撳寘澶勭悊寰楄繃紼嬶紝鍥犱負鎸囬拡絳夋暟鎹紝蹇呴』閫氳繃涓瀹氬緱杞崲錛屾墠鑳借鍙︿竴緇勪歡鎵鐞嗚В銆傚彲浠ヨ鍒楅泦(Marshalling)鏄竴縐嶆暟鎹牸寮忕殑杞崲鏂規硶銆傦級
Grails鍚屾牱鏀寔鑷姩鍒楅泦(Marshalling)棰嗗煙綾諱負XML閫氳繃鐗瑰畾鐨勮漿鎹㈠櫒銆?
棣栧厛錛屽鍏?code>grails.converters 綾誨寘鍒頒綘鐨勬帶鍒跺櫒錛圕ontrollers錛変腑錛?
import grails.converters.*
鐜板湪錛屼綘鍙互浣跨敤涓嬪垪楂樺害鏄撹鐨勮娉曟潵鑷姩杞崲棰嗗煙綾繪垚XML錛?
render Book.list() as XML
杈撳嚭緇撴灉鐪嬩笂鍘諱細鍍忎笅鍒楄繖鏍鳳細
<?xml version="1.0" encoding="ISO-8859-1"?> <list> <book id="1"> <author>Stephen King</author> <title>The Stand</title> </book> <book id="2"> <author>Stephen King</author> <title>The Shining</title> </book> </list>
涓涓嬌鐢ㄨ漿鎹㈠櫒鐨勬浛浠f柟娉曟槸浣跨敤Grails鐨刢odecs鐗規с俢odecs鐗規ф彁渚涗簡encodeAsXML鍜宔ncodeAsJSON鏂規硶:
def xml = Book.list().encodeAsXML() render xml
Grails鍚屾牱鏀寔鑷姩鍒楅泦(Marshalling)涓篔SON閫氳繃鍚屾牱鐨勬満鍒躲傜畝鍗曟浛浠?code>XML 涓?code>JSON
render Book.list() as JSON
杈撳嚭緇撴灉鐪嬩笂鍘諱細鍍忎笅鍒楄繖鏍鳳細
[ {"id":1, "class":"Book", "author":"Stephen King", "title":"The Stand"}, {"id":2, "class":"Book", "author":"Stephen King", "releaseDate":new Date(1194127343161), "title":"The Shining"} ]
鍐嶆浣滀負涓縐嶆浛浠o紝浣犲彲浠ヤ嬌鐢?code>encodeAsJSON杈懼埌鐩稿悓鐨勬晥鏋?
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize"> <value>1000000</value> </property> </bean>褰撶劧gsp欏甸潰闇瑕佸湪form閲岄潰璁劇疆enctype="multipart/form-data"
<g:form method="post" action="save" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit"/> </g:form>
import org.springframework.web.multipart.MultipartHttpServletRequest
import org.springframework.web.multipart.commons.CommonsMultipartFile
class UploadController {
static String uploadDir = "uploadfile"
def index = {
render(view:"upload")
}
def save = {
if (request instanceof MultipartHttpServletRequest) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request
CommonsMultipartFile orginalFile = (CommonsMultipartFile) multiRequest.getFile("file")
// 鍒ゆ柇鏄惁涓婁紶鏂囦歡
if (orginalFile != null && !orginalFile.isEmpty()) {
// 鑾峰彇緋葷粺榛樿鏂囦歡璺緞鍒嗛殧絎?br />
def separator = System.getProperty("file.separator")
println "file separator is ${separator} "
// 鑾峰彇鍘熸枃浠跺悕縐?br />
String originalFilename = orginalFile.getOriginalFilename()
// 鑾峰彇涓婁紶鏂囦歡鎵╁睍鍚?br />
def extension = originalFilename.substring(originalFilename.indexOf(".") + 1)
println "extension is ${extension}"
def name = ".." + separator + uploadDir + separator + orginalFile.getOriginalFilename()
println "file name is : ${name}"
// 浣跨敤瀛樻斁鏂囦歡鐨勭粷瀵硅礬寰勫垱寤鴻緭鍑烘祦
/**
DataOutputStream out = new DataOutputStream(new FileOutputStream(name))
InputStream is = null
try {
is = orginalFile.getInputStream()
byte[] buffer = new byte[1024]
while (is.read(buffer) > 0) {
out.write(buffer) // 鍐欏叆紓佺洏
}
} catch (IOException exception) {
exception.printStackTrace()
} finally {
if (is != null) {
is.close()
}
if (out != null) {
out.close()
}
}
*/
orginalFile.transferTo(new File(name))
render(view:"success")
}
} else {
println "No multipart"
}
}
}
def format = attrs.get('format')
if (!format) {
format = "yyyy-MM-dd HH:mm:ss z"
}
out << new Java.text.SimpleDateFormat(format).format(date)
}
def formatNumber = { attrs ->
def number = attrs.get('number')
if (!number) {
number = new Double(0)
}
def format = attrs.get('format')
if (!format) {
format = "0"
}
out << new Java.text.DecimalFormat(format).format((Double)number)
}
}
2銆佸畨瑁匞rails