i18n message dentro de un service

122 views
Skip to first unread message

jmiguel rodriguez

unread,
Dec 3, 2012, 4:23:18 PM12/3/12
to grailsenc...@googlegroups.com
Hola de nuevo,

Siguiendo vuestros sabios consejos, estoy refactorizando el controller que tenia algo lógica a un service, y me encuentro con que acceder a los messages i18n desde el servicio no parece ser tan trivial como se podia esperar. O, seguramente no encuentro la forma 'facil' de hacerlo.

Dado mi original:
  messageSource.getMessage( code: "mi.codigo.i18n", default: "Hola")    

He encontrado ( http://stackoverflow.com/questions/5903689/how-can-i-use-g-message-outside-a-controller-in-grails ), desde

--------------------------------------------------------------------------
    import org.springframework.context.i18n.LocaleContextHolder as LCH
    ....
    messageSource.getMessage(key, ["myArg"].toArray(), LCH.getLocale())
--------------------------------------------------------------------------

.. que no me gusta porque cambia el formato, a ( http://blog.zmok.net/articles/2008/08/07/grails-internationalization-in-the-service )

--------------------------------------------------------------------------
def getApplicationTagLib(){
def ctx = ApplicationHolder.getApplication().getMainContext()
return ctx.getBean(‘org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib’)
}

y luego:

def g = xyzTools.getApplicationTagLib()
def msg = g.message(code:’message.code.to.translate’)
--------------------------------------------------------------------------

.... y algunas variantes mas 'esotéricas', todas ellas aparentemente antiguas, y nada (que haya sabido encontrar) en los Docs de Grails.  Seguro que hay alguna forma mejor, ¿cual es?)

Gracias por adelantado!



--
 saludos,
 jmiguel

 http://www.jmiguel.eu
 http://www.aerotrastornados.com

Alberto Vilches

unread,
Dec 3, 2012, 5:05:22 PM12/3/12
to grailsenc...@googlegroups.com
Si el servicio lo usas en un controller, puedes pasarle g como parámetro... no lo resuelve pero es menos "laborioso".

class TuController {
    def tuService

    def action() {
       tuService.metodo(g)       
    }
}

A ver si alguien por aquí tiene alguna solución más interesante.


2012/12/3 jmiguel rodriguez <jmiguel....@gmail.com>

--
Has recibido este mensaje porque estás suscrito al grupo "grailsEnCastellano" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a grailsenc...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a grailsencastell...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/grailsencastellano?hl=es.



--
Un saludo.
Alberto Vilches
Twitter: @albertovilches

Jmiguel Rodriguez

unread,
Dec 3, 2012, 5:15:31 PM12/3/12
to grailsenc...@googlegroups.com, grailsenc...@googlegroups.com


El 03/12/2012, a las 23:05, Alberto Vilches <vil...@gmail.com> escribió:

> Si el servicio lo usas en un controller, puedes pasarle g como parámetro... no lo resuelve pero es menos "laborioso".
>


g ?. Eso es nuevo para mi :-).

Me imagino lo que es, mañana lo miro, he soltado el teclado por hoy, que estoy con fiebre... y me vengo a la cama con el tablet.. Puro vicio.

Seguramente hay alguna otra solucion, pero para ir tirando esta me puede valer. Gracias!

Alberto Vilches

unread,
Dec 3, 2012, 5:26:39 PM12/3/12
to grailsenc...@googlegroups.com
Pues g es la variable que te inyecta Grails en tus controllers, para que uses en tus action cosas como esta: g.message(code:’message.code.to.translate’)
Pero claro, en tus servicios no la tienes, así que se la pasas como parámetro! Tómate un gelocatil y mañana te lo miras :b


2012/12/3 Jmiguel Rodriguez <jmiguel....@gmail.com>
--
Has recibido este mensaje porque estás suscrito al grupo "grailsEnCastellano" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a grailsenc...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a grailsencastell...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/grailsencastellano?hl=es.

Alberto Vilches

unread,
Dec 3, 2012, 5:42:19 PM12/3/12
to grailsenc...@googlegroups.com

Iván López

unread,
Dec 3, 2012, 5:43:51 PM12/3/12
to grailsenc...@googlegroups.com
Hola,

nosotros hacemos esto desde un servicio:

import org.springframework.context.i18n.LocaleContextHolder as LCH

