This document was uploaded by user and they confirmed that they have the permission to share
it. If you are author or own the copyright of this book, please report to us by using this DMCA
report form. Report DMCA
Overview
Download & View Treasure-hunt.pdf as PDF for free.
UNIVERSITATEA ALEXANDRU IOAN CUZA IAŞI FACULTATEA DE INFORMATICĂ
Treasure hunt: aplicație web ce promovează cultura Iașului
Adrian-Dumitru Munteanu
Sesiunea: Iulie, 2016
Coordonator ştiinţific
Asist. Dr. Vasile Alaiba
2
DECLARAŢIE PRIVIND ORIGINALITATE ŞI RESPECTAREA DREPTURILOR DE AUTOR Prin prezenta declar că Lucrarea de licenţă cu titlul „Treasure hunt: aplicație web ce promovează cultura Iașului” este scrisă de mine şi nu a mai fost prezentată niciodată la o altă facultate sau instituţie de învăţământ superior din ţară sau străinătate. De asemenea, declar că toate sursele utilizate, inclusiv cele preluate de pe Internet, sunt indicate în lucrare, cu respectarea regulilor de evitare a plagiatului:
toate fragmentele de text reproduse exact, chiar şi în traducere proprie din altă limbă, sunt scrise între ghilimele şi deţin referinţa precisă a sursei;
reformularea în cuvinte proprii a textelor scrise de către alţi autori deţine referinţa precisă;
codul sursă, imaginile etc. preluate din proiecte open-source sau alte surse sunt utilizate cu respectarea drepturilor de autor şi deţin referinţe precise;
rezumarea ideilor altor autori precizează referinţa precisă la textul original.
Iaşi, data
Absolvent Prenume Nume _________________________ (semnătura în original)
3
DECLARAŢIE DE CONSIMŢĂMÂNT
Prin prezenta declar că sunt de acord ca Lucrarea de licență cu titlul „Titlul complet al lucrării”, codul sursă al programelor şi celelalte conţinuturi (grafice, multimedia, date de test etc.) care însoţesc această lucrare să fie utilizate în cadrul Facultăţii de Informatică. De asemenea, sunt de acord ca Facultatea de Informatică de la Universitatea „Alexandru Ioan Cuza” Iași să utilizeze, modifice, reproducă şi să distribuie în scopuri necomerciale programele-calculator, format executabil şi sursă, realizate de mine în cadrul prezentei lucrări de licenţă.
Iaşi, data
Absolvent Prenume Nume _________________________ (semnătura în original)
Strategii de îmbunatățire a performanțelor................................................................................... 38 5.1 Memorarea locala a unor resurse. .................................................................................................. 38 5.2 Accesarea resurselor doar atunci când sunt cerute ....................................................................... 39
6.
Utilizarea aplicației........................................................................................................................... 41 6.1 Pagina de misiuni ............................................................................................................................. 41 6.2 Accesarea unei misiuni .................................................................................................................... 41 6.3 Pagina de ştiri ............................................................................................................................... 43 6.4 Clasamentul .................................................................................................................................. 44 6.5 Pagina de profil ............................................................................................................................ 44 6.6 Pagina administratorului ........................................................................................................... 45 6.7 Prietenii ......................................................................................................................................... 46 7. Directii viitoare ale aplicatiei........................................................................................................... 47 7.1 Spring Security ................................................................................................................................. 47 7.2 Chat între utilizatori......................................................................................................................... 48 7.3 Transformarea aplicației într-un serviciu REST............................................................................... 48
„Treasure hunt” este un joc pentru una sau mai multe persoane, de toate vârstele, ce implică găsirea unor locaţii/obiecte şi combină elemente de orientare, artă şi rezolvare a problemelor pe baza unor indicii. Acest tip de joc a apărut în anul 1956, fiind creat de comediantul Jan Murray. Treasure hunt a trecut la un alt nivel, în anul 2000, odată cu apariţia „Geocaching”-ului, ce presupunea că fiecare participant să dispună de un sistem GPS, cu ajutorul căruia puteau localiza diverse locaţii. Astfel, a apărut şi aplicaţia mobilă „Geocaching” ce afişează o hartă cu mai multe marcaje. Utilizatorii trebuiau să găsească cutiile din locaţiile sugerate şi să îşi valideze poziţia. Aplicaţia este în continuare populară, având peşte 1 milion de descărcări în magazinul Google Play. Alte evenimente dedicate acestui tip de joc au avut loc in 2012, unde s-a stabilit un record mondial ca număr de participanți (466, divizați in 93 de echipe). Tot în acest an, eBay, a organizat un astfel de joc, cu premii în valoare de $200.000. Subiectul acestei lucrări îl reprezintă o aplicaţie web, ce susţine cultura oraşului Iaşi. Motivul realizării aceasteia a fost pentru a susţine campania „Iaşi, Capitală Culturală Europeană în 2021”. Între timp, Iașul a fost eliminat din cursă pentru acest titlu, lucru ce însă nu împiedică dezvoltarea aplicaţiei în continuare. Spre deosebire de „Geocaching”, aplicaţia presupune realizarea unor misiuni mai diferite, mergând pe ideea de gamification. Gamification este un concept de integrare a mecanismelor de joc, cu scopul de a capta şi motiva oamenii să-şi atingă ţelurile. Cele mai utilizatate mecanisme de joc sunt: punctele, insignele, nivelele, clasamentul, provocările, etc. Conceptul a devenit foarte popular cu timpul, fiind aplicat în site-uri precum: Linkedin, Stack Overflow, Amazon, SAP Community Network, etc. Misiunile pot reprezenta găsirea unui punct de interes cultural, edificiu sau răspunderea la diverse întrebări ce vizează cultura Iaşului. Găsirea edificiului este validată atât prin locaţia utilizatorului, dar şi prin procesarea imaginii pe care acesta trebuie să o realizeze. Aşadar, într-un mod interactiv, aplicaţia îndeamnă utlizatorul să iasă din casă, să înveţe cultura oraşului în care locuieşte şi este recompensat pentru aceasta. Recompensele contribuie la ideea de gamification a jocului. Odată finalizată o misiune, jucătorul primeşte puncte de experienţă, cu ajutorul cărora poate creşte în nivel sau rang. În acest sens este realizat şi un clasament, sporind concurenţa şi motivaţia jucătorilor.
7
Pe scurt, soluţia acestei idei, o reprezentă o aplicaţie web, realizată în Java, cu ajutorul bibliotecii Spring MVC, menită pentru a fi utilizată atat de pe calculatorul personal, cât și de pe telefon. Alte părţi mai interesante: procesarea imaginilor (utlizarea algoritmului ASIFT), geolocația (suport nativ în HTML5), simularea cache-ului la nivel de server, arhitectura aplicației, tehnologiile folosite, etc.
8
Contribuții O primă contribuție în realizarea lucrării o reprezintă etapă de cercetare în vederea conceperii unei idei neimplementate, ce poate avea un impact în societate. Sunt de părere că un joc, cu o idee bună, captează utilizatorul, putând să îl influenţeze într-o anumită direcție. În realizarea lucrării de licență cu tema „Treasure hunt: aplicație web ce promovează cultura Iașului” am propus o abordare proprie și originală a realizării unui joc. Ideea reprezintă automatizarea jocului de Treasure Hunt, particularizandu-l pe subiecte ce vizează istoria, cultura, arta unei comunități. Scopul lucrării îl reprezintă asimilarea informațiilor culturale ce vizează orașul în care locuim (Iași). Consider că astfel de informații culturale se asimiliează mult mai repede printr-un joc competitiv ce interacționează cu realitatea. Jucătorul este practic îndemnat să se informeze despre cultura orașului în vedearea avansării în joc. Soluția propusă (automatizarea jocului) nu se bazează pe supervizarea unor coordonatori pentru validarea unor stagii, cum este prevăzut în jocul clasic de „Treasure Hunt”. În acest scop am creat o aplicație web ce implementează problema de mai sus, creată folosind tehnologii opensource, robuste. Aplicația respectă principiile SOLID şi se bazează pe o structură modularizată, implementată în așa fel încât adăugarea de noi funcționalități sau orice modificări aduse să nu afecteze bună funcționare a celorlalte componente. O parte interesantă a aplicației o reprezintă lipsa dependeței de un supervizor uman care să valideze misiunile (duse sau nu la bun sfârșit). Validarea unei misiuni, ce presupune identificarea unui edificiu, prezintă un subiect complex şi de mare interes. Acest lucru implică identificarea locației jucătorului și validarea pozei pe care acesta trebuie să o realizeze. În privinţa procesării imaginii, am ales să utilizez algoritmul ASIFT (cu anumite condiții impuse) ce ajută în extragerea unor trăsături din imagini. Apoi s-au testat diferiţi comparatori de trăsături pentru a identifica unul ce se potriveşte pe modele arhitecturale, precum clădirile. O altă contribuție interesantă este redată de adoptarea unor strategii de îmbunătăţire a performanțelor aplicaţiei. Aceste strategii implică încercarea realizării a câtor mai puţine accesări la baza de date, precum şi procesări de imagini pe fire de execuţie separate. Așadar, lucrarea prezintă o idee originală de joc, ce consider că poate avea un impact bun în rândul ieşenilor. Realizarea cu succes a acesteia se bazează atât pe elemente menţionate mai sus, cât şi pe conceptele practice şi teoretice dobândite în facultate.
9
1. Tehnologii folosite 1.1 Java Limbajul de programare Java este unul dintre cele mai populare limbaje orientate obiect, având următoarele catacteristici:
Dinamicitate: reține cantităţi substanțiale de infomații la runtime
Simplitatea: sintaxă similară cu cea din C/C++, simplificată
Robustețea: nu permite suprascrierea memoriei prin renunțarea la pointeri, ceea ce poate preveni coruperi de date. Nu permite moştenirea multiplă iar dealocarea momeriei reprezintă o sarcină de care se ocupă o procedură ce rulează în fundal („Garbage Collector”)
Complet orientat obiect
Portabilitatea: se poate executa pe orice platformă; poate fi transferat și pe web (appleturi)
Conceptul de pointer nu există în Java, însă se bazează pe referinţe pentru a păstra adresele de memorie ale obiectelor. Alt concept care lipseşte este acela de destructor, fiind introdus Garbage Collector-ul. Deși monștenirea multiplă este eliminată, programatorul poate simula acest lucru prin moștenirea înlănțuită. Spre deosebire de multe limbaje, Java este şi interpretat şi compilat, caracteristică ce îi redă portabilitatea. În procesul de compilare Java prezintă doi pași mari. În primul, codul sursă este transformat în bytecode, urmând ca în al doilea pas, masina virtuală Java (JVM) să interpreteze acest cod intermediar. Sun Microsystems (achiziţionat ulterior de Oracle) a dezvoltat patru ediţii Java, ţintind spre diferite medii de dezvoltare :
Java Card, pentru carduri inteligente
Java Micro Edition, pentru medii cu resurse limitate
Java Standard Edition, pentru staţiile de lucru comune
Java Enterprise Edition, pentru aplicaţiile enterprise
10
Figura 1: Java-portabilitate pe diferite platforme 1
1.2 Spring MVC Framework Biblioteca Spring MVC este una dedicate Web-ului, oferind o arhitectură Model-ViewController şi componente ce ajută în crearea de aplicaţii web flexibile. Şablonul MVC ajută în separarea diferitelor aspecte ale unei aplicaţii, în timp ce menţine un cuplaj slab între aceste elemente (nu există dependinţe puternice). Acestă bibliotecă se bazează pe un servlet, numit DispatcherServlet, care preia toate cererile şi răspunsurile HTTP. În diagrama de mai jos, se ilustrează cum servletul procesează o cerere.
1.3 Apache Tomcat Apache Tomcat este un server-web și container de servleturi open-source. Acesta implementează diverse specificații Java Enterprise Edition, precum Java Servlet, Java Servlet Pages, WebSocket, etc. Prezintă trei componente: Catalina – este numele containerului de servlet, a cărui funcționalitate este de a implementa specificaţiile Sun Microsystems pentru servlet şi JSP (Java Server Pages). Catalina este integrat în orice tip de platformă unde informațiile necesare autentificării sunt deja create şi menținute
Coyote – Această componentă ascultă pentru conexiuni noi la server pe un port TCP și trimite cererea către motorul Tomcat pentru a o procesa, clientul primițând astfel un răspuns. Ca şi server web, suportă protocolul HTTP 1.1, fiind componenta de conectare. Permie oricărui container JSP să se comporte ca un server web.
Jasper – cunoscut și ca „Tomcat JSP Engine”, este motorul folosit de Tomcat pentru fişierele JSP , în sensul că parsează le parsează și le compilează în cod Java ca şi servleturi ce pot fi folosite de Catalina. Schimbările in JSP-uri sunt detectate, și salvate automat, ajutând dezvoltatorul, întrucât serverul nu mai trebuie restartat.
1.4 Apache Maven Maven este un instrument pentru automatizarea build-ului, utilizat în proiecte Java. Acesta descrie construcția unei aplicații, adresându-se totodată și asupra dependențelor (pachetele de care are nevoie proiectul Java). Aplicația este construită pe baza unui fișier XML, numit POM (Project Object Model), ce specifică dependențele către alte module sau componente externe. Așadar, la build, toate bibliotecile necesare sunt preluate din cache-ul local iar în cazul în care acestea lipsesc, sunt descăcate automat. Spre deosebire de tehnologiile similare (Ant, Gradle), Maven introduce conceptele de artifact, repository, ceea că ajută mult la depănare, versionare şi documentare a aplicației. Orice proiect Maven are o structură predefinită, evidențiată mai jos:
12
Figura 3: Structura unui proiect Maven
1.5 ORM-ul Hibernate Hibernate este o bibliotecă open-source ce simplifică dezvoltarea aplicaţiilor Java care interacţionează cu bazele de date. Acesta oferă o soluţie de mapare a unui model orientat obiect în bazele de date clasice, fiind independent de sistemul de gestiune a bazei de date. Reprezintă o implementare a interfeţei JPA (Java Persistence API), însemnând că poate fi integrat în orice sistem ce suportă JPA (aplicaţii pe platformele Java SE, EE, etc). O caracteristică enețială o reprezintă performanţă, hibernate având diverse strategii de fetching, precum iniţializarea leneşă (un obiect este extras din baza de date, doar atunci când este cerut). Hibernate are de asemenea şi propriul limbaj pentru interogări, numit HQL (Hibernate Query Language), ce permite scrierea de cod SQL utilizând obiectele Java. În plus, biblioteca generează majoritatea codului SQL în timpul instanțierii obiectului, nu la runtime.
1.6 JavaServer Pages (JSP) Jsp este o tehnologie ce rulează pe partea de server şi ajută în crearea dinamică de conţinut HTML. O particularitate a acestei tehnologii este că permite inserarea de scriplet-uri (cod Java) prin delimitatorii <%= [...] %> Un compilator JSP este un program care parsează JSP-urile şi le transformă în servleturi Java executabile. Randarea codului HTML la nivel de server poate reprezenta un avantaj,
13
întrucât vă avea aceleaşi performațe indiferent de platforma clientului (dat fiind faptul că pe mobil, operaţiile DOM sunt mult mai lente).
1.7 jQuery jQuery este unul dintre cele mai populare biblioteci de JavaScript, conceput pentru a uşura şi îmbunătăţi procese asupra arborelui DOM, cereri AJAX, animaţii, etc. Javascript este un limbaj de programare orientat obiect bazat pe conceptul prototipurilor, rulat direct în browser. Are rol în introducerea unor funcţionalităţi în paginile web. Motivul alegerii jQuery se datorează faptului că scurtează substanţial atât timpul de dezvoltare, precum şi lungimea codului JavaScript.
1.8 Materialize CSS Materialize este o bibliotecă de CSS, ce ajută în crearea de site-uri şi aplicaţii web. Conţine şabloane bazate pe HTML și CSS pentru tipografie, formulare, butoane navigare şi alte elemente de interfaţă precum şi extensii opţionale JavaScript. Se bazează pe ideea de „Material Design”, promovată de Google şi utilizată în majoritatea aplicaţiilor lor.
1.9 Apache Tiles Apache Tiles este un „templating framework” pentru aplicaţiile Java moderne. Se bazează pe şablonul de proiectare Composite şi ajută la dezvoltarea paginilor web. Şablonul Composite sugerează că un grup de obiecte similare să fie tratate ca aceeaşi instanţă a unui obiect. În cazul paginilor web, în layout (header şi footer) sunt introduse JSP-urile returnate de Controller.
Inserarea de JSP-uri se face prin:
Așadar, la schimbarea conținutului paginei web, header-ul si footer-ul nu vor mai fi reîncărcate.
14
2. Arhitectura aplicației Aplicația se bazează pe o arhitectură „server-side”. În modulul de server, se remarcă 3 mari straturi:
Presentation Layer Business Layer Data Access Layer
Fiecare strat „ştie” foarte puţin din codul celorlalte, doar cât este suficient pentru a realiza sarcinile necesare. De menţionat faptul că Presentation Layer nu poate comunica direct cu Data Acces Layer (şi invers). Comunicarea se realizează strict prin Business Layer.
Figura 4: Arhitectura aplicației 3
2.1 Presentation Layer Partea de prezentare este organizată pe baza şablonului MVC (Model-View-Controller), unde este de mare ajutor biblioteca Spring MVC. Cererea HTTP este preluată de controller, care la rândul său decide dacă trebuie să apeleze stratul de business. Dacă acest lucru nu este necesar,
controller-ul va returna direct un view. Însă, dacă în caz contrar, va interacţiona cu Business Layer-ul, care la rândul său va comunica mai departe cu al treilea modul. Toate controller-ele definite de dezvoltator, în Spring, trebuie să implementeze interfața Controller (@Controller) sau să extindă AbstractController. Partea de model din layer nu se referă la entităţile utilizate în DOA, ci la modelul pe care îl poate returna un controller. Acesta este practic un „map” ce va fi ataşat unui view. În JSP-uri, acest model poate fi accesat prin sintaxa ${cheieMap}.
2.2 Business Layer Acest layer conţine funcţionalităţile de bază ale aplicaţiei. Practic, acest modul determină cum informaţiile sunt create, afişate, stocate şi schimbate, primind comenzi de la Presentation Layer şi apelând mai departe Data Access Layer. În acest modul, regăsim clasele adnotate cu @Service, fiind un specific al frameworkului Spring. Acest lucru indică faptul că o clasă respectă practica DDD (Domain driven design), unde modelul rămâne încapsulat pe partea de server, fiind reprezentat doar la nivel de servicii şi repository-uri (persistentă a datelor). Aceste servicii respectă principiul singurei responsabilități. În cazul aplicaţiei noastre, există câte un serviciu pentru: fluxul jocului, upload-ul imginilor, procesarea imaginilor, trimitere de mail-uri, etc. Gruparea serviciilor, în aşa fel încât să aibă fiecare o singură responsabilitate, reduce impactul schimbărilor ulterioare, codul fiind mult mai uşor de menţinut.
2.3 Data Access Layer
DAO: Data Acces Object este de fapt un şablon de proiectare folosit în separarea APIurilor low-level de accesare a datelor de serviciile business high-level. În general, şablonul este asociat cu aplicaţiile Java EE şi bazele de date relaţionare, accesate prin JDBC, fiind specificat în ghidul de practici bune al „Sun Microsystems”. Acesta încapsulează toate accesele la baza de date. DAO realizează managementul conexiunii cu sursa de date pentru a obţine şi pastra informaţii. Este format din 3 componente: interfaţa DAO (defineşte operaţiile standard ce pot fi realizate pe model), implementarea interfeţei DAO (implementarea interfeţei de mai sus), obiectele Model (POJO-uri, conţinând metode set şi get). Mapând apelurile aplicaţiei asupra acestui strat, DAO oferă operații cu date specifice, însă nu expune informaţii sensibile despre baza de date. Avantajele folosirii acestui şablon au impact în separarea a două părţi importante ale aplicaţiei (Baza de date - Data Access Layer) care ar trebui să se dezvolte independent, neştiind prea multe una despre cealaltă. Aşadar, modificări asupra logicii de acces a obiectelor se pot realiza în DAO, însă schimbări în partea de persistenţă nu ar trebui să influenţeze clasele DAO, în cazul în care interfaţa este corect implementată.
16
Figura 5 Schema DAO 4
Entitățile: reprezintă obiectele model, menţionate mai sus. Aceasta sunt evidenţiate prin adnotarea @Entity, fiind mapate cu tabelele din baza de date prin @Table. O coloană este mapata prin @Column, fiind de fapt un obiect Java, remarcându-se că numele acesteia nu trebuie să coincidă cu cel al coloanei din tabel.
3. Implementarea aplicației 3.1 web-context.xml Acest fişier conţine detaliile de configurare care ajută serverul Tomcat, oferind mai multe informaţii (menţionate mai jos). <mvc:annotation-driven /> <mvc:resources mapping="/resources/**" location="/resources/" /> <mvc:interceptors> <property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" /> <property name="definitions"> <list> /WEB-INF/views/**/tiles-definitions.xml
Sunt specificate unde sunt plasate resursele aplicaţiei, putand fi accesate doar din această locaţie. Este menţionat un interceptor care filtrează toate cererile din aplicaţie, fiind utilizat pentru controlul accesului şi nu numai. De asemenea, web-context.xml specifică (printr-un pattern) şi locul în care se găsesc definiţiile pentru Apache Tiles.
3.2 application-context.xml Reprezintă interfaţa centrală dintr-o aplicaţie Spring, ce conţine informaţii de configurare a acesteia. La run-time este read-only, dar poate fi reîncărcat dacă este necesar. ApplicationContext poate încărca java beans, la cerere le poate distribui, şi le poate lega împreună. Prezintă interes deoarece adaugă funcţionalități specifice aplicaţiilor enterprise.
Locul unde se găsesc toate clasesle ce conţin adnotările @Controller, @Repository, @Service, etc (base-package="demo"). În cazul în care aceste clase sunt găsite, Spring le va înregistra în „bean-factory”
beanul entityManagerFactory, este cel care se ocupă de proprietăţile JPA (Java Persistence API), făcând referire la proprietatea 'dataSource'. Aceasta conţine informaţii ce ajută la stabilirea conexiunii cu baza de date.
Beanul txManager: este menţionată clasa JpaTransactionManager care este responsabilă de realizarea tranzacţiilor de informaţii între baza de date şi aplicaţie. Având aceste configurări, în implementările DAO putem injecta entityManagerul: @PersistenceContext private EntityManager em;
19
3.3 pom.xml Project Oriented Mode reprezintă fişierul de configuraţie a bibliotecii Maven. Conține informaţiile necesare bibliotecii să construiască un proiect. Printre elemente se numără dependenţele proiectului, versiunea proiectului, numele dezvoltatorilor, descriera, etc. Un astfel de fişier trebuie să conţină groupId (id-ul grupului proiectului, de regulă fiind unic pe companie), artifactId (id-ul proiectului), version (versiunea proiectului). <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0 demo <artifactId>demo 1.0 <packaging>war Skelet <description>Skelet POM OpenIMAJ maven releases repositoryhttp://maven.openimaj.org <dependency> com.fasterxml.jackson.core <artifactId>jackson-core 2.3.0
În pom-ul proiectului avem specificat goupId-ul şi artifactId-ul ca fiind „demo”, cu versiunea 1.0. De asemenea este menţionat modul de împachetare al proiectului, în acest caz fiind war (web application archive). Elementul „repository” marchează (în acest caz) un repository remote. Acest lucru este folositor în momentul în care Maven nu găseşte dependenţele în repository-ul central. Cum biblioteca OpenIMAJ nu se regăsește acolo, Maven va căuta în url precizat mai sus. Pentru exemplu, este specificată şi o dependenţă, în cazul nostru, biblioteca Jackson (responsabilă de conversia automată din obiecte Java în obiecte JSON). La momentul build-ului, dacă această bibliotecă nu se găseşte în cache-ul local, Maven o va descărca şi o va injecta la dependenţele proiectului.
3.3 Maparea unei entități cu baza de date Acest lucru se realizează cu ajutorul bibliotecii de persistenţă Hibernate. O clasă (entitate) va corespunde unui tabel din baza de date. @Entity @Table(name = "Quest") @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
Prin adnotarea @Entity marcăm clasa „Quest” ca fiind un bean, fiind mapată de tabelul „Quest” prin @Table (name = "Quest"). O regulă a Hibernate-ului este ca orice entitate să aibă o cheie primară, specificată prin @Id. @Column se foloseşte pentru a face maparea dintre proprietatea clasei şi coloanele tabelului. De menţionat faptul că numele tabelului, coloanei nu trebuie să corespundă cu numele clasei, respectiv proprietăţii, aceste putând să difere prin (name = „nume tabel/coloană”). Entitatea de mai sus reprezintă un caz mai special, deoarece toate clasele care o vor extinde, nu vor avea un tabel separat. Valorile acestora vor fi păstrate tot în acest tabel, fiind adăugate doar noi coloane (@Inheritance (strategy = InheritanceType. SINGLE_TABLE)). @DiscriminatorColumn va introduce o nouă coloană în tabel (nu şi o nouă variabila java), ce va avea valoarea sugerată de @DiscrimatorValue. Aşadar, subclasele nu vor mai avea adnotarea @Table, însă obligatoriu este să conţină valoarea discriminatorului. @Entity @DiscriminatorValue ("localization_quest") Public class LocalizationQuest extends Quest {[..]}
Evident, vor exista coloane cu valori nule, corespunzătoare unei anumite subclase. Însă, un avantaj semnificativ îl reprezintă faptul că la extragerea unei subclase, join-ul nu mai este necesar pentru a obţine informaţii din superclasă.
21
3.4 Extragerea informațiilor din baza de date @PersistenceContext private EntityManager em; @Override public List<User> getAdmins() { Query query = em.createQuery("from User user where user.access='admin'"); try { return(query.getResultList()); } catch (NoResultException e) { e.printStackTrace(); } return null; }
Acesta este un fragment de cod din implentarea unui DAO, reprezentând extragerea utilizatorilor care au accesul de admin. EntityManager este o interfaţă cu metode pentru interacţionarea cu contextul de persistenţă. Funcţia createQuery primeşte ca parametru un String în formal HQL (Hibernate Query Language). Diferenţa dintre SQL şi HQL este ca ultimul menţionat face referire la obiecte Java şi nu la elemente specifice bazei de date. Un DAO este injectat într-un serviciu/controller prin adnotarea @Autowired. Practic, în acest fel, rolul instantierii clasei DAO este preluat de Spring şi nu de dezvoltator. O sintaxă precum cea de mai jos este suficientă pentru a avea un bean Spring intializat. @Autowired UserDAO userDAO;
Adnotarea se bazează pe conceptul de „Dependency Injection”, fiind un şablon de proiectare ce implementează „Inversion of Control”. O dependenţă este un obiect de cerut (în cazul nsotru, un serviciu sau DAO). O injecţie presupune pasarea dependenţei la un obiect dependent care ar avea nevoie de ea. Practic, în loc de a avea obiecte care creează dependenţe, acestea sunt pasate în constructor sau printr-un set. „’Dependency Injection’ is a 25-dollar term for a 5-cent concept. [...] Dependency injection means giving an object its instance variables” – James Shore5.
3.5 Relația URL - contoller Maparea dintre controller și url se realizează astfel: @Controller @RequestMapping(value = "/account") public class AccountController { @RequestMapping(value="/userProfile", method = RequestMethod.GET) public String displayUserProfile( @RequestParam String id){ [...]} }
Această metodă mapează adrese de genul: „/account/userProfile? Id= [idUser]”. În cazul în care nu există o mapare pentru URL-ul tastat în browser, utilizatorul va fi direcţionat pe o pagină 404, fiindui specificat că pagina căutată nu există. Prinderea erorii HTTP 404 se realizeză prin codul de mai jos (din web.xml), fiind făcută redirectarea către o pagină proprie. <error-page> <error-code>404 /WEB-INF/views/error/404.jsp
3.6 Autentificarea Utlizatorul are posibilitatea să se autentifice printr-un formular clasic, dar mai interesantă este cea prin reţelele sociale (Facebook, Twitter, Google+). Acest lucru se realizează cu ajutorul servleturilor. Un servlet este o clasă Java care extinde capabilităţile unui server. Acesta preia de regulă cereri http, putând şi să răspundă la ele. Este practic, o componentă web, deploy-ată pe server cu scopul de a crea pagini web dinamice. În primul rând avem un buton ce apelează servletul:
Acțiunea „facebookLogin” este asociată unui servlet in web.xml, astfel: <servlet> <servlet-name>FBLoginServlet <servlet-class>facebook.login.domain.LoginServlet <servlet-mapping> <servlet-name>FBLoginServlet /facebookLogin
Mai sus este declarat servletul „FbLoginServlet”, mapat cu clasa facebook.login.domain.LoginServlet, având ca acţiune „/facebookLogin”. Odată apăsat butonul de autentificare, acţiunea se mută în metoda doGet a servletului. În acest moment se apelează un serviciu oferit de biblioteca OAuth ce securizează tranzacţia de informaţii dintre serverul
23
aplicaţiei şi serverele Facebook. Dacă utlizatorul acceptă să ofere informaţiile personale, aplicaţia va dispune de numele, email-ul, id-ul şi poza de profil ale acestuia. După efectuarea tranzacţiei, dacă id-ul utilizatorului nu se regăseşte în baza de date, acesta este salvat, trimiţânduse şi un mail de bun venit.
3.7 Trimiterea de mail-uri Spring contribuie cu un API de nivel înalt pentru simplificarea procesului de trimis mailuri. Este Bazat pe JavaMail(un API independent de platformă și protocol ce ajută în construirea de mail-uri).
Figura 7 Diagrama JavaMail 6
Pentru a trimite mesaje, este folosită clasa JavaMailSenderImpl. Aceasta necesită urmatoarea declarație in application-context.xml:
În acest sens, s-a creat un serviciu care se ocupă de email-uri (mesaj de bun venit, mesaj de resetare a parolei). @Service public class MailService { @Autowired JavaMailSender mailSender; public void sendHelloEmail(String to, String firstname) { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom("[email protected]"); message.setTo(to); message.setSubject("Bine ai venit"); message.setText("Salutare "+firstname+"\n\n Ne bucuram ca te-ai inregistrat!" ); mailSender.send(message); }
În această clasă putem injecta JavaMailSender-ul prin adnotarea @Autowired, trimiterea mesajului realizându-se foarte uşor prin mailSender. Send (message). La rândul său, serviciul MailService, va fi injectat în controller. Astfel, se realizează separarea dintre Business Layer şi Presentation Layer.
3.8 Încărcarea de imagini din browser Încărcarea se poate realiza atât din varianta desktop (file picker), cât şi din varianta mobilă (cu ajutorul camerei). Acest lucru este implementat în următorul cod HTML:
Atributul „accept” specifică tipul de fişiere care pot fi acceptate la upload. Pentru a se realiza transferul care server, este necesară o secvenţă de cod JavaScript: function sendFileToServer(e){ file = e.target.files[0]; […] url=”/demo/upload/photo/user”; if (checkFile(file)){ data = new FormData(); data.append("image",file); jQuery.ajax({ url: url, data: data, cache: false, contentType: false, processData: false, type: 'POST', complete: function(data){} }) } }
25
Odată selectată imaginea, funcţia de mai sus este apelată. Este extrasă imaginea din e.target.files[0] urmând să fie validată. Funcţia checkFile() verifică dacă dimensiunea imaginii nu depăşeşte 5Mb şi dacă aceasta are într-adevăr o extensie corespunzătoare unei imaginii. În cazul în care condiţiile sunt îndeplinite, se realizează o cerere Ajax care url-ul specificat. AJAX (Asynchronous JavaScript and XML) reprezintă o nouă modalitate de a folosi împreună tehnologii precum (X) HTML, CSS, JavaScript, DOM, XML, XSLT, XMLHttpRequest, prin intermediul căreia aplicaţiile web devin capabile să realizeze actualizări mai rapide de interfaţă, fără încărcarea întreagă a paginii. Cererea ajax din codul de mai sus va apela o metodă din controller-ul responsabil de încărcarea de imagini. Salvarea imaginii se realizează prin : imageService.saveImage(), a cărei implementare este urmatoarea: public void saveImage(String fileName,MultipartFile image, String type){ String photoPath; switch (type) { case "forUser": photoPath = DIRECTORY_PATH + fileName + "." + getImageExtension(image); break; case "forQuest": photoPath = QUEST_DIRECTORY_PATH + fileName + "." + getImageExtension(image); break; default: photoPath = HINT_DIRECTORY_PATH + fileName + "." + getImageExtension(image); File file = new File(photoPath); try { image.transferTo(file); } catch (IOException e) { e.printStackTrace(); } }
După cum se poate observa, imaginea nu este păstrată în baza de date că tip BLOB, ci este păstrată pe o partiţie a maşinii server. După ce imaginea a fost salvată, obiectului căruia îi este asignată imaginea (un utilizator, o misiunea sau un hint), îi este setată proprietate „photoUrl” după modelul: „/demo/upload/getPhoto/tip/id”. Astfel putem face referire la imagini după cum este arătat mai jos:
În momentul construirii dinamice a codului HTML, pentru a afișa imaginea de mai sus, se va face apel la urmatoarea metoda: @RequestMapping(value = "/getPhoto/{type}/{fileName}/{extension}", method = RequestMethod.GET) @ResponseBody public byte[] sendProfilePhoto(@PathVariable String type, @PathVariable String fileName, @PathVariable String extension) { ImageService imageService = new ImageService(); String path; switch (type) { case "user": path = ImageService.DIRECTORY_PATH + fileName + "." + extension; break; case "quest": path = ImageService.QUEST_DIRECTORY_PATH + fileName + "." + extension; break;
Calculând calea adevarată a imaginii, se va face apelul la funcția getImageFromPath() ce va citi imaginea într-un flux de bytes și o va returna.
Concluzii S-a ales salvarea imaginilor ca path-uri în baza de date din următoarele motive:
stocarea în baza de date este de obicei mai costisitoare
serverul nu are nevoie de procedee speciale pentru a accesa imaginile din sistem (funcţia getImageFromPath)
bazele de date au spaţiu de stocare limitat.
Desigur, şi a doua variantă de stocare ar fi avut avantajele ei, precum păstrarea integrităţii datelor, ceea ce sistemul de fişiere nu garantează. Însă cumulând avantajele şi dezavantejele, stocarea în sitemul de fişiere a fost soluţia aleasă.
3.9 Interceptarea fiecărei cereri Acest lucru se realizează extinzând clasa HandlerInterceptorAdapter din pachetul org.springframework.web.servlet.handler. O parte restrănsă din metodă este prezentă mai jos. @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(request.getRequestURI()); if(request.getRequestURI().contains("/demo/account/") || request.getRequestURI().contains("/demo/game") || request.getRequestURI().contains("/demo/log")) if(!request.getRequestURI().contains("findEmail")){ User u = (User) request.getSession().getAttribute("user"); if(u == null ){ response.sendRedirect("/demo/"); return false; } } return true; }
Extinzând metoda preHandle() putem realiza o anumită acţiune inante ca browser-ul să primească răspunsul. În cazul nostru, cu această tehnică realizăm controlul accesului. Cum utilizatorul logat se află în sesiune, dacă atributul „user” este null atunci cererea spre o anumită resursă/pagină va sfârşi prin redirectarea spre pagina de logare. În caz contrar, utilizatorul va acces la resursa dorită.
27
De menţionat faptul că pentru a fi recunoscut acest interceptor, trebuie declarat în webcontext.xml <mvc:interceptors>
3.10 Procesarea și compararea de imagini Procesarea unei imagini se realizează prin intermediul algoritmului ASIFT, din cadrul bibliotecii OpenIMAJ, a cărei funcţionalitate este explicată în unul din capitolele de mai jos. Întreaga parte de procesare este în sarcina serviciului ImageProcessorService. O primă funcţionalitate este cea de transforma imaginea din format MultiPartFile în format Fimage. public static FImage multipartToFImage(MultipartFile multipartFile){ try { return ImageUtilities.readF(ImageProcessor .multipartToFile(multipartFile)); } catch (IOException e) { e.printStackTrace(); return null; } }
Foarte important, înainte de a extrage trăsăturile unei imagini, aceasta trebuie redimensionată, pentru a nu pune jucatorul să aștepte foarte mult procesarea propriei imagini. S-a remarcat faptul că algoritmul dă rezultate bune și la rezoluții de 400x600. Astfel, în implementare se află minimul dintre înalțimea si lățimea imaginii, după care se setează pe 400 pixeli, păstrând proporțiile imaginii.
După care urmează extragerea trăsăturilor. Implementarea standard a algoritmului ASIFT în OpenIMAJ se regăseşte în clasa ASIFTEngine, fiind instanțiată mai jos în obiectul engine. public static LocalFeatureList extractFeatures(FImage image){ LocalFeatureList inputFeats = engine.findKeypoints(image); System.out.println("Extracted : " + inputFeats.size()); return inputFeats; }
Trăsăturile sunt păstrate într-o structură de date (LocalFeatureList), fiind de fapt o listă de puncte cheie extrase din imagine. Acestea sunt procesate în momentul în care administratorul adaugă o nouă misiune şi sunt stocate la nivel de server, fiind serializate la închiderea acestuia. În momentul în care administratorul introduce o misiune de localizare, un nou fir de execuție porneşte, având ca sarcină extragerea trăsăturilor imaginii. Când utilizatorul realizează o imagine pentru a rezolva misiunea, trăsăturile sunt extrase, apoi comparate cu cele de pe server cu scopul de a valida misiunea. Ultima funcţionalitate a serviciului o reprezintă compararea a două imagini. Aflarea mai precisă a potrivirilor presupune filtrarea acestora, bazată pe un model geometric dat. Un mod de a reuşi acest lucru reprezintă utilizarea clasei ConsistentLocalFeatureMatcher, care primeşte un „matcher” intern (FastBasicKeypointMatcher în cazul nostru) şi un estimator (RobustAffineTransformEstimator). Estimatorul se potriveşte pe un anumit model geometric (transformările afine7). Numărul de potriviri este dat de metoda findMatches ().
7
Model ce păstrează colinearitatea și ponderea distanțelor la diferite transformări http://mathworld.wolfram.com/AffineTransformation.html
28
public static int getMatches(LocalFeatureList firstFeats, LocalFeatureList secondFeats){ LocalFeatureMatcher matcher; RobustAffineTransformEstimator modelFitter = new RobustAffineTransformEstimator(5.0, 1500, new RANSAC.PercentageInliersStoppingCondition(0.5)); matcher = new ConsistentLocalFeatureMatcher2d( new FastBasicKeypointMatcher(8), modelFitter); matcher.setModelFeatures(firstFeats); matcher.findMatches(secondFeats); final List<Pair> matches = matcher.getMatches(); System.out.println("Matches found: " + matches.size()); return matches.size(); }
După mai multe teste se remarcă faptul că RobustHomographyEstimator întoarce rezultate mai bune decât RobustAffineTransformEstimator. Primul menţionat face referire la „planar homographies”8, ce sunt mai generale ca transformările afine, mapând patrulatere la patrulatere. Totuşi, codul suferă schimbări minore: RobustHomographyEstimator modelFitter2 = new RobustHomographyEstimator(5.0, 1500, new RANSAC.PercentageInliersStoppingCondition(0.5), HomographyRefinement.SYMMETRIC_TRANSFER); Unde SYMMETRIC_TRANSFER semnifică faptul că punctele din prima imagine sunt
proiectate de o „homography matrix” pentru a produce noi estimări ale celei de a două imagini şi viceversa. Teste:
Palatul Culturii
Figura 8 RobustAffineTransformEstimator, 7 potriviri
Figura 10 RobustAffineTransformEstimator, 12 potriviri
Figura 11 RobustHomographyEstimator, 75 potriviri
30
Imagini cu obiective diferite
Figura 12 RobustAffineTransformEstimator, 9 potriviri
Figura 13 RobustHomographyEstimator, 0 potriviri
Concluzii
procesarea unei imagini prin algoritmul ASIFT este una costisitoare, atât ca timp, dar şi ca memorie, motiv pentru care toate imaginile sunt redimensionate. Pentru o imagine de 400x600 pixeli o astfel de procesare durează în jur de 10 secunde.
potrivirile extrase nu sunt întotdeauna perfecte. Pot exista cazuri în care nu se găsesc potriviri, deşi imaginile conţin acelaşi obiectiv. Un astfel de caz este reprezentat de efectul puternic de relief, spre exemplu:
31
Figura 14 0 potriviri, indiferent de estimator
estimatorul afin, produce în medie mai puţine potriviri, acestea putând fi şi eronate în cazul imaginilor ce conţin obiecte total diferite, cum este evidenţiat în ultimul test.
3.11 Afișarea timpului unei știri În pagina de newsfeed, este vizibil timpul trecut din momentul apariţiei unei ştiri. Acest lucru se realizează cu ajutorul bibliotecii open-source numită Timeago9, al cărei autor este Ryan McGeary. Interesant în implementare este faptul că biblioteca poate primi ca parametru chiar java.util.Date, astfel: .
La momentul încărcării codului HTML, este apelată biblioteca cu următorul cod JavaScript: jQuery(document).ready(function() { jQuery("time.timeago").timeago(); });
9
Biblioteca Timeago: http://timeago.yarp.com/
32
Extinderea bibliotecii Timeago pentru a returna timpul calculat, cu termeni în limba romană, este urmatoarea: strings: { prefixAgo: "Acum", prefixFromNow: null, suffixAgo: null, suffixFromNow: null, inPast: 'Orice moment', seconds: "", minute: "1 min", minutes: "%d min", hour: "1 ora", hours: "%d ore", day: "1 zi", days: "%d zile", month: "1 luna", months: "%d luni", year: "1 an", years: "%d ani", wordSeparator: " ", numbers: [] }
33
4. Algoritmii de procesare de imagine 4.1 Algoritmul ASIFT Acronimul provine de la Affine Scale-Invariant Feature Transform, ASIFT fiind practic o îmbunătăţire a algoritmului SIFT, care va fi detaliat mai jos. Problemă: Conţin imaginile acelaşi obiect?
Soluţie: DA, deşi pozele sunt realizate din unghiuri diferite
Figura 15 ASIFT - Potrivirile găsite
Utlizand acest algoritm, este posibilă recunoaşterea obiectelor solide într-o imagine digitală, indiferent de unghi, distanţă, atât timp cât rezoluția permite acest lucru. Dacă un obiect fizic are margini netede, imaginea realizată de orice cameră digitală din diferite poziţii va prezenta aceste margini tot netede, dar deformate. Aceste deformaţii sunt aproximate de transformările afine. Algoritmul simulează imaginea iniţială, obţinută prin modificarea orientării camerei, simulare ce nu este tratată de algoritmul SIFT, apoi aplică SIFT. Un algoritm de potrivire a imaginilor afine invariante trebuie să acopere cei 6 parametri afini. Metoda SIFT tratează doar 4 dintre aceştia, normalizând rotaţiile, translaţiile şi simulând zoomurile.
34
Figura 16 ASIFT - privire de ansamblu 10
După cum este ilustrat în imagine, ASIFT completează SIFT, simulând doi parametri care modelează axa de direcţie a unei camere foto: scala și unghiurile de latitudine şi longitudine ale camerei, normalizând translaţia şi rotaţia. Paşii algoritmului:
imaginea este transformată prin simularea tuturor distorsionărilor afine cauzate de modificiarea axei de orientare a camerei. Distorsionările depind de longitudine (φ) şi latitudine (θ).
distorsionările sunt apoi rotite la unghiul φ, urmate de înclinări cu parametrul t = 1/| cos θ|. Aceste rotaţii şi înclinări sunt realizate pentru un număr mic, finit de unghiuri de latitudine şi longitudine.
toate imaginile simulate sunt comparate de SIFT
4.2 Algoritmul SIFT Acest algoritm prezintă 2 mari stagii:
Detecţia punctelor de interes
Generarea descriptorilor
Pentru a explica ce reprezintă un punct de interes vom folosi un exemplu: Este dată poza unei uşi. Aceasta are 4 colţuri, fiind de asemenea şi punctele de interes ale imaginii. Apoi imaginea este rotită, fiind alterată şi dimensiunea acesteia. Imaginea iniţială poate fi comparată cu cea modificată prin aceste 4 puncte, deoarece la scalare/rotaţie punctele nu se schimbă; uşa tot va avea 4 colţuri. Aşadar, pe acestea le numim puncte de interes.
10
Sursă: http://www.ipol.im/pub/art/2011/my-asift/
35
Figura 17 SIFT - puncte de interes 11
În pasul următor, se filtrează punctele de interes, fiind eliminate muchiile sau zonele cu contrast scăzut. Apoi se asignează fiecărui punct o orientare. Acest lucru, practic, anulează orice efect de orientare al imaginii, făcând-o invariantă la rotaţii.
Figura 18 SIFT - puncte de interes cu orientare 12
Pentru generarea punctelor de interes sift, numite şi descriptori, algoritmul calculează gradientul imaginii. Apoi va forma histograme ale orientărilor. Aceste histograme măsoară puterea gradientului în fiecare direcţie. Formând mai multe histograme şi concatenandu-le se obţine o histogramă (Histograma gradienților orientați13) finală ce va reprezenta descriptorii (utilizaţi în găsirea similarităţilor dintre două imagini).
Figura 19 Puncte de interes, gradienți, descriptori
5. Strategii de îmbunatățire a performanțelor Adoptând unele tehnici de îmbunătățire a performanţelor, s-a ajuns ca unele pagini să se încarce şi de două ori mai rapid.
5.1 Memorarea locala a unor resurse. Încărcarea paginilor depinde foarte mult de timpul de execuţie a metodei din controller, corespunzătoare unei rute. S-a remarcat faptul că accesul multiplu la baza de date generează timpi suplimentari de execuţie. Aşadar, o soluţie găsită este de a simula cache-ul la nivel de server. În serviciul CachedData avem stocaţi toţi utilizatorii şi misiunile deoarece aceste resurse au fost cele mai acesate din baza de date. @Service public class CachedDataImpl implements CachedData { private Map<String, User> users ; private Map<String, Quest> quests ;
Pe lângă setteri şi getteri, această clasă conţine metode utilitare, ce ajută în realizarea operaţiilor CRUD15 pe resursele stocate. CachedData poate fi injectată în controller, accesul la resurse realizându-se mult mai rapid după cum arată şi următorul caz de test:
Accesul la resurse doar prin baza de date:
@RequestMapping("/test1") @ResponseBody public double test1(){ double start, finish; start = System.currentTimeMillis(); List<User> users = cachedData.getUsers(); List quests = cachedData.getQuests(); questDAO.getQuest("213edba8-ac55-40f5-b9c7-c1d292096fab"); questDAO.getQuest("06f8e1c4-af2b-4d03-ab12-b43565b21c4a"); userDAO.findUser("1"); userDAO.findUser("2"); finish = System.currentTimeMillis(); return finish - start; } Rezultat (in functie calculatorul pe care o 360ms in medie o 140ms in medie
15
de strategia de performanta pe care o adopta serverul ruleaza) (putere scazuta) (putere mare)
Accesul la resurse prin datele stocate pe server.
Create, Read, Update, Delete
38
@RequestMapping("/test2") @ResponseBody public double test2(){ double start, finish; start = System.currentTimeMillis(); List<User> users = cachedData.getUsers(); List quests = cachedData.getQuests(); cachedData.getQuest("213edba8-ac55-40f5-b9c7-c1d292096fab"); cachedData.getQuest("06f8e1c4-af2b-4d03-ab12-b43565b21c4a"); cachedData.getUser("1"); cachedData.getUser("2"); finish = System.currentTimeMillis(); return finish - start; } Rezultat: o 0ms (putere scazuta) o 0ms (putere mare)
Desigur, pagina nu se va incărca instant nici prin a doua metoda, acest lucru fiind dependent și resursele CSS, JS și viteza de internet a utilizatorului.
5.2 Accesarea resurselor doar atunci când sunt cerute După cum s-a mai menționat, JSP-uri pot primi din controller un model la care are acces prin ${numeModel}. Se evită accesarea resurselor şi popularea modelului cu informaţii pe care clientul nu le observă la încărcarea paginii, accesul acestora fiind făcut ulterior, dacă este cerut. Spre exemplu, în pagina de profil, utilizatorul poate vedea relaţia cu ceilalţi jucători
Figura 20 Relatia dintre jucatori
39
Dacă acesta nu este interesat de cine îl urmăreşte, nu se va mai realiza o interogare inutilă pe bază de date. În schimb, dacă doreşte să vadă, în momentul apăsării pe fila „Urmărit de”, se efectuează următorul apel Ajax: function showFollowers() { if (notLoaded) { notLoaded = false; $.ajax({ url : "/demo/account/getFollowers?userId=" + userId }) .then( function(data) { for (index in data) { user = data[index]; $('#followers').append( '
„notLoaded” este o variabilă care indică dacă interogarea de mai sus a mai fost realizată sau nu. În caz afirmativ, cererea Ajax nu mai este făcută. În secvenţa „for”, este populat elementul HTML cu id-ul „followers”. Executând metoda de mai sus, se ajunge la urmatorul rezultat:
Figura 21 Exemplu de resurse cerute prin AJAX
40
6. Utilizarea aplicației 6.1 Pagina de misiuni Odată logat, utilizatorul (indiferent de gradul de acces) poate vedea pagina de misiuni. Aceste misiuni sunt sortate pe 3 categori:
misiuni noi: cele proaspăt adăugate de administratori, pe care utilizatorul încă nu le-a accesat.
misiuni începute: cele care au fost accesate în trecut.
misiuni terminate: cele pentru care s-a oferit deja un răspuns, fie el corect sau nu.
Figure 22 Pagina de misiuni
6.2 Accesarea unei misiuni Misiunile sunt împărţite pe doua categorii: cele de localizare a unui edificiu şi întrebările de cultură generală. Mai jos este pagina de accesare a unei misiuni de localizare. Aceasta prezintă informaţii specifice, precum dificultatea, descrierea şi indicaţii de realizare a pozei. De asemenea, în partea dreaptă este afişat numărul de hint-uri disponibile. Un hint poate fi folosit dacă misiunea are unul asignat.
41
Figura 23 Misiunea de localizare
În momentul realizării pozei, locaţia utilizatorului este preluată şi comparată cu cea a edificiului. Dacă distanţa este mai mică de 50 metri (se ia în calcul şi eroarea localizării), atunci se trece la pasul ce vizează procesarea imaginii. Pentru ca procesarea să nu dureze exagerat de mult imaginea este redimensionată (minimului dintre înălţime şi lăţime i se atribuie valoarea de 400 pixeli, păstrând proporţiile dintre cele două dimensiuni). Având trăsăturile imaginii din baza de date încărcate în memoria serverului, acestea sunt comparate cu cele extrase din poza realizată de jucător. Dacă numărul de potriviri depăşeşte 20, înseamnă ca jucătorul a finalizat cu succes misiunea. Ambele sunt acoperite mai jos.
Figura 24 Rezultatul terminării unei misiuni
De asemenea următoarea imagine prezintă o întrebare de cultură generală, cu informaţii aferente acesteia.
42
Figura 25 Intrebare de cultură generală
Realizarea unei misiuni este recompensată cu puncte de experienţă în funcţie de dificultatea acesteia. Acumularea de puncte experienţă conduce la creşterea în nivel şi în rank. Jucătorul beneficiază de un hint în plus la fiecare creştere de nivel.
6.3 Pagina de ştiri În această pagină utlizatorul poate regăsi informaţii ce au legătură cu jucătorii pe care îi urmăreşte. Informaţiile au scop motivaţional, acestea făcând referire la terminarea unei misiuni, creşterea în nivel, rank, etc.
Figura 26 Pagina de știri
43
6.4 Clasamentul În clasament se regăsesc utlizatorii sortaţi în ordinea rankului, nivelului şi a punctelor de experienţă. Pagina reprezintă unul din punctele cheie al conceptului de gamification.
Figura 27 Pagina de clasament
6.5 Pagina de profil Pagina de profil afişează toate informaţiile asociate unui cont. Aici, jucătorul poate observa cine îl urmăreşte şi pe cine urmăreşte el, având posibilitatea şi să îşi editeze profilul.
Figura 28 Pagina de profil
44
6.6 Pagina administratorului Această pagină presupune accesul autorizat. Prezintă ceilalți administratori, utilizatorii şi misiunile, administratorul autentificat, având posibilitatea să modifice aceste date. De asemenea, tot din această pagină se pot adauga misiunile. Trebuie menţionat faptul că datele afişate sunt paginate. Cererea de date corespunzătoare unei pagini se realizează printr-un apel AJAX către server, acesta returnând o listă de obiecte. Orice ştergere din listă va actualiza automat pagina, fără a o mai încarca din nou. Înainte de efectuarea unei ștergeri, administratorul este nevoit să își confirme acțiunea printr-o fereastra modală.
Figura 29 Pagina administratorului
Un caz mai interesant îl reprezintă adăugarea misiunii de localizare. Aceasta specifică posibilitatea încărcării unei imagini, setarea descrierii/dificultăţii/informaţiilor adiţionale, precum şi alegerea coordonatelor. În momentul poziţionării unui marcaj pe hartă, automat sunt extrase latitudinea şi longitudinea. Infomaţiile adiţionale sunt afişate jucatorului după ce acesta a terminat cu succes misiunea. Acestea au fost introduse din scop pur informativ, pentru a oferi detalii despre locaţia identificată.
45
Figura 30 Adăugarea unei misiuni de localizare
6.7 Prietenii În pagina dedicată acestui subiect, jucătorul poate vedea toţi prietenii săi (persoanele pe care le urmăreşte), împreună cu detalii aferente progresului lor (rangul, nivelul şi punctele de experiență). De asemenea este disponibilă căutarea de utilizatori noi. Aceasta beneficiază de autocompletare. Căutarea se realizează pentru minim 2 caractere, având totodată şi o intârziere, pentru a nu face cereri inutile către server.
46
Figure 31 Pagina prietenilor
7. Directii viitoare ale aplicatiei 7.1 Spring Security În momentul de faţă, controlul accesului se realizează prin rutare, fiecare cerere fiind verificată de un interceptor (a se vedea capitolul 3.8). O altă soluţie ar fi utilizarea pachetului Security din cadrul bibliotecii Spring. Aceasta asigură autentificarea şi autorizarea în aplicaţiile Java. Puterea acestei biblioteci constă în uşurinţa cu care poate fi extinsă pentru a satisface cerinţe particulare. Avantajele ar fi:
ușurința cu care se realizează controlul accesului. Spre exemplu:
@PreAuthorize("hasRole('ROLE_ADMIN')") public void deleteUser(String username);
vine cu pachete pentru criptarea parolei precum (Md5PasswordEncoder, BaseDigestPasswordEncoder, etc)
are suport pentru controlul accesului chiar şi în JSP-uri <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> <sec:authorize access="hasRole('ROLE_ADMIN')"> Acest mesaj va fi vizibil doar pentru admini.
47
poate expirma condiţia ca autentificarea să se realizeze doar prin HTTPS astfel în fişierul de configurare
7.2 Chat între utilizatori Dat fiind faptul că utilizatorii primesc ştiri (news feed) de la prietenii lor, o funcţionalitate bună de adăugat ar fi aceea de a da posibilitatea jucătorilor să comunice live. Acest lucru se poate realiza prin intermediul Web Socket-urilor. Websocket-urile sunt o tehnologie modernă ce face posibilă comunicarea interactivă între browser şi server, utilizând o singură conexiune TCP. Cu acest API se pot trimite mesaje la server şi primi răspunsuri fără a fi aşteptate sau cerute. Desigur, pentru a păstra mesajele, este nevoie de un model pentru baza de date. Cel de mai jos este inspirat din structura Facebook-ului de stocare de mesaje:
Figura 32 Model de stocare a mesajelor
7.3 Transformarea aplicației într-un serviciu REST Într-o arhiterctura REST, totul reprezintă resurse. O astfel de arhitectură ajută foarte mult în minimizarea cuplajului dintre client şi componentele serverului. Trecerea pe o arhitectură REST implică schimbări majore, însă ar aduce avantaje notabile, precum posibilitatea utlizarii aceluiaşi server pe diferite tipuri de clienţi (browser, 48
aplicaţii mobile). Deoarece JSP-uri nu pot fi folosite în aplicaţii pure REST, o sugestie pentru a realiza clientul de tip browser ar fi utilizarea bibliotecii AngularJS. Aceasta, folosită de regulă în dezvoltarea aplicaţiilor web cu o singură pagină, se bazează pe o arhitectură MVC şi MVVM (Model View-View Model). Avantajele ar fi ca AngularJS extinde HTML-ul, oferă suport pentru legarea de date („data-binding”), permite testare la nivel enterprise, etc. O altă direcţie a clientului o reprezintă aplicaţiile native pe diferite platforme (Android, iOS, windows). Acestea pot profita de avantajele oferite de sistemul de operare, precum diferiţi senzori, performanţă ridicată, etc. Spre exemplu, intr-o aplicație Android, aplicație ar rula mai fluent decât in browser, localizarea s-ar face mai eficient, procesarea imaginilor s-ar putea realiza direct pe client pentru a evita suprasolicitarea serverului, etc.
49
Concluzii Aplicația descrisă în această lucrare propune o altă abordare a jocului de Treasure Hunt, una automatizată, cu orientare spre obiective culturale. Consider că este foarte important ca un ieșean să cunoască istoria și cultura propriului oraș, așa că am decis dezvoltarea unei aplicații ce îmbină utlilul (asimilarea de noi cunoștințe) cu plăcutul (jocul propriu-zis). Jucătorul poate afla noi informații prin intermediul misiunilor disponibile. Am considerat că terminarea acestor misiuni nu reprezintă o sursă de motivație suficientă, așa că am adoptat conceptul de gamification. Practic, orice reușită este recompensată cu puncte de experiență. Se poate spune că jucătorii sunt într-o oarecare competiție, fiind realizat un clasament în acest sens. O problemă pe care am ridicat-o (în misiunile de localizare) a fost necesitatea deplasării jucatorului la edificiul sugerat. Acest lucru se bazează pe faptul că am observat cum tot mai multă lume preferă să-și petreacă mare parte din timp izolați, în fața calculatorului din casă. Pe lângă acest lucru, sunt de părere ca vizionarea pozei unui edificiu nu este la fel de memorabilă precum analizarea acestuia „la fața locului”. În acest scop, misiunile pot fi extinse pentru a realiza chiar un tur de prezentare al orașului. În implementarea aplicației m-am orientat spre tehnologii robuste, de actualitate. Așadar am decis dezvoltarea unei aplicații web în limbajul Java, cu ajutorul bibliotecii Spring MVC. Am preferat o aplicație web deorece este independentă de platforma clientului, fiind necesar doar un browser. S-au adoptat diferite strategii de îmbunătățire a timpului de încarcare a paginii precum solicitarea deasă a memoriei Heap16, procesarea asincronă a imaginilor, etc. Așadar, subiectul acestei lucrări prezintă o idee nouă, ce consider ca poate avea un impact bun în randul ieșenilor. Aplicația (ce poate avea și caracter turistic) îndeamnă utilizatorul să iasă din casă și să se distreze în timp ce învață cultura orașului.
16
heap – spațiul de stocare al obiectelor Java
50
Bibliografie [1] Craig, Walls. Spring in Action. Manning, 2014. [2] Pivotal Software. Spring Framework -
https://spring.io/docs [3] Cameron McKenzie. Hibernate made easy. PulpJava, 2008. [4] Apache Software Foundation. Maven http://maven.apache.org/guides [5] Apache Software Foundation. Tomcat https://tomcat.apache.org/tomcat-7.0-doc/index.html [6] Materialize CSS http://materializecss.com/about.html [7] jQuery - http://api.jquery.com/ [8] Cristian, Frăsinaru. Curs practic de Java http://web.info.uvt.ro/~iordan/P_III/Cristian_Frasinaru-Curs_practic_de_Java.pdf [9] Guoshen Yu, Jean-Michel Morel. ASIFT: An algorithm for Fully Affine Invariant Comparison http://www.ipol.im/pub/art/2011/my-asift/article_lr.pdf [10] Brian, Burke. Gamify: How Gamification Motivates People to Do Extraordinary Things. Hardcover, 2014. [11]Robert, Martin. Clean Code: A Handbook of Agile Software Craftmanship. Prentice Hall, 2009. [12] StackOverflow – http://stackoverflow.com/