No início havia muitas dúvidas se o Grails iria ser útil para aplicações grandes, ou de grande porte. Mas peraí, o que é uma aplicação grande? eBay é gigante. Se considerarmos uma medida, aí acho que podemos definir grande. Page-views por mês, por exemplo, pode ser uma medida, já que é fácil de saber, de monitorar, etc.
Um eBay tem algo em torno de 15 bilhões de page-views por mês. A globo.com tem uns 2 bilhões de page-views/mês. Um Peladeiro.com.br tem 1,2 milhão de page-views/mês. O Peladeiro é pequeno, Globo.com é grande, eBay é gigante. Pelo menos na minha opinião, sem muito exercício científico.
Além da medida de grande número de acessos, há também: grande volume de dados, necessidade de alta disponibilidade e redundância, escalabilidade, hot swap, cluster failover, etc, etc....
Aí voltamos a pergunta original: o Grails é bom para isso? Dá pra confiar que uma aplicação grails serve para uma demanda de uma aplicação de grande porte?
Grails e Cloud: desenvolvimento, deploy, execução e monitoramento. Ciclo completo com Grails na Nuvem.
Enviando emails formatados com Html e CSS - será que vai certinho?
Muito bom esta tabela que mostra o que cada cliente de email consegue mostrar corretamente em termos de CSS nos emails Html que vc envia.
http://www.campaignmonitor.com/css/
Ou seja, não adianta referenciar um arquivo CSS na tag link lá no header, pois nem todos os clientes levam isso em consideração. E nem tag style no header, e nem..... olhe o link acima.
Abcs
Felipe
Serviços do Grails, Transações e Rollback automático
Comprei o livro recente que saiu do Glen Smith, o Grails in Action. E, claro, comecei a ler. Ainda não terminei. Mas já valeu a compra e a dedicação de ler só pelo fato que eu descobri e não sabia:
Manubia.com.br - Controle Financeiro com Grails e, agora, com jQuery
É pessoal....
- jQuery tem um mundo plugins que resolvem diversos problemas que a gente precisa ficar catando pela web quando usamos Prototype + Scriptaculous.
- o jQuery tem um projeto inteiro dedicado a interface gráfica: jQuery UI
- formatação de campos de um formulário (formatar valor numérico com pontos e vírgulas, de forma internacionalizada): Masked Input Plugin
- Calendário tipo Date Picker para campos de datas: jQuery UI DatePicker
- Plugin para manipulação de comboboxes (select boxes).
- No final das contas, a gente escreve menos código JavaScript do que com Prototype. Parece que fica mais limpo o código.
- Tem um site dedicado aos plugins
- De acordo com alguns benchmarks (um aqui, outro aqui), o jQuery tem uma performance melhor do que o Prototype (ou seja, os usuários é que ganham).
- Eu tenho tudo que preciso em uma biblioteca só, não preciso usar parte de uma, parte de outra, etc... (pelo menos por enquanto, vamos ver até quando).
Filtro do Grails para impor SSL (https) a determinadas páginas
Olá pessoal,
/**
* Created by IntelliJ IDEA.
* User: danielhonig
* Date: Jan 23, 2009
* Time: 4:27:10 PM
* To change this template use File | Settings | File Templates.
*/
import org.codehaus.groovy.grails.commons.ConfigurationHolder
class SSLFilters {
// Set these to your HTTP/HTTPS ports
def defaultPortHTTP = 80
def defaultPortHTTPS = 443
static def SSLRequiredMap = ConfigurationHolder.config.SSLRequiredMap
def shouldUseSSL(controllerName, actionName) {
// User actions use SSL
if (SSLRequiredMap[controllerName]!=null) {
//If * then all actions are secured
if (SSLRequiredMap[controllerName][0] == '*')
return true
//else look for specific action
if (SSLRequiredMap[controllerName].contains(actionName))
return true
}
false
}
def filters = {
sslFilter(controller: "*", action: "*"){
before = {
def controller = controllerName
def action = actionName
log.debug("SSLFilter: ${params?.controller}.${params?.action}")
def url = null
// SSL off by default
def useSSL = shouldUseSSL(controllerName,actionName)
log.debug("${controller}.${action}, useSSL:$useSSL")
// Get redirected url
url = getRedirectURL(request, params, useSSL);
// If redirect url returned, redirect to it
if (url) {
redirect(url: url)
return false;
}
return true;
}
}
}
def getRedirectURL = {request, params, ssl ->
log.debug("getRedirectURL: $ssl")
// Are we there already?
if (request.isSecure() == ssl)
return null;
def protocol
def port
// Otherwise we need to flip
if (ssl) {
protocol = 'https'
// If using the standard ports, don't include them on the URL
port = defaultPortHTTPS
if (port == "443")
port = ""
else
port = ":${port}"
}
else {
protocol = 'http'
// If using the standard ports, don't include them on the URL
port = defaultPortHTTP
if (port == "80")
port = ""
else
port = ":${port}"
}
log.debug("Flip protocol to $protocol")
def url = request.forwardURI
def server = request.serverName
def args = paramsAsUrl(params)
url = "$protocol://$server$port$url$args"
log.debug("getRedirectURL - redirect to $url")
return url;
}
def paramsAsUrl = {params ->
int ii = 0
String args = ""
params.each
{k, v ->
if (['controller', 'action', 'id'].find {k == it})
return;
if (ii)
args += "&"
else
args += "?"
args += "$k=$v"
ii++
}
return args
}
}
Controle Financeiro e Planejamento Financeiro com Grails e Prototype
Mês passado eu e um grande amigo, e meu sócio neste projeto, lançamos um site para controle financeiro pessoal: www.manubia.com.br
Logging com Grails 1.1
Hoje fiquei tentando entender a configuração do Logging no grails 1.1...pois mudou um pouco.
Tem um bom exemplo aqui, que eu reproduzo abaixo.
log4j = {
appenders {
console name:'console', threshold:Level.ERROR,
layout:pattern(conversionPattern: '%p %d{ISO8601} %c{4} %m%n')
rollingFile name:"rollingFileTrace", threshold:Level।TRACE, maxFileSize:1048576,
file:logFile+'Trace।log', layout:pattern(conversionPattern: '%p %d{ISO8601} %c{5} %m%n')
rollingFile name:"rollingFileDebug", threshold:Level।DEBUG, maxFileSize:1048576,
file:logFile+'Debug.log', layout:pattern(conversionPattern: '%p %d{ISO8601} %c{5} %m%n')
rollingFile name:"rollingFileError", threshold:Level.ERROR, maxFileSize:1048576,
file:logFile+'Error.log', layout:pattern(conversionPattern: '%p %d{ISO8601} %c{5} %m%n')
}
error console, rollingFileDebug, rollingFileError, rollingFileTrace:
'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages', // GSP
'org.codehaus.groovy.grails.web.sitemesh', // layouts
'org.codehaus.groovy.grails."web.mapping.filter', // URL mapping
'org.codehaus.groovy.grails."web.mapping', // URL mapping
'org.codehaus.groovy.grails.commons', // core / classloading
'org.codehaus.groovy.grails.plugins', // plugins
'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
'org.springframework'
debug rollingFileDebug, rollingFileTrace:'org.hibernate',
'com.britetab',
'BootStrap',
'org.apache.ddlutils'
trace rollingFileTrace:'org.hibernate.SQL',
'org.hibernate.type',
'flex.messaging.services'
warn console,rollingFileDebug,rollingFileTrace:'org.mortbay.log',
'org.hibernate.tool.hbm2ddl'
root {
trace 'rollingFileTrace'
debug 'rollingFileDebug','rollingFileTrace'
error 'console','rollingFileError','rollingFileDebug','rollingFileTrace'
additivity = true
}
}
Detalhe do Grails com Eclipse
Pessoal
eu já passei maus bocados uma vez por causa da questão que irei escrever aqui. Hoje, meu companheiro de desenvolvimento João Paulo passou pelo mesmo problema...Depois de algum tempo ele resolveu me perguntar, e lendo o erro que ele me passou, não deu outra, era o problema que já passei.
Quando você ler um erro como este:
No signature of method: Requestmap.save() is applicable for argument types: () values: {}
(é claro que no seu caso a sua classe de domain não será Requestmap, será Pessoa, Categoria, Produto, sei lá o que)
Uma das possíveis causas disso é uma configuração no eclipse, que faz com que o Eclipse compile as classes groovy, gerando os arquivos .class . Neste caso, o grails, ao rodar a aplicação com "grails run-app"
, ele também compila, aí tudo se perde.
Não deixe de configurar o Eclipse para não compilar os arquivos de groovy. Para isso:
- Clique com botão direito no seu projeto, no eclipse
- Selecione "Groovy project Properties"
- Marque a opção "Disable Groovy Compiler Generating Class Files"
Abcs
Felipe
Grails 1.0.1 e many-to-many com GORM DSL
Oi pessoal,
primeiro queria divulgar o forum do GrailsBrasil ( www.grailsbrasil.com ). Um ótimo espaço para os brazucas, que cada vez mais descobrem e se encantam com o Grails.
Em seguida, queria falar, com certo atraso, da tão esperada Release 1.0 do Grails, que na verdade já está na 1.0.1. Isso é uma grande notícia.
Por último, a razão deste post....
O Grails 1.0.1 possui o GORM DSL, que oferece grande facilidade para controlar detalhes do mapeamento objeto relacional dos objetos de domínio. Ao migrar uma aplicação do grails 0.6 para o 1.0.1, quis alterar alguns detalhes do mapeamento, já que agoraeu conseguiria isso sem precisar apelar para mapeamento Hibernate com XML.
O problema que eu queria resolver era:
Digamos que eu tenha uma classe Usuario e outra Privilegio, com um relacionamento many-to-many entre elas. Logo teremos:
class Usuario {
String nome
static hasMany = [privilegios:Privilegio]
}
class Privilegio {
String nome
static hasMany = [usuarios:Usuario]
static belongsTo = Usuario
}
Com as classes acima, o grails gera as seguintes tabelas:
usuario
id
nome
privilegio
id
nome
usuario_priv
usuarios_id (que é uma FK para privilegio.id)
privilegios_id (que é uma FK para usuario.id)
É isso mesmo: o campo usuarios_id é uma chave estrangeira para o id da tabela privilegio; e o campo privilegios_id é uma chave estrangeira para o id da tabela usuario. A explicação pra isso está aqui (vejam o comentário do Graeme).Eu não sei quanto a vocês, mas pra mim isso soa muito estranho. Mas é assim mesmo que o grails gera por padrão. A forma que eu gosto de trabalhar é com campos no singular e com o nome do campo da chave estangeira condizente com o nome da tabela de referência:
usuario_priv.usuario_id = usuario.id
usuario_priv.privilegio_id = privilegio.id
Para isso, então, eu antigamente teria que fazer o mapemanto com XML do hibernate (já fiz vários para outras aplicações com grails). Mas agora na versão atual posso fazer o que quero com o GORM DSL. E é isso que quero mostrar, pois há um detalhe que precisei fazer alguns testes até entender o comportamento do Grails com essa DSL. Vamos lá...
class Usuario {
String nome
static hasMany = [privilegios:Privilegio]
static mapping = {
privilegios column:'usuario_id', joinTable:'usuario_priv'
}
}
class Privilegio {
String priv
static hasMany = [usuarios:Usuario]
static belongsTo = Usuario
static mapping = {
usuarios column:'privilegio_id', joinTable:'usuario_priv'
}
}
O que eu acho curioso e anti-intuitivo no código acima, é que numa primeira tentativa eu coloquei:
Mas isso acabou sendo errado. Na verdade temos que colocar como nome da coluna (para ter o resultado que eu esperava), o nome da classe em que me encontro, e não o nome do atributo de relacionamento. Em fim: o correto é o código acima completo das classe Usuario e Privilegio, e não o código acima com fundo avermelhado.class Usuario {
static mapping = {
privilegios column:'privilegio_id', joinTable:'usuario_priv'
}
}
Fiz questão de colocar isso aqui, pois a documentação não me parece muito clara quanto a isso. (talvez eu é que tenha entendido errado a documentação, sei lá....em fim....tá aí pra quem precisar deste detalhe).
Abcs
Felipe
Grails, Gravl, SAP e REST intro
Oi pessoal,
hoje eu vou fazer um pequeno post com algumas coisas que achei interessantes recentemente.
Primeiro, nosso amigo Glen Smith, novamente, faz um desafio a si mesmo em benfício da comunidade Grails. Essas comunidades open source são demais mesmo....
O Glen está implementando um pequeno sistema de blog, chamado de Gravl, em no máximo 1000 linhas de código (LOC), para mostrar algumas funcionalidade do Grails e seus plugins. Ele está usando algumas das últimas novidades das recentes versões do Grails, como Web Flow, GORM DSL, URL Mappings, RSS Plugin, Searchable Plugin, Ajax Upload com barra de progresso, entre outras coisas. O código fonte está disponível como um projeto open source do google code, e seu objetivo é ser uma aplicação de exemplo do Grails. Vale conferir. ( veja outros posts dele sobre este tema ).
Segundo, a SAP anunciou que estará usando o Grails 1.0 para o seu produto Composition on Grails, que é uma aplicação que provê facilidade para o rápido desenvolvimento de "aplicações compostas"(composite applications) no SAP NetWeaver 7.1 CE. Esta notícia é muito interessante por colocar o Grails como a opção escolhida por uma corporação de peso como a SAP para um de seus produtos. Excelente notícia para a comunidade Grails. Veja o post do Grame Rocher sobre isso.
E em terceiro, (sem ter uma relação direta com grails, mas que me fez pensar muito nas facilidade que o grails tem a respeito de REST) li outro dia um artigo introdutório sobre REST no InfoQ, que foi muito bom apesar de eu já ter lido outros sobre este tema. Mostra de maneira simples uma possível implementação dos conceitos de REST, e reforça esta alternativa light ao mundo de web services. E só pra não deixar passar, veja as facilidades para REST que o Grails tem (veja item 13.1).
Até a próxima...
Grails muito perto da release 1.0
Olá,
depois de tanto tempo lonje do meu blog, infelizmente, volto a campo para comentar algumas coisas.
Primeiro, estou tão longe assim devido (eu sei que não é desculpa, mas...) ao trabalho e muito também a minha filha. Manuela completará 1 ano daqui a duas semanas. E este primeiro ano de pai de filha única e menina, realmente eu fiquei muito babão e dedicando todo meu tempo livre a ela.
Em fim....
Depois de um período de trabalhos de consultoria, um pouco longe da mão na massa, tenho voltado a codificar, e naturalmente usando o Grails. Tendo usado o grails desde a versão 0.3, e isso já faz quase um ano, e passando pelas migrações para as versões 0.4.1, 0.4.2, 0.5 e agora 0.6, percebo o quanto valeu a pena ter escolhido o Grails para novas aplicações quando ainda era 0.3 Na época existia um questionamento muito grande se eu deveria ou não usar o Grails 0.3, quando ainda era muito no início do framework, quando a cada nova release era necessário alguma reengenharia devido a mudanças de API (eu senti muito migrande da 0.4.2 para a 0.6). Hoje, agradeço a mim mesmo por ter apostado no Grails naquela época.
Tenho uma aplicação que começou a ser desenvolvida lá traz com 0.3, e hoje roda em produção com grails 0.6 (ainda não migrei para 1.0-RC1). Estou muito satisfeito com a decisão de usar o grails desde o início, pois o granho de produtividade foi tanto, que hoje quando precisamos dar manutenção, evoluir e criar novas funcionalidades, penso em como seria custoso se não estivessemos usando o Grails. Acho que seria caro demais para meu cliente, ou então usaríamos uma solução em PHP (neste caso, deste cliente).
O Grails está na versão 1.0 RC1, faltando poucas semanas para a release final 1.0, finalmente. Muitas pessoas, e principalmente empresas, só irão assumir a aposta num novo framework caso ele tenha um release 1.0 estável. E agora o Grails já está quase lá.
A quantidade de facilidades que o grails 1.0 nos dá é enorme:
- Facilidades para Web Services (REST ou SOAP)
- Diversos plugins. Destaques para:
- Converters Plugin
- XFire Plugin
- Cacheable Plugin
- Searchable Plugin (facilmente adiciona busca com Lucene+Compass na sua aplicação)
- Image Tols Plugin (oferece grande facilidade para manipulação de imagens com JAI)
- GWT Plugin
- Build com Ivy ou Maven
Não dá nem para citar tudo aqui. Só lendo mesmo, e principalmente, experimentando.
Falando em "lendo", numa discussão há algumas semanas, o pessoal da lista colocou a opinião de que era fundamental para uma boa adoção do grails (corporativa principalmente) a existência de uma documentação MUITO melhor, pois o site era razoável apenas. Em resposta a isso, o pessoal da G2One (empresa criada para dar suporte ao Groovy e Grails) escreveu o primeiro draft do Reference Guide. Que para uma primeira versão, está muito bom. Vale a leitura completa para conhecer diversos detalhes do framework.
O que me motivou para escrever este post de hoje foi uma mensagem enviada para a lista pelo Matt Raible. Ele é um consultor/arquiteto/desenvolvedor Java, com bastante experiência, e criador do AppFuse. Já usei muito o AppFuse, e se não fosse o Grails, estaria usando até hoje.
O Matt Raible mandou uma mensagem perguntando algumas coisas sobre performance do Grails, sobre o uso do FreeMarker com o Grails, sobre a possibilidade de criar um Struts2 plugin para o grails, e outras coisas. Ele perguntava essas coisas pois queria ter mais argumentos para conseguir "vender" o grails para algumas emoresas em que ele está prestando consultoria, empresas essas que usam essas tecnologias e cujos diretores gostariam de manter a tecnologia em uso para os próximos projetos. Os argumentos e dúvidas do Matt são de que o Grails permitiria a continuidade do uso dessas tecnologias, e ainda oferece um desenvolvido mais produtivo, etc, etc...
Depois da release 1.0, com o nível de documentação que se está alcançando, com a comunidade ativa que o grails tem hoje...... Aí, quando eu leio o Matt defendendo o uso do Grails em empresas que ele dá consultoria, sinceramente é o último argumento que eu precisava. Não tem mais volta. Pra mim, aplicações web na plataforma java, só em grails.
Ah, em relação a minha aplicação que citei acima. É um site que tem mais de 200.000 usuários cadastrados, q tem 31.000 visitantes por dia, gerando aproximadamente 400.000 page views por dia. Há controle de login, processamento de imagens, envio de emails, módulo administrativo, geração de relatórios, etc, etc.
Vejam por si só:
http://www.noiteuniversitaria.com.br
Grande abraço e até a próxima.
Grails e ImageMagick, poderio em manipulação de imagens
Recentemente tive que lidar, mais uma vez, com manipulação de imagens numa aplicação web. O requsito era o clássico: usuário faz upload de uma imagem que a gente não sabe as dimensões, e a aplicação precisa criar um thumbnail (aquela versão bem reduzida da imagem para apresentar numa página junto com diversos outros elementos de página), e também um versão da imagem em tamanho grande pré-determinado.
Mas desta vez havia requisitos novos:
1) Era preciso adicionar uma marca d'água à foto grande, e;
2) Deveria ser possível fazer um upload de um arquivo zip com dezenas de fotos dentro, e a aplicação precisava processar todas as imagens do zip, criando o tumbnail, a foto grande e a marca d'água.
Uma das opções que surgiram no meio do caminho apareceu quando surgiu este assunto na lista do Grails e alguém fez com que eu conhecesse o ImageMagick. Esta biblioteca é uma biblioteca nativa de processamento de imagens...como se fosse um photoshop, porém sem interface gráfica, apenas por linha de comando. E o mais interessante é que ela realmente possui diversas funcionalidades de um photoshop, como filtros, transformações, conversões, ou seja, realmente edição de imagem. Vale a pena conhecer. Veja alguns exemplos aqui. Para exemplos de uso da API, veja aqui.
Ok....então passamos a conhecer o ImageMagic (IM). Ah, antes que eu esqueça, existem várias intefaces de acesso ao IM para várias linguagens. Há inclusive o JMagick, que é a API java para o IM. Porém, pesquisando a respeito no google a gente vê que em diversas situações o JMagick crasha (crash). Então, se a gente não pode ainda, ou não deve, usar o JMagick, a saída é usar o IM nativamente ( que deve ser o que o JMagick faz, mas não sabemos o que fizeram lá para ele entrar em crash né).
Portanto, finalmente, este post tem então o objetivo de mostar uma action de um controller grails que eu fiz num micro projetinho grails só pra testar o uso do IM usando groovy e executando o IM nativamente, seguindo as dicas do nosso amigo James Page da lista do grails.
O primeiro passo é instalar o ImageMagick na sua plataforma. Em windows há o instalador através de um arquivo .exe. No linux há o RPM. E é claro, você pode instalar a partir do fonte do ImageMagick também.
Depois de instalar, você pode testar facilmente pela linha de comando. Se funcionou, vamos para o mundo web com nosso grails.
Eu criei um projeto novo só pra testar. Para isso:
grails create-app
Chamei este projeto de "img". Após criar, vá para o diretório do projeto e
grails create-domain-class
Chamei esta classe de domínio de TaskFile (só porque em outro projeto eu tenho uma classe Task que possui diversos TaskFile).
class TaskFile {
String name
Date uploaded = new Date()
String description
}
Em seguida gerei o controlador TaskFileController (com comando "grails generate-controller").
import org.springframework.web.multipart.MultipartFile;
class TaskFileController {
def index = { redirect(action:list,params:params) }
// .... todas as actions que o grails gera. Alterei a action save
// alem de alterar, criei metodos privados
def save = {
def taskFile = new TaskFile()
taskFile.properties = params
if(taskFile.save()) {
def f = request.getFile('taskFile')
if(!f.empty) {
def fileName = 'file_' + taskFile.id + getExtension(f)
f.transferTo( new File('imgs/' + fileName) )
processImg(fileName)
}
redirect(action:show,id:taskFile.id)
}
else {
render(view:'create',model:[taskFile:taskFile])
}
}
private void processImg(fileName){
final String original = 'imgs/' + fileName
def t = Thread.start {
def cmd = createCmd(original, '-thumbnail', createDimentions(100,0) , 'imgs/tumb_' + fileName)
def process = cmd.execute()
process.waitFor()
def cmdMain = createCmd(original, '-thumbnail', createDimentions(400,0) , 'imgs/main_' + fileName)
def processMain = cmdMain.execute()
processMain.waitFor()
def waterMarkCmd = ["cmd /c composite -compose atop watermark.png", 'imgs/main_' + fileName, 'imgs/wm_' + fileName]
waterMarkCmd.join(" ").execute()
}
}
private String getExtension(MultipartFile file){
String contentType = file.getContentType();
String fileExtension = null;
if (contentType.equalsIgnoreCase("image/pjpeg") || contentType.equalsIgnoreCase("image/jpeg")) {
fileExtension = ".jpg";
}
else if (contentType.equalsIgnoreCase("image/gif")) {
fileExtension = ".gif";
}
else if (contentType.equalsIgnoreCase("image/x-png")) {
fileExtension = ".png";
}
return fileExtension;
}
String createCmd(inpath, action, options ,outpath){
//@todo Need os specific code here... Remove c for Linux.....
def cmd = ['cmd','/c', 'convert', inpath, action , options, outpath]
return cmd.join(" ");
}
String createDimentions(width, height){
StringBuffer sb = new StringBuffer();
if(width > 0)
sb.append(width);
sb.append('x');
if(height > 0)
sb.append(height)
return sb.toString()
}
}
Percebam que no código do controlador, o interessante foi o uso de uma Thread separada para o processamento das imagens. Já que processar imagens pode levar algum tempo em determinados casos, não é necessário deixar o usuário final esperando isso. Assim, criei uma nova thread que faz este trabalho enquanto a thread do request já manda o response direto pro usuário. Neste exemplo, eu faço 3 coisas: salvo o arquivo original, crio o thumbnail, crio a imagem grande que chamei de main, e por último crio a imagem grande com a marca d'água (watermark). Tudo isso é feito no método processImg(fileName). Percebam que este método faz uso do método execute() do groovy, que executa um comando no sistema operacional e retorna um java.lang.Process.
Depois disso foi só gerar as views (grails generate-views). Alterei a create.gsp para que tivesse o upload do meu arquivo:
<g:form action="save" method="post" enctype="multipart/form-data">
<div class="dialog">
<table>
<tbody>
<tr class='prop'><td valign='top' class='name'><label for='description'>Description:</label></td><td valign='top' class='value ${hasErrors(bean:taskFile,field:'description','errors')}'><input type='text' name='description' value="${taskFile?.description?.encodeAsHTML()}" /></td></tr>
<tr class='prop'><td valign='top' class='name'><label for='name'>Name:</label></td><td valign='top' class='value ${hasErrors(bean:taskFile,field:'name','errors')}'><input type='text' name='name' value="${taskFile?.name?.encodeAsHTML()}" /></td></tr>
<tr class='prop'><td valign='top' class='name'><label for='taskFile'>taskFile:</label></td><td valign='top' class='value ${hasErrors(bean:taskFile,field:'uploaded','errors')}'><input type="file" name="taskFile" /></td></tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="formButton">
<input type="submit" value="Create"></input>
</span>
</div>
</g:form>
E só isso. Até a próxima. Abcs.
Grails plugins mostrando sua força
O projeto Grails lançou recentemente sua versão 0.5.
A evolução tem sido bastante rápida, com o objetivo de chegar na versão 1.0 até o fim deste ano. Já dise uma vez e vou dizer de novo: estar na versão 0.5 ( ou qualquer uma que ainda não seja 1.0) não significa que não possa ser usado para sistemas em produção, significa apenas que a API pode ser alterada ao longo do caminho, forçando as aplicações a se atualizarem junto com a evolução do Grails.
Uma das novidades recentes é a API de Plugins do Grails....ok ok, eu sei que já falei disso.
Neste post que quero apenas comprovar como o Grails Plugins pode ser bastante poderoso. O Graeme Rocher enviou recentemente um post no seu blog demonstrando a beleza dos plugins ao criar um plugin para integrar o Wicket ao Grails.
Vale a pena olhar para quem tem interesse neste crescente projeto que é o Wicket.
Abcs
Felipe
Grails: Controller para download de arquivo em diretório
Eu tenho colocado ultimamente posts que são pequenos e possuem código fonte de algumas pequenas coisas. Hoje vou colocar aqui uma action de um controller que faz download de um arquivo qualquer de um diretório no sistema de arquivos.
Eu acho interessante ter estes pequenos posts de exemplos pois servem de referência para dúvidas futuras, inclusive minhas. Alguém acha ruim este tipo de post? Preferem os posts mais elaborados (porém demandam mais tempo né)?
Em fim, segue o código.
def downloadBook = {
def file = new File("c:/temp/onliso.pdf")
response.setHeader("Content-Type", "application/octet-stream;")
response.setHeader("Content-Disposition", "attachment;filename=\" onlisp.pdf\"")
response.setHeader("Content-Length", "${file.size()}")
response.outputStream << file.text.bytes
}
É simples ou não é desenvolver vom grails e groovy. Olha o tamanho deste código. QUal seria a alternativa em Java? Quantas linhas a mais? Não quero criticar não, eu adoro Java, mas ter uma linguagem de script como Groovy na plataforma Java é muito bom, MUITO BOM.
Até a próxima.
[]s
Felipe
Bind de coleção de objetos com Grails
Muitas vezes os frameworks ágeis de programação web como Grails e Ruby on Rails ajudam muito nas operações CRUD simples. Você consegue rapidamente fazer criar, obter, alterar e apagar objetos de domínio com forms simples. Mas nas aplicações reais, fora dos "Hello World" usados nos exemplos, a gente se depara algumas vezes com a necessidade de fazer operações de CRUD em forms mais elaborados. Às vezes há casos que queremos reunir mais de um objeto de domínio num mesmo form, e há outros casos em que queremos reunir o mesmo objeto de domínio mais de uma vez: um exemplo seria salvar vários objetos Endereço de uma só vez.
Há uma maneira simples, usando o Grails, de se fazer o bind de uma coleção de objetos do mesmo tipo. Vamos a ela:
Neste exemplo, digamos que a gente queira salvar vários objetos Person de uma só vez, recebendo um post de um form único.
Crie um objeto helper em Groovy (um objeto comum que irá lhe ajudar nesta tarefa) como se segue:
class MyForm {
def personList = [new Person(), new Person()]
}
No arquivo GSP que terá o form, faça assim:
<input name="personList[0].firstname" value="Fred" />
<input name="personList[0].surname" value="Jones" />
<input name="personList[1].firstname" value="Bob" />
<input name="personList[1].surname" value="Smith" />
No controlador que irá receber o POST, você só precisará fazer o bind desta forma:
def form = new MyForm()
bind(form, params)
Pronto, simples assim. Desta forma você continua aproveitando o BIND automático do Grails (no fundo é Bind do Spring) e simplificando o código do seu controller.
[]s
Felipe