class MyService {

       def messageSource

       /**
         * Gets the i18n text associated to the code
         * 
         * @param code The code to look for in i18n property file
         * @param args The optional args
         * 
         * @return the message
         */
        public String message(String code, List args = []) {
                String message = ""
                try {
                        message = messageSource.getMessage(code, args.toArray(), LCH.getLocale())
                } catch (org.springframework.context.NoSuchMessageException e) {
                        message = code
                }

                return message
        }
}

Si en messages.properties tenemos:

my.i18n.key = Hola {0}

Desde cualquier otro servicio inyectamos myService y hacemos:

myService.message("my.i18n.key", ["Iván"])

y obtendremos:

Hola Iván.

Espero que te sirva.

Saludos, Iván.

--
El Blog de Iván López - http://lopezivan.blogspot.com
Twitter - http://www.twitter.com/ilopmar



2012/12/3 Alberto Vilches <vil...@gmail.com>

Alvaro Sanchez-Mariscal

unread,
Dec 4, 2012, 3:02:50 AM12/4/12
to grailsencastellano
¿Y hacéis eso en cada servicio? ¿Una y otra vez? Al menos podíais inyectárselo a todos automáticamente:

        grailsApplication.serviceClasses.each {service ->
            service.metaClass.message = {code, args ->
                def message

                try {
                    message = messageSource.getMessage(code, args.toArray(), LCH.getLocale())
                } catch (nsme) {

                    message = code
                }
                return message
            }
        }

Lo que está claro es que esto es una necesidad recurrente. ¿Alguien se anima a hacer una propuesta en jira.grails.org? ;). Es más, si queréis hacer un pull request, este es el sitio: https://github.com/grails/grails-core/blob/master/grails-plugin-i18n/src/main/groovy/org/codehaus/groovy/grails/plugins/i18n/I18nGrailsPlugin.groovy

Respecto a las formas que comenta José Miguel, para mí la únca opción es ésta (getMessage y usar LocaleContextHolder).

Un saludo.


2012/12/3 Iván López <lopez...@gmail.com>

Iván López

unread,
Dec 4, 2012, 3:08:38 AM12/4/12
to grailsenc...@googlegroups.com
Noooo, tenemos un servicio y desde cualquier otro servicio lo inyectamos y sólo hacemos esto:

myService.message("my.i18n.key", ["Iván"])

Saludos, Iván.

--
El Blog de Iván López - http://lopezivan.blogspot.com
Twitter - http://www.twitter.com/ilopmar



2012/12/4 Alvaro Sanchez-Mariscal <alvaro.sanc...@gmail.com>

jmiguel rodriguez

unread,
Dec 4, 2012, 12:58:37 PM12/4/12
to grailsenc...@googlegroups.com
Hola de nuevo, 


El lunes, 3 de diciembre de 2012 23:42:19 UTC+1, Alberto Vilches escribió:
Mira, aquí está la solución! :)


Si, esta es una de las que vi (creía que la habia enlazado, pero veo que era una previa) pero no me gustaba mucho porque cambia la forma de hacer la llamada. 

Lo de la variable g, visto, muchas gracias. 

Y sobre la forma 'definitiva' de hacer esto, la que mas me gusta es la de Iván, asi que me pongo con ella.  Muchas gracias a todos!


 saludos, 
 jmiguel


jmiguel rodriguez

unread,
Dec 4, 2012, 3:36:32 PM12/4/12
to grailsenc...@googlegroups.com
El 3 de diciembre de 2012 23:26, Alberto Vilches <vil...@gmail.com> escribió:
Pues g es la variable que te inyecta Grails en tus controllers, para que uses en tus action cosas como esta: g.message(code:’message.code.to.translate’)


[...]

Sigo preguntando 'simplezas' relacionadas pero a las que no encuentro solución fácil o por lo menos que me convenzan. Sigo pasado mi logica que estaba en el controlador al servicio y tengo, por ejemplo, cosas como 

 if (!params.club.id) {
      redirect(action: "list")
 }

El params, obviamente, no me llega al servicio. Lo paso como parámetro y listo.  El redirect: ni puedo directamente ni (entiendo) debo hacerlo desde el servicio. ¿Como me lo monto?.  ¿Devuelvo codigos desde el servicio (p.e.: 0 = OK,  -1 (o con una static final int ERROR_NO_ENCONTRADO = -1 ) , -2 para error tipo X, -3 para tipo Y ... etc) y en la vuelta del controller pregunto por el codigo de respuesta? . Un poco chapuza pero me parece lo mas obvio.   

O bien, ¿podria usar el params para devolver los errores?. O tal vez mejor, ¿incluyo mis propios ClaseDeDominio.setError() aparte de los que meta el validate()?. Supongo que los hasErrors() 'sobreviven' desde el servicio hasta el GSP


2ª pregunta: A lo mejor no usais esta técnica sacada del scaffolding, pero para devolver un mensaje de error a una pagina GSP, por ejemplo de validaciones, estoy usando el flash.message . Lo mismo que en la pregunta original de este hilo, ¿como accedo a flash desde el servicio?. O, si usara lo que comentaba en el punto anterior de ClaseDeDominio.setError() podria hacer en el controller algo como preguntar por 'mi error generico' para hacer el flash.message(). ¿como lo veis?

Sigo jugando. Muchas gracias a todos!. 

(Alberto, Ivan y Álvaro: os estais buscando que las proximas cañas del MadridGUG vayan por mi cuenta... :-))


--

Alberto Vilches

unread,
Dec 4, 2012, 4:21:11 PM12/4/12
to grailsenc...@googlegroups.com
- Validaciones, redirecciones y demas, va todo en el controller, nunca en el servicio. Es decir, tu llamas al servicio solo cuando ya tienes tus datos validados y haces (en general) solo una operación que o funciona o falla. Toda la logica de gestion de errores en función de los parámetros se queda en el controller.

- Personalmente, si no voy a hacer nada muy complejo, yo no meto un servicio para eso. Puede que alguno de la lista se esté tirando de los pelos ahora mismo, pero oye, yo tengo algunos controllers asi (código real):

    def addProvider(String name, String parser, String channel) {
        name = name?.toLowerCase()?.trim()
        if (name) {
            Provider p = Provider.findOrCreateWhere(name: name)
            p.parser = parser
            p.channel = Provider.ProviderChannel."$channel"
            p.save()
            flash.message = "Done"
        }
        redirect action:"index"
    }


- Si necesitas acceder a varias valores de los parametros, lo ideal es usar command objects: http://grails.org/doc/latest/guide/single.html#commandObjects

