Numărul 9
Last issue

Dispozitive mobile

Get it on Google Play

Abonare revistă



Numerele anterioare


Numărul 22
Issue:22
Numărul 21
Issue:21
Numărul 20
Issue:20
Numărul 19
Issue:19
Ediții anterioare

Introducere în Grails (III)

Sper că articolele precedente despre Grails v-au trezit interesul asupra framework-ului. Acesta este ultimul articol din seria “Introducere în Grails”, prezentând următoarele topicuri:

  • Validatori custom
  • Internaționalizarea
  • Librării de tag-uri
  • Mapări de url-uri
  • Persistență

Validatori custom

În articolele precendente am discutat despre constrângeri care se aplică obiectelor domeniu. Grails oferă un set bogat de constrângeri: nullable, blank, size, etc. În cazul în care dorim validări adiționale asupra obiectelor noastre de domeniu, va trebui să ne scriem validatorii noștri.

Să încercăm să adăugam un validator custom care să nu permită folosirea cuvântului “test” ca parte a unui mesaj pe care vrem să îl postăm. În primul rând va trebui să specificăm folosirea unui validator custom:

static constraints = {
  message size:5..100, blank:false, validator:
  {val, obj -> obj.messageValidator(val)}	
}	

Apoi va trebui să definim metoda de validare în clasa Message:

private messageValidator(val) {
 if (val.toLowerCase().contains(„test”)) {
   return „test.is.not.allowed”
 }
 return true
}

Validatorul primește ca parametru valoarea de validat (în cazul nostru textul mesajului de postat). Dacă textul este ok relativ la regulile noastre, metoda de validare va returna “true”. Orice altă expresie returnată va fi considerată ca validare eșuată la apelarea metodei “validate” pentru obiectul nostru Message și aplicația va afișa un mesaj de eroare. Vom vedea în secțiunea următoare cum să customizăm mesajele aplicației noastre, adăugând suport pentru internationalizare.

Internaționalizarea

Majoritatea aplicațiilor web sunt destinate utilizatorilor care vorbesc limbi diferite. De asemenea, mesajele default pe care Grails le pune la dispoziție pentru a trata erori, nu sunt întotdeauna user-friendly (vezi mai sus). Suportul de internaționalizare al Grails se bazează pe Spring MVC. Setările de limbă sunt implementate folosind obiectul Locale, asociat cu sesiunea unui user.

Grails stochează pachetele de mesaje în folderul grails-app/i18n ca fișiere de proprietăți Java. Convenția este că pachetele de mesaje încep cu “messages” și se termină cu numele locale-ului. Câteva exemple:

  • messages.properties
  • messages_en.properties
  • messages_pt_BR.properties
  • messages_ro.properties

Pentru aplicația noastră vom folosi doar două fișiere:

  • messages.properties,
  • messages_ro.properties.

Să luam exemplul de mai sus, unde mesajul de eroare pus la dispoziție de Grails nu a fost foarte user friendly și să adăugam textul nostru de eroare în fișierele de proprietăți.

Deschide https://github.com/tavibolog/GrailsSocialNetwork/tree/master/grails-app/i18n/messages.properties și adaugă:

message.name=My message
test.is.not.allowed=Test is not allowed!

Acum încearcă să postezi un mesaj care conține cuvântul “test”. Vom observa două lucruri:

test.is.not.allowed=Test nu este admis!
message.name=Mesajul meu

După cum ați observat am mai adăugat o pereche cheie-valoare pentru un nou text și am dori să o folosim în fișierele gsp. Aceasta este foarte simplu în Grails. Deschide https://github.com/tavibolog/GrailsSocialNetwork/blob/master/grails-app/views/message/create.gsp și caută stringul “Message” și înlocuiește-l cu: <g:message code=”message.name”/>. Acest tag va cere Grails să caute în fișierele de internaționalizare după o cheie numită “message.name” și să o folosească în funcție de setarea de limbă curentă.

Aplicația noastră nu are un selector de limbă, dar Grails ne ajută să testăm schimbarea setării de limbă, expunând un parametru de request, numit “lang” care poate fi folosit pentru selectarea limbii în aplicația noastră. Dacă dorim să schimbăm limba aplicației în română, va trebui să facem un request folosind “lang=ro”, ca și mai jos:

http://localhost:8080/GrailsSocialNetwork/message/create?lang=ro

Pagina de creare a unui mesaj va arăta semi-internaționalizat (iar mesajul de eroare venit de la validatorul custom va fi afișat de asemenea în română):

