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

Aplicação Swing em Groovy para Regular Expressions

Hoje um usuário (Jeremy Rayner) da lista do Grails nos enviou uma pequena aplicação desktop escrita em Groovy que pode ser bastante útil para testar Regular Expressions. É tão pequena que vou colocar o código fonte abaixo. Esta aplicação faz o highlight das partes de um texto que você colocar de acordo com a expressão regular inserida. Veja screen shot abaixo. Para executar basta salvar este código num script RegexCoach.groovy e executar o comando: groovy RegexCoach

// Groovy Regex Coach - Copyright 2007 Jeremy Rayner
// inspired by http://weitz.de/regex-coach/
import java.awt.*
import java.awt.event.*
import java.util.regex.*
import javax.swing.*
import javax.swing.text.DefaultHighlighter
import groovy.swing.SwingBuilder

// define the view
def swing = new SwingBuilder()
def gui = swing.frame(title:'The Groovy Regex Coach', location:[20,40], size:[600,500], defaultCloseOperation:WindowConstants.EXIT_ON_CLOSE) {
panel(layout:new BorderLayout()) {
splitPane(orientation:JSplitPane.VERTICAL_SPLIT, dividerLocation:150) {
panel(layout:new BorderLayout()) {
label(constraints:BorderLayout.NORTH, text:'Regular expression:')
scrollPane(constraints:BorderLayout.CENTER) {textPane(id:'regexPane')}
}
panel(layout:new BorderLayout()) {
label(constraints:BorderLayout.NORTH, text:'Target string:')
scrollPane(constraints:BorderLayout.CENTER) {textPane(id:'targetPane')}
panel(constraints:BorderLayout.SOUTH, layout:new FlowLayout()) {
button('<<-', id:'scanLeft')
button('->>', id:'scanRight')
}
}
}
}
}
def highlighter = new RegexHighlighter(swing:swing)
swing.regexPane.addKeyListener(highlighter)
swing.targetPane.addKeyListener(highlighter)
swing.scanLeft.addActionListener(highlighter)
swing.scanRight.addActionListener(highlighter)
gui.show()

class RegexHighlighter extends KeyAdapter implements ActionListener {
def swing // reference to the view
int scanIndex // how many times to execute matcher.find()
def orange = new DefaultHighlighter.DefaultHighlightPainter(Color.ORANGE)
def yellow = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW)
def red = new DefaultHighlighter.DefaultHighlightPainter(Color.RED)

// react to user actions
public void actionPerformed(ActionEvent event) {
if (event.actionCommand == '<<-') {scanIndex = Math.max(scanIndex - 1, 0)}
if (event.actionCommand == '->>') {scanIndex++}
doHighlights()
}
public void keyReleased(KeyEvent event) {
scanIndex = 0
doHighlights()
}

// the main regex logic
private void doHighlights() {
try {
swing.regexPane.highlighter.removeAllHighlights()
swing.targetPane.highlighter.removeAllHighlights()
def regex = swing.regexPane.text
def target = swing.targetPane.text
def matcher = (target =~ regex)
int scan = 0
while (scan < scanIndex) {
matcher.find()
scan++
}
if (matcher.find()) {
int i = 0
while (i++ < matcher.groupCount()) {
swing.targetPane.highlighter.addHighlight(matcher.start(i), matcher.end(i), orange)
}
swing.targetPane.highlighter.addHighlight(matcher.start(), matcher.end(), yellow)
} else {
scanIndex = Math.max(scan - 1, 0)
if (scanIndex > 0) {doHighlights()}
}
} catch (PatternSyntaxException e) {
swing.regexPane.highlighter.addHighlight(e.index, e.index + 2, red)
}
}
}




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