- flash.message es el scope para guardar datos después de un redirect (mira http://en.wikipedia.org/wiki/Post/Redirect/Get para entender porque se usan redirects), pero forma parte del "modelo" que envias a la vista en el MVC, por lo tanto, tu servicio no debería intentar acceder al contexto flash. Tu servicio escribe, lee, modifica, envia mails o lo que sea, y cuando acaba, es el controller el que decide que enviarle a la pagina.

- Yo prefiero que nos invites a cenar, me gusta la comida japonesa y la carne a la brasa :bbbb


2012/12/4 jmiguel rodriguez <jmiguel....@gmail.com>
--
Has recibido este mensaje porque estás suscrito al grupo "grailsEnCastellano" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a grailsenc...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a grailsencastell...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/grailsencastellano?hl=es.

Iván López

unread,
Dec 4, 2012, 5:03:11 PM12/4/12
to grailsenc...@googlegroups.com
Buenas,

mis respuestas:

- Las validaciones se deben hacer en el controller. Es "lo único" para lo que sirve. Como dice Alberto, sólo debes llamar al servicio cuando sepas que los parámetros y los objetos de dominio que le pases son válidos.
- Cuando en un servicio haces un .save() de un objeto del dominio y hay errores, en objeto.errors tienes toda la lista de errores. Puedes hacer un render de la vista que corresponda pasándole el objeto del dominio y en esa vista comprobar si el objeto tiene errores para mostrar un mensaje de error genérico. También puedes preguntar si un atributo concreto tiene errores para marcar ese campo de alguna forma (con una clase css que lo ponga rojo,...).
- No tiene sentido acceder a flash desde un servicio. Por ejemplo tienes el típico formulario donde rellenas campos y al final haces el bind de todos los campos e intentas salvar el objeto. Lo que puedes hacer si falla el save es un render de la vista de creación y marcar los campos erróneos. Adicionalmente puedes poner algún mensaje general en flash para mostrarlo desde la gsp, pero también lo podrías pasar en el model.
- Por el contrario que Alberto, yo pongo toda la lógica siempre en servicios, aunque sea muy sencilla. Me permite hacer los test por separado y tenerla centralizada.
- Para validaciones complejas o repetidas en varias acciones, lo mejor CommandObjects, son muy potentes y dejan el código del controller muy limpio. 

P.D: Alberto, deja de boicotear mi charla de Greach :-P
P.D2: Por cierto, yo también prefiero la carne a la brasa...

Saludos, Iván.

--
El Blog de Iván López - http://lopezivan.blogspot.com
Twitter - http://www.twitter.com/ilopmar



2012/12/4 Alberto Vilches <vil...@gmail.com>

Jmiguel Rodriguez

unread,
Dec 4, 2012, 5:27:38 PM12/4/12
to grailsenc...@googlegroups.com

Hola!,

El 04/12/2012, a las 23:03, Iván López <lopez...@gmail.com> escribió:

Buenas,

mis respuestas:

- Las validaciones se deben hacer en el controller. Es "lo único" para lo que sirve. Como dice Alberto, sólo debes llamar al servicio cuando sepas que los parámetros y los objetos de dominio que le pases son válidos.

Entendido. No es el caso, pero, imaginemos que el servicio se usa para que un cliente remoto, usando tu API llame a este metodo. Ahi no puedes fiarte de que los valores sean buenos. Supongo que en ese caso habria que exponer otro servicio.


- Cuando en un servicio haces un .save() de un objeto del dominio y hay errores, en objeto.errors tienes toda la lista de errores. Puedes hacer un render de la vista que

Perfecto, aclarado.

. Lo que puedes hacer si falla el save es un render de la vista de creación y marcar los campos erróneos. Adicionalmente puedes poner algún mensaje general en flash para mostrarlo desde la gsp, pero también lo podrías pasar en el model.

Ok, a esta forma de hacerlo me referia: preguntando si hay algun error mediante el hasErrors(), que puede que lo haya asignado yo mismo, no solo el validate/save. Perfecto :-)

- Por el contrario que Alberto, yo pongo toda la lógica siempre en servicios, aunque sea muy sencilla. Me permite hacer los test por separado y tenerla centralizada.

Tomo nota. A mi me esta costando acostumbrarme a poner 'cada cosa en su sitio', en parte porque a veces (como estas ultimas preguntas) no se donde tiene que ir, y ya que estoy empezando, que menos que intentar coger buenos habitos. Aun no tengo/tenemos costumbre de test...  en la mayoria de las veces no sabemos ni como plantearlos, ni que/como probar. Se que es lo suyo asi que intentare separar responsabilidades como recomiendas.

- Para validaciones complejas o repetidas en varias acciones, lo mejor CommandObjects, son muy potentes y dejan el código del controller muy limpio. 

Ok, Alberto gracias por el enlace. Luego lo veo mas despacio pero parece algo como clases de dominio sin reflejo en base de datos, no? (Sorry si acabo de soltar una burrada, solo he echado un vistazo rapido). Y gracias tambien por el cacho de código, con mi nivel actual de cualqueir cosa veo cosas de las que aprender :-).  Creo que voy a 'forkear' medio github para intentar aprender :-)


P.D2: Por cierto, yo también prefiero la carne a la brasa...
- Yo prefiero que nos invites a cenar, me gusta la comida japonesa y la carne a la brasa :bbbb


 Como tengo alergia al anisakis (y ya he tenido un susto grave) lo del japones me acojona bastante. Lo de la brasa... todo se andará ;-)

David Santamaria

unread,
Dec 5, 2012, 3:48:20 AM12/5/12
to grailsenc...@googlegroups.com
Venga ahi, esto me gusta!
Ddecir que estaba por escribir en el hilo, porque lo de los mensajes i18n en un service, estaba empezando a ser un "code smell" en toda regla (no digo que yo no los tenga, pero por comentar), y es que si un Service tiene que encargarse de "buscar un mensaje", en mi opinion hay algo ahi que no encaja. Por aportar (aunque ya habeis comentado muchas de las cosas):