Câteodată avem nevoie de suport de internaționalizare la nivelul controllerului.

Să încercăm să adăugăm suport de internaționalizare pentru mesajul de eroare afișat în cazul în care combinația user-parolă nu este validă.

Implementarea curentă (https://github.com/tavibolog/GrailsSocialNetwork/blob/master/grails-app/controllers/com/todaysoftmag/gsn/UserController.groovy ) este mai jos:

render(view: „login”, model: [message: “Wrong username or password!”]) 

Localizarea este făcută folosindu-se tagul “message”; tot ce trebuie să facem este să apelăm tagul cu parametri necesari. Iată codul schimbat:

render(view: „login”, model: [message: message(code:”error.wrong”, args:[message(code: „error.usernameorpassword”)])])

Deși pare puțin complicat, s-a vrut prezentarea suport de parametri în conținutul internaționalizat folosind Grails. În cazul nostru, vrem să afișăm un text definit de cheia “error.wrong”, care are la rândul ei parametri, definiți în lista de argumente “args” – aceștia putând fi internaționalizați. În ambele cazuri, trebuie doar să apelăm tagul “message” cu parametri necesari: “code” – specifică textul de afișat și “args” – specifică eventuali parametri de înlocuit în textul internaționalizat.

Următorul pas este să definim noile string-uri în messages.properties:

error.wrong=Wrong {0}
error.usernameorpassword=username or passwordd

și messages_ro.properties:

error.wrong={0} sunt gresite
error.usernameorpassword=username sau parola

Acum, dacă încercăm să ne logăm cu o combinație invalidă de user și parolă, specificând o setare de limbă, aplicația va afișa un mesaj de eroare localizat.

Librării de tag-uri

Librăriile de tag-uri sunt o modalitate elegantă de a construi componente re-utilizabile în fișierele gsp. Librăriile de tag-uri sunt stocate în /grails-app/taglib. Librăriile de tag-uri sunt definite ca și clase Groovy și pot avea mai multe metode. Ele pot să aibă și namespace-uri pentru a nu intra în coliziune cu tag-urile standard Grails sau tag-uri definite de alți developeri.

Să încercăm să construim o librărie de tag-uri care va fi folosită să afișeze un mesaj de întâmpinare pentru userii aplicației noastre. Momentan acesta este implementată în list.gsp (https://github.com/tavibolog/GrailsSocialNetwork/blob/master/grails-app/views/message/list.gsp ):

<g:if test=”${session?.user}”>
<div id=”login”>Hi ${session.user}
</div>
</g:if>

Abordarea acesta are mai multe probleme:

  • Funcționează doar în acest view;
  • Nu afișează un mesaj dacă userul nu este logat în aplicație;
  • Este mai complicat de menținut pentru că va trebui să modificăm fișierul gsp de câte ori vrem să schimbăm implementarea și eventual va trebui replicat și în alte fișiere.

Soluția este să folosim o librărie de tag-uri. Pentru a crea o librărie de taguri, rulăm următoarea comandă:

create-tag-lib com.todaysoftmag.gsn.Display

Aceasta va crea o librărie de taguri numită DisplayTagLib și fișierul de test asociat: DisplayTagLibTests.

package com.todaysoftmag.gsn
 
class DisplayTagLib {
static namespace = „display”
	
def greetings = {attrs ->
  if (session && session.user) {
    out << „<div id=”login”>Hello,
         „ + session.user + „!</div>”
   } else {
    out << g.link(controller: „user”, 
    action: „login”){„not signed in”}
      }
    }
	
}

Să observăm acum implementarea și să o explicăm:

  • Numele pachetului este la fel ca și pentru orice clasă Java/Groovy;
  • “namespace” – este definit pentru a proteja librăria noastră de coliziuni cu alte librării standard Grails sau definite de alți developer sau pentru a plasa metodele librăriei în contextul potrivit. Pentru a folosi metoda definită în librărie, trebuie doar să o apelăm: <display:greetings/>;
  • “greetings” este numele metodei pe care librăria noastră îl expune, definit ca și closure;
  • “attrs” – este un hash care conține parametri ce sunt pasați tagului de către codul client. În cazul în care apelăm tagul ca și: <disply:greetings greetingName=’Hi’/>, în metoda “greetings” o sa avem access la attrs[“greetingName”];
  • Metodelei librăriei de taguri au acces la sesiunea userului;
  • “out” – este streamul în care se scrie rezultatul metodei;
  • Logica tag libului este: verificăm dacă există o sesiune și un obiect “user” pe sesiune. Dacă da, atunci afișăm un salut pentru utilizator. Dacă nu, afișăm un link în care cerem utilizatorului să se logheze. Ca exercițiu, puteți adăuga suport de internaționalizare pentru acest link.

Acum că am definit librăria de tag-uri, să o și folosim în locul potrivit: main.gsp (https://github.com/tavibolog/GrailsSocialNetwork/blob/master/grails-app/views/layouts/main.gsp ).

Aceasta este scheletul care include toate paginile aplicației, deci pare locul potrivit să afișăm mesajul de întâmpinare:

<div id=”grailsLogo” role=”banner”><a href=”http://grails.org”><img src=”${resource(dir: ‚images’, file: ‚grails_logo.png’)}” alt=”Grails”/></a></div>
<display:greetings/>
<g:layoutBody/>

Mapări de Urluri

Grails oferă un suport ușor de folosit pentru a manipula url-urile aplicației. “Locul de joacă” este UrlMappings.groovy, stocat în grails-app/conf (https://github.com/tavibolog/GrailsSocialNetwork/blob/master/grails-app/conf/UrlMappings.groovy ).

Până acum, aplicația noastră folosea ca și pagină de start pagina default pusă la dispoziție de Grails: http://localhost:8080/GrailsSocialNetwork . Acum, am dori să schimbăm asta și să afișam pagina de login. Mai mult, am dori să afișăm un nume mai simplu pentru url-ul de login, care este definit default ca și ”/user/login”. Am prefera ceva mai simplu, cum ar fi “/login”.

Pentru a realiza acest lucru avem nevoie de câteva schimbări în fișierul de mapări de url-uri:

„/login” (controller: „user”, action: „login”)
 
„/”(view:”/user/login”)
Prima modificare este pentru a avea un url de login mai simplu (“/login” în loc de “/user/login”). A doua modificare este pentru a cere Grails să afișeze view-ul de login de fiecare data când cineva accesează: http://localhost:8080/GrailsSocialNetwork - e.g. rădăcina aplicației.

Datorită acestor modificări, aplicația noastră arată mai bine când este accesată pentru prima dată:

Persistența

Până acum, aplicația noastră a folosit un mecanism de persistență în memorie (la fiecare restart datele se pierdeau). În această secțiune aș dori să descriu cum să adăugăm aplicației un data source persistent, folosim GORM. Configurarea data source-urilor se face în DataSource.groovy (https://github.com/tavibolog/GrailsSocialNetwork/blob/master/grails-app/conf/DataSource.groovy ).

Primul pas este să definim câteva configurări ale data source-ului, cum ar fi pooling, driverul folosit pentru conectare, username și parolă:

dataSource { pooled = true driverClassName = „com.mysql.jdbc.Driver” username = „tavi” password = „tavi” }

Toate aceste configurări pot fi suprascrise pentru fiecare mediu de dezvoltare. Să luam ca și exemplu, mediul de “development”, cel pe care îl folosim când implementăm aplicația:

development {
    dataSource {
      dbCreate = „create-drop” 
       // one of ’create’‚‘create-drop’,  
       //’update’, ‚‘validate’, ‚’’
      url = „jdbc:mysql://localhost:3306/gsn”
        }
    }

Aici definim url-ul data source-ului, în cazul nostru un MySQL server, rulând o bază de date numită “gsn”. De asemenea, când aplicația pornește, va șterge tabelele existente și va crea un nou set după cum este specificat de către clasele de domeniu: User și Message. Aceasta este foarte la îndemână de folosit pentru dezvoltare, dar de evitat într-un sistem de producție.

O ultimă configurare ar fi să permitem folosirea dependenței MySQL în proiectul nostru. În BuildConfig.groovy (https://github.com/tavibolog/GrailsSocialNetwork/blob/master/grails-app/conf/BuildConfig.groovy ), adăugăm conectorul MySQL ca și dependență dinamică:

dependencies {     
    runtime ‚mysql:mysql-connector-java:5.1.16’
}

Asumând că aveți o bază de date MySQL disponibilă la acest url: jdbc:mysql://localhost:3306/gsn și o combinație user/parolă să o accesați, să restartăm aplicația.

Hmm, Grails nu pornește din cauza unei erori:

| Error 2013-02-24 21:37:48,821 [pool-7-thread-1] ERROR hbm2ddl.SchemaExport  - Unsuccessful:
create table user (id varchar(255) not null auto_increment, version bigint not null, first_name varchar(10) not null, last_name varchar(10) not null, password varchar(10) not null, user_name varchar(10) not null unique, primary key (id))
| Error 2013-02-24 21:37:48,823 [pool-7-thread-1] ERROR hbm2ddl.SchemaExport  - Incorrect column specifier for column ‚id’

Din fericire, aceasta este ușor de fixat. Eroarea a apărut pentru că atributul “id” al clasei User este de tip String, dar GORM încearcă să îl seteze ca și AUTO_INCREMENT, însă doar tipurile numerice pot fi auto-incrementate în MySQL. Deci, să schimbăm tipul atributului nostru de la “String” la “long” și să lăsăm GORM și MySQL să se ocupe de generarea id-urilor noastre:

class User {
	long id // prior it  was String id = UUID.randomUUID().toString()
	String firstName
	String lastName
	String userName
	String password
…
}

Acum, aplicația va porni fără probleme. Dacă aruncăm o privire la baza de date “gsn”, observăm că aceasta conține două tabele: “user” și “message”; GORM (via Hibernate) a creat tabele folosind atributele claselor domeniu și relațiile dintre ele. Datorită rutinei de ințializare din BootStrap.groovy, tabelele aplicației noastre au deja conținut pre-încărcat și sunt gata de folosit. De asemenea conținutul salvat acum poate supraviețui restartării unei aplicații.

Concluzie

În acest moment, am reușit să construim o aplicație folosind funcționalitătile de bază ale Grails și Groovy. Bine-înțeles, aplicația nu este pregătită de rulat în producție, dar este folositoare la învățarea unei nou framework de development.

Grails ajută developerii să devină productivi după câteva săptămâni de development la nivelul la care pot să construiască o aplicație web cu conținut dinamic. Bine-înțeles, universal Grails și Groovy este foarte vast și necesită mai mult timp pentru a-l stăpâni.

Sper că aceste trei articole v-au trezit interesul pentru a încerca Grails și Groovy în activitățile de web development. Acest framework a meritat investiția pentru echipa mea.

Bibliografie

http://grails.org/documentation

http://www.springsource.org/downloads/sts-ggts



Tavi Bolog

Development Lead at Nokia



Related Articles

Sângele lui Gogu fierbea iar el simțea că încet, încet, presiunea în interiorul capului său crește ireversibil. Deveni subit conștient că va exploda, iar sentimentul îl umplu de o liniște nefirească care îi șterse parcă orice emoție, rămăsese doar un gust amar... Era momentul pentru o reacție, acum ori niciodată. Îl întrerups...

PHP este un limbaj de programare dedicat dezvoltării paginilor și aplicatiilor web. Numele lui este un acronim recursiv însemnând PHP: Hypertext Preprocessor, nume adoptat după lansarea versiunii 3.0. Prima versiune creată în 1994 de Rasmus Lerdorf, a fost scris în C și a fost o suită de scripturi pentru a monitoriza vizitele către pagin...

Grails este un framework web bazat pe Java și Groovy. Grails împrumută concepte din frameowork-uri precum Rails în dorința de a simplifica web development-ul în Java. La o scurtă privire, Grails folosește:
• Limbajul Groovy – pentru a conecta toate stack-urile de mai jos;
• Hibernate – pentru modelarea datelor folosing G...

Unul dintre factorii cei mai importanți în explozia învățării automate în ultimii zece ani a fost puterea crescută de calcul. În 2010, Dan Cireșan et al. au doborât recordul de recunoaștere de cifre scrise de mână, folosind un algoritm inventat prin anii 1980 și augmentând setul de date printr-un procedeu descris în 1990. Singura d...

Am văzut în numărul trecut statisticile referitoare la reușita proiectelor ce arată că rata de succes este de 24% considerând rezultatele anului 2009. Pentru a diminua riscurile unui eșec, fiecare companie se adaptează situațiilor dificile aplicând mecanisme menite să transforme potențiale pierderi într-o reușită. Într-o perspectivă generalizată folosirea intensivă a unor procese sau echipe cu grad ridicat de experiență se pot impune ca demersuri și soluții eficiente.


Citește

Sponsori

ISDC

SmallFootprint

TPG



fortech accesa Betfair yardi hp accenture mozaic works

Media

Reclamă