- Validaciones, control de errores, recepcion de parametros (con su correpondiente tratamiento si lo necesitas), preparacion de los modelos, flujos de las peticiones (redirect,forward,...), va todo en el controller.
- Busquedas de entidades en las entidades con Criterias y wheres a las entidades (namedQueries y metodos staticos).
- Actualizaciones masivas, y operaciones en batch a un service, pero con cuidado, al menos yo (@Ivan espero no pisarte tampoco la charla) he estado "abusando" de los Services durante años, y creo que he dicho ya basta, ahora necesito un buen motivo para meter algo a un Service (que sea una operacion transaccional, por ejemplo)

My two Cents,



--
Has recibido este mensaje porque estás suscrito al grupo "grailsEnCastellano" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a grailsenc...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a grailsencastell...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/grailsencastellano?hl=es.



--
David.

Jmiguel Rodriguez

unread,
Dec 6, 2012, 9:54:57 AM12/6/12
to grailsenc...@googlegroups.com
Hola David,

El 05/12/2012, a las 09:48, David Santamaria <d.high...@gmail.com> escribió:

> Venga ahi, esto me gusta!
> Ddecir que estaba por escribir en el hilo, porque lo de los mensajes i18n en un service, estaba empezando a ser un "code smell" en toda regla (no digo que yo no los tenga, pero por

:-) . Me gusta la expresion. Y gracias por tus sugerencias. Yo tengo cierta experiencia en programacion en general y precisamente como hay tantas formas de hacer las cosas ando por aqui preguntando temas que tal vez os parezcan muy obvios


> masivas, y operaciones en batch a un service, pero con cuidado, al menos yo (@Ivan espero no pisarte tampoco la charla) he estado "abusando" de los Services durante años, y creo que he dicho ya basta, ahora necesito un buen motivo para meter algo a un Service (que sea una operacion transaccional, por ejemplo)

Donde lo metes si no?. En controller si es 'simple y genérico' y en la propia clase de dominio si es relacionado con ella?. Pregunto inocentemente, eh?. Porque yo estaba sacando la conclusion de este hilo de que 'casi todo' debe ir al servicio.

Gracias!

David Santamaria

unread,
Dec 6, 2012, 11:04:50 AM12/6/12
to grailsenc...@googlegroups.com
Hola,

:-) . Me gusta la expresion.
 
Obviamente no es mia, pero por si alguno quiere profundizar en ella

 
Y gracias por tus sugerencias. Yo tengo cierta experiencia en programacion en general y precisamente como hay tantas formas de hacer las cosas ando por aqui preguntando temas que tal vez os parezcan muy obvios

IMO, el tema es que Grails no es un MVC al uso, por lo que a veces donde meter las cosas no resulta tan obvio.
 
> masivas, y operaciones en batch a un service, pero con cuidado, al menos yo (@Ivan espero no pisarte tampoco la charla) he estado "abusando" de los Services durante años, y creo que he dicho ya basta, ahora necesito un buen motivo para meter algo a un Service (que sea una operacion transaccional, por ejemplo)

Donde lo metes si no?.
En controller si es 'simple y genérico' y en la propia clase de dominio si es relacionado con ella?.  Pregunto inocentemente, eh?.

Como hemos comentado, lo simple al controller, ultimamente le doy mas resposabilidades a las entidades de dominio (no mas, las que deben ser suyas), ya que antes sufria de Objetos de dominio anemicos (http://en.wikipedia.org/wiki/Anemic_domain_model ) y es algo que estoy cambiando. Piensa de verdad quien tiene la responsabilidad ultima de hacer esa operacion que necesitas hacer, y dale a esa clase la responsabilidad que debe y merece.

Y por ultimo, algo que pecamos mucho, existe grails-app/services para los servicios, grails-app/domains para las clases de dominio, grails-app/controllers para los controladores, pero se nos suele olvidar que existe una carpeta llamada /src/groovy, no tengas miedo de meter Helpers, Utilities, y Entidades que no tengan que ser del dominio de la aplicacion, no persistentes, y mil cosas mas.
 
Porque yo estaba sacando la conclusion de este hilo de que 'casi todo' debe ir al servicio.
 
Esa es la idea que yo quiero quitarte de la cabeza (es mi opinion, ojo), abusar de los Services es malo, los services tienen ciertas propiedades, son transaccionales por defecto, permiten el autowire/inyeccion de dependencias en otros artefactos, permiten scopes (singletomn por defecto), pero que pasa si el codigo que vas a ejecutar no necesita nada de eso?? ahi es donde yo quiero llegar.

Una vez mas, me mola mil este hilo, aportaciones/criticas a mi ida de pinza son aceptadas!
Un saludo.


--
David.

David Santamaria

unread,
Dec 6, 2012, 11:29:20 AM12/6/12
to grailsenc...@googlegroups.com
Por cierto, comentar que he leido en muchos sitios lo contrario (lo comento por si alguien esta pensando: "pues yo tenia entendido lo contrario"), y es que en los libros de Grails, y en la documentacion dicen lo contrario, Cito textualmente de aqui:


"Services in Grails are the place to put the majority of the logic in your application, leaving controllers responsible for handling request flow with redirects and so on."

Yo simplemente quiero pensar que esto esta hecho con una idea muy basica, hacer entender que es cada cosa en Grails, y es que obviamente prefiero que mi logica este en un service a que este en un Controller, solo digo que quizas (para mi) a llegado el momento de darle una vuelta de tuerca a ese concepto.

Un saludo.

--
David.

Alberto Vilches

unread,
Dec 6, 2012, 11:30:15 AM12/6/12
to grailsenc...@googlegroups.com
Hilo interesante. Yo uso los servicios cuando necesito una entidad que haga ciertas acciones con un agente externo del proyecto o es una funcionalidad horizontal que se usa por toda la aplicación. Por ejemplo, un servicio para enviar mails, otro para la pasarela de pago, otro para acceder al buscador, otro para el recomendador, un servicio por cada cliente de webservices que se conecta con una editorial para descarga su catálogo, etc. También tengo un servicio por cada Job de Quartz. El resto de operaciones que están involucradas con el modelo de datos las dejo en el dominio, buscando lo que se conoce como "modelo rico" en contraposición al "modelo anémico". El modelo anémico es tener tus clases de dominio solo con sus propiedades, sin métodos que tengan acciones. Los encargados de manejar el modelo son los dao o servicios. Yo prefiero no hacerlo así. Por ejemplo, si un usuario hace una compra, tengo un metodo purchase dentro del usuario que se encargará de iniciar una transacción si es necesario, crear la entidad purchase y asociados, llamar al servicio de la pasarela de pago y si todo va bien, llamar al servicio de envio de correos. Pero no tengo un servicio para comprar, por ejemplo.

Iván López

unread,
Dec 6, 2012, 11:34:25 AM12/6/12
to grailsenc...@googlegroups.com
Buenas,

estoy tomando nota de todo lo que comentais para añadirlo/tocarlo en mi charla de Greach "Todo lo que me hubiera gustado saber cuando empecé a desarrollar con Grails". Espero veros allí en el turno de preguntas :-)

Saludos, Iván.
--
El Blog de Iván López - http://lopezivan.blogspot.com
Twitter - http://www.twitter.com/ilopmar



2012/12/6 David Santamaria <d.high...@gmail.com>

--

Alfredo Casado

unread,
Dec 6, 2012, 4:26:24 PM12/6/12
to grailsenc...@googlegroups.com
Buenas, interesante hilo.

Lo de colocar toda la logica en los servicios y tener dominios anemicos... personalmente me parece volver a la programación estructurada, servicios sin estado que son basicamente funciones que acceden a un modelo de datos global: el dominio. 

MI opinión de como estructurar las cosas en un app grails:

- Los controles: logica de navegación, llaman a quien hace el trabajo (dominio o servicio) y redirigen o renderizan la vista adecuada. En general todo lo que tenga que ver con HTTP o particularidades de una app web (ej: la sesión) es lo que debería manejar aqui.

- Los command: validaciones de datos que vienen por HTTP, en casos muy sencillos se podría hacer en el controlador, pero por lo general creo que es buena idea separar este concepto.

- El dominio: El mapeo con la bd y toda la logica asociada a ese objeto dominio. En general intentar seguir el patron experto: "quien debe contener X logica es quien tiene la mayor información para hacerlo". Una cosa buena de grails para construir modelos ricos es que es muy sencillo inyectar cosas en las clases de dominio (algo no tan trivial en un proyecto spring-hibernate en java) y esto en mi opinión permite construir modelos ricos mucho más facilmente.

- Servicios: logica que implica el manejo de varias clases de dominio. Ejemplo tipico, transferencia de dinero de una cuenta a otra quien se encarga la cuenta que recibe o la que envia?, pues ante la duda mejor un servicio.

Y como comentaba alguien antes, la carpeta src/groovy también esta para algo!. Al principio yo creo que también pecamos bastante de meter muchas cosas como servicios que podrían/deberían ser simples clases groovy, por ejemplo, llamar a un webservice externo ¿que ganas con hacerlo como un servicio?. Por ejemplo, nosotros hicimos como servicios llamadas a un webservice externo y lo más probable es que tengamos que cambiarlo porque estos mismos servicios los vamos a reutilizar en un proceso de back-office que no es una app grails.

En general a mi me gustan las ideas de Domain Driven Design, y por lo general grails permite seguir esas ideas (la parte que "menos" el tema de Gorm y el dominio que esta muy pegado a la bd, pero por contra esto ahorra bastante tiempo y tampoco es cuestión de pasarse de purista con los patrones o los estilos de diseño).

Alberto Vilches

unread,
Dec 6, 2012, 4:59:50 PM12/6/12
to grailsenc...@googlegroups.com
De acuerdo en todo salvo en una cosa (y ya me da miedo llevarte la contrario Alfredo, pero me voy a arriesgar ;). Tomando el ejemplo del cliente de servicio web ¿lo haces en un servicio o en una clase suelta aparte? Hacerlo en un servicio me permite dos cosas que no me permite una clase suelta en src/groovy (o al menos, no tan facilmente): definir el scope y ahorrarme el gestionar la instancia de la clase suelta (inyección).

- Un servicio (por defecto) es un singleton y Spring me lo inyecta en mis clases de dominio, controladores y otros servicios. Si lo hago con una clase suelta, tengo que gestionarme yo el singleton (wtf!) o hacerlo con métodos estáticos (woooo!)
- Puede que el cliente de mi servicio web no pueda ser un singleton por la razón que sea, sino que es una clase de usar y tirar. Si me hago una clase suelta, tengo que hacerme un new MiCliente() y gestionar yo la instancia. Pero si lo hago con un servicio con scope prototype ya lo tengo: cada vez que se inyecta Spring se encarga de crear una nueva instancia. Y siempre puedo afinar más y hacer que el scope sea de session o request, lo que me parece mucho más potente.
- Y si la razón para crear una clase suelta es hacerla en Java para ser reutilizada en otros proyectos, siempre puedo convertir una clase Java en un servicio usando el resources.groovy, y Spring ya se encarga de inyectar mi clase Java como si fuera servicio en cualquier lugar.
- Y si lo que no gusta es que el servicio sea transactional, se desactiva esa opción...

¿Para que uso entonces src/groovy o src/java? Pues para clases sueltas de verdad, como por ejemplo, un bean con x atributos que uso para meter las credenciales de la pasarela de pago y que uso en diferentes sitios de la aplicación entre varios servicios (se lo van pasando unos a otros). No es un comando porque lo creo yo a mano (no me viene de una petición), ni tampoco una clase de dominio porque no se persiste, así que la mando a src/groovy.


PD: patrones! os acordáis de estos? que tiempos eh! http://www.corej2eepatterns.com/images06/figure06_02.gif



2012/12/6 Alfredo Casado <casado....@gmail.com>



--

Alfredo Casado

unread,
Dec 6, 2012, 8:14:07 PM12/6/12
to grailsenc...@googlegroups.com
Digamos que en el caso de que no uses transacciones lo único que te ahorras haciendola servicio es una declaración en el resources.groovy para que spring la inyecte. Por la parte negativa tienes que acordarte de desactivar las transaciones y tienes que llamar a tu clase blablablaService que es un poco feuno. Tampoco es que haya una gran diferencia, y precisamente por eso, porque no hay gran diferencia entre hacer una clase y un servicio de momento me quedo con la opción más sencilla que es una clase. 

jmiguel rodriguez

unread,
Dec 7, 2012, 4:34:28 AM12/7/12
to grailsenc...@googlegroups.com
El 6 de diciembre de 2012 17:34, Iván López <lopez...@gmail.com> escribió:
Buenas,

estoy tomando nota de todo lo que comentais para añadirlo/tocarlo en mi charla de Greach "Todo lo que me hubiera gustado saber cuando empecé a desarrollar con Grails". Espero veros allí en el turno de preguntas :-)

Si te hacen falta 'betas' para escucharla en primicia ya sabes donde estoy... ;-)

--

Jose Mª Fernandez

unread,
Dec 7, 2012, 5:13:58 AM12/7/12
to grailsenc...@googlegroups.com
Este hilo me lo guardo con la estrellita para leerlo tranquilamente un día relajadamente! es una joya! :-)


--
Has recibido este mensaje porque estás suscrito al grupo "grailsEnCastellano" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a grailsenc...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a grailsencastell...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/grailsencastellano?hl=es.



--
José María Fernández

sirdaiz

unread,
Apr 11, 2013, 10:45:41 AM4/11/13
to grailsenc...@googlegroups.com
Volviendo a este tema, tengo el sgte problema, estoy usando grails 1.3.4 y mi controller:

import org.springframework.context.i18n.LocaleContextHolder as LCH

class PruebaController {

def messageSource

def changeLocale = {

            println "ENTRA A BOOTSTRAP"+messageSource.getMessage("pruebaPepe", LCH.getLocale())

            redirect(controller: "prueba", action: "list")
    }
}

Pero me da este error:

No signature of method: org.codehaus.groovy.grails.context.support.PluginAwareResourceBundleMessageSource.getMessage() is applicable for argument types: (java.lang.String, java.util.Locale) values: [pruebaPepe, es]


Saludos


Domingo Suárez Torres

unread,
Apr 11, 2013, 11:55:18 AM4/11/13
to grailsenc...@googlegroups.com

el error es esta linea:

println "ENTRA A BOOTSTRAP"+messageSource.getMessage("pruebaPepe", LCH.getLocale())

Cambiala por:
println ( "ENTRA A BOOTSTRAP"+messageSource.getMessage("pruebaPepe", LCH.getLocale()))

Saludos

2013/4/11 sirdaiz <pepinf...@gmail.com>

--
Has recibido este mensaje porque estás suscrito al grupo "grailsEnCastellano" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus correos electrónicos, envía un correo electrónico a grailsencastell...@googlegroups.com.

Para publicar una entrada en este grupo, envía un correo electrónico a grailsenc...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/grailsencastellano?hl=es.
Para obtener más opciones, visita https://groups.google.com/groups/opt_out.
 
 

Domingo Suárez Torres

unread,
Apr 11, 2013, 11:57:13 AM4/11/13
to grailsenc...@googlegroups.com
Conteste muy rapido, el error es por los parentesis opcionales, en este caso no es opcional usarlos, es obligatorio debido a que estas usando una concatenacion y llamada a metodos, entonces Groovy no puede idetificar donde se termina la llamada a "println"





2013/4/11 Domingo Suárez Torres <domingo...@gmail.com>

sirdaiz

unread,
Apr 11, 2013, 12:02:01 PM4/11/13
to grailsenc...@googlegroups.com
Hola, gracias por la respuesta, el problema no es ese ya lo probe y nada, la solucion a sido:

println "ENTRA A BOOTSTRAP: "+messageSource.getMessage("pruebaPepe", null ,LCH.getLocale())

Ahora intento pasar parametros y falla

Saludos

Domingo Suárez Torres

unread,
Apr 11, 2013, 12:07:04 PM4/11/13
to grailsenc...@googlegroups.com
Tienes razón,
que error obtienes ahora? o porque dices que falla?




2013/4/11 sirdaiz <pepinf...@gmail.com>

--
Has recibido este mensaje porque estás suscrito al grupo "grailsEnCastellano" de Grupos de Google.

Rafael Gutiérrez

unread,
Apr 11, 2013, 12:10:46 PM4/11/13
to grailsenc...@googlegroups.com
Intenta con un GString, asi:

println "ENTRA A BOOTSTRAP: ${messageSource.getMessage("pruebaPepe", null ,LCH.getLocale())}"

aunque el problema de los parametros puede ser otra cosa


2013/4/11 Domingo Suárez Torres <domingo...@gmail.com>
Tienes razón,
Message has been deleted

sirdaiz

unread,
Apr 11, 2013, 12:19:57 PM4/11/13
to grailsenc...@googlegroups.com
la solucion es esta por si a alguien le sirve:

def Object[] args = ["aaa"]
println "ENTRA A BOOTSTRAP: "+messageSource.getMessage("pruebaPepe", args ,LCH.getLocale())

Saludos
Reply all
Reply to author
Forward
0 new messages