webForum webForum sponsras med lina och serverplats av Binero AB

Gå tillbaka   webForum > Artiklar och källkod > Artiklar > Webbrelaterade artiklar

Webbrelaterade artiklar Här skriver du artiklar om asp, asp.net, java, c#, html, webbsäkerhet

Svar
 
Trådverktyg Betygsätt tråden Visningsalternativ
Äldre 2010-04-27, 23:47   #1
SPiN
Medlem
 
Registrerad: 2000-03-12
Ort: Göteborg
Inlägg: 5 832
Lösningar: 179
[Java] Play! Framework - en introduktion

Jag har nyligen upptäckt ett intressant ramverk för Java, som heter Play! Framework. Jag har egentligen bara hunnit känna på det men är redan imponerad över hur enkelt det är att använda och hur snabbt man utvecklar med det. Det är inte lika stort och flexibelt som t.ex. Spring, men om man vill ha något relativt enkelt gjort på en kort utvecklingstid kan Play! vara värt att titta närmare på.

Play! är ett MVC-ramverk som använder JPA och Hibernate under huven – och som utvecklare behöver man inte bry sig alls om konfigurationen för JPA och Hibernate! Det är väldigt smidigt gjort, man får Model-superklasser att ärva från för att en smidig integration mot datakällan.

Vidare har Play! ett utmärkt gränssnitt för unit testning, med antingen JUnit eller Selenium, där man kommer åt testen via webläsaren. Det är dock ingenting jag fokuserar på i den här texten.

Jag kommer visa ett kortare exempel där jag bygger upp en filmsajt för listningar av filmer och skådespelare. De redskap som jag kommer använda är Play! Framework och eclipse för att hantera min kod.

Upplägget ser ut som följer:
  1. Installation och hur man skapar ett projekt
  2. Sätta upp modeller och datakälla
  3. Första titt på vyer
  4. Sätta upp kontrollers
  5. Vyer för våra kontrollers
  6. URL-mappning och rutter
  7. Knyt ihop säcken!
  8. Avslutning

1. Installation och hur man skapar ett projekt

Ladda ned ramverket och packa upp det på valfri plats, ingen automatisk installation sker. Allt vi behöver finns i zip-arkivet. Efter att du packat upp Play! behöver vi peka miljövariabeln PATH till platsen där Play! hittas. I mitt fall, jag sitter i GNU/Linux, sparade jag Play! i min hemmapp home/bjorn/play så för att mitt system ska kunna hitta Play! lägger jag till följande rader i min ~/.bash_profile:
Kod:
PATH=$HOME/play:$PATH
export PATH
Start om terminalen du sitter i och du ska kunna komma åt Play! genom att helt enkelt skriva play.
Då var installationen klar! Dags att sätta upp ett första projekt.
Placera dig i den mapp där du vill att ditt nya projekt ska husera, i mitt fall blev det /home/bjorn/projects. Jag väljer att döpa det här projektet till moviedb och ska också finnas i en mapp som heter moviedb, så för att skapa projektet och mappen kör jag helt enkelt kommandot:
Kod:
play new moviedb
Kommandot skapar en projektmapp med namnet moviedb. Vi får nu en fråga om vad vi vill döpa själva projektet till, och här anger jag moviedb igen.
Nu har vi skapat projektet moviedb i mappen med samma namn, och Play! har nu skapat ett skelett med kataloger och filer i projektmappen. Redan nu kan vi köra projektet genom:
Kod:
play run moviedb
Vi kan titta på vårat verk genom en webläsare, pekad mot addressen http://localhost:9000/ - 9000 är Play!s standardport vilken går att ändra. Det som visas är Play!s välkommen-skärm, som bara visar att allt har gått som det ska.
För att vi ska kunna använda eclipse som IDE till vårat nya Play! projekt på ett smidigt sätt, kan vi låta Play! göra om vårat projekt till ett eclipse-projekt genom kommandot:
Kod:
play eclipsify moviedb
Öppna nu upp eclipse, gå till File > Import... och välj General > Existing Projects into Workspace, och lägg till moviedb-mappen. Vips, så fungerar allt out-of-the-box med eclipse!

I mappen app finns de filer vi kommer att arbeta med, nämligen våra kontroller, modeller och vyer. Vi kommer också att titta lite i conf för den lilla konfiguration vi behöver göra. Tillsvidare använder vi standardkonfigurationen av Play!.

2. Modeller och datakälla

Som jag tidigare sa sköter Play! all mappning med JPA och Hibernate åt oss, utan att vi behöver bry oss om konfigurationsinställningar och liknande. Däremot måste vi tala om för Play! vilken typ av datakälla vi vill använda. Under utvecklingstiden kan vi använda HSQLDB, en "in-memory"-databas från Hibernate. Så fort vi stänger vårat projekt töms alltså databasen på information. I eclipse öppnar vi upp filen conf/application.conf. För att få Play! att använda HSQLDB som datakälla är det enda vi behöver göra att avmarkera rad 75, under Database configuration, så det står db=mem.

Min första modell blir klassen som representerar en skådespelare. De egenskaper vi lagrar för våra skådespelare är enbart namn. Vanligtvis sätter man upp sina modeller med inkapsling och privata instansvariabler för att lagra värden, men Play! arbetar lite annorlunda. Här har vi istället publika instansvariabler som Play! senare kapslar in åt oss. Varje modell måste också ha annoteringen @Entity för att JPA ska hantera det som en entitet/modell, liksom en konstruktor med de nödvändiga parametrarna för instansen. Skapa filen Actor.java under models-paketet i eclipse. I sin helhet ser klassen ut så här:
java:

package models;

import play.db.jpa.*;

import javax.persistence.*;

/* Tala om för JPA att det här är en entitet */
@Entity
public class Actor extends Model { /* Få funktionalitet från Play!s modeller */
public String name;

public Actor(String name) {
this.name = name;
}
}

Den andra modellen blir klassen som representerar en film. De egenskaper våra filmer behöver är en titel för varje film, en handling och en samling med skådespelare. Eftersom att en film kan ha flera skådespelare och en skådespelare kan medverka i flera filmer, blir relationen mellan dom många-till-många. Det måste märkas ut med annoteringar för att JPA ska förstå sambandet mellan våra entiteter. Skapa filen Movie.java under models-paketet i eclipse. I sin helhet ser klassen ut så här:

java:

package models;

import play.db.jpa.*;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;

/* Tala om för JPA att det är en entitet */
@Entity
public class Movie extends Model { /* Få funktionalitet från Play!s modeller */
public String title;
/* Tala om för JPA att det ska kunna rymmas
mycket text i variabeln plot */
@Lob
public String plot;

/* Vår lista med skådespelare återkommer vi strax till */
@ManyToMany(cascade=CascadeType.PERSIST)
public List<Actor> cast;

/* Konstruktorn tar emot de nödvändiga parametrarna
som behövs för att skapa en film */
public Movie(List<Actor> cast, String title, String plot) {
this.cast = cast;
this.title = title;
this.plot = plot;
}
}

Vi ska ha ytterligare en modell i vårt projekt, för att visa ett en-till-många-förhållande, nämligen s.k. arbetstitlar för en film. En film kan alltså ha flera arbetstitlar, innan den slutgiltiga titeln sätts. Modellen ser ut som följer:
java:

package models;

import play.db.jpa.*;

import javax.persistence.*;

@Entity
public class WorkingTitle extends Model {
public String title;
/* Den här entiteten hör till “många”-gruppen
i ett en-till-många-förhållande */
@ManyToOne
public Movie movie;

/* På “många”-sidan injicerar vi vilken film
arbetstiteln hör till */
public WorkingTitle(Movie movie, String title) {
this.movie = movie;
this.title = title;
}
}


Nu måste vi ju dock uppdatera vår Movie-modell så att den innehåller alla sina arbetstitlar. Lägg till följande efter listan med skådespelare:
java:

@OneToMany(mappedBy=”movie”, cascade=CascadeType.ALL)
public List<WorkingTitle> workingTitles;

Vi behöver också initiera listan i konstruktorn, på samma sätt som vi gör med listan över skådespelare - men vi behöver inte ta emot en lista med arbetstitlar som parameter:
java:

public Movie(List<Actor> cast, String title, String plot) {
this.workingTitles = new ArrayList<WorkingTitle>();


Då ska våra modeller vara klara! Redan nu kan man köra projektet, för att se så att man inte har gjort något galet – Play! spottar direkt ur sig felmeddelanden. Kör play run moviedb från terminalen och peka webläsaren till http://localhost:9000 – förhoppningsvis ska du få upp samma välkomstskärm som första gången du körde projektet. Om du får ett felmeddelande är det väldigt välbeskrivande, med radnummer på var felet inträffade och i vilken fil tillsammans med några rader kod från där problemet hittades.

3. Första titt på vyer

I mappen views hittar vi våra vyer, sorterade i mappar med samma namn som kontrollern som anropar dom. Än så länge har vi inte rört våra kontrollers, och det finns bara två mapper – en för standardkontrollern Application och en för felhanteringen med mappen errors. I dessa mappar finns sidmallar i form av HTML-filer, mest kända som "template"-mallar. Direkt under mappen views finns en fil som heter main.html, som innehåller dokumentens huvud och fot – och som man använder som standardmall. In i denna mall injiceras sedan varje anrops (även kallad action) template-mall.

Om man har programmerat något i Groovy känner man igen en del från template-mallarnas syntax. Om man öppnar main.html (i eclipse högerklickar man och väljer "Open With > Text editor") så ser man var det injiceras data – nämligen vid alla #{...}/@{...}/${...}-taggar. Det magiska i filen händer vid #{doLayout /}, där action-templaten injiceras. Vi kommer snart att se mer på hur vi hanterar data i våra vyer.

4. Kontrollers

En kontroller (fr. eng. Controller) agerar mellanlager mellan entiteter/datakälla och vyer. De bestämmer vilken data som ska skickas till vyn, helt enkelt. Själva kontrollern är en klass, och dess metoder kallas för action-metoder – det är dessa som anropas när besökaren efterfrågar en sida. Varje action-metod svarar mot en vy med samma namn. T.ex. vyn views/listing/actors.html anropas när metoden actors() i kontrollern controllers/Listing.java anropas.

Play! har som sagt en standardkontroller färdig åt oss, Application.java, men det är väl lika bra att göra en egen på en gång?! Det vi vill göra på vår webplats är att lista filmer och tillhandahålla information kring dem, samt att lista skådespelare och information om dessa. Det låter väl ganska vettigt att då skapa en Listing-kontroller? Vi börjar med ett skelett:
java:

package controllers;

import play.*;
import play.mvc.*;

public class Listing extends Controller {

}

Om en besökare efterfrågar roten (/) på vår webplats, vill vi lista alla de filmer vi har i vår databas. Eftersom att ingen action har efterfrågats då, sätter vi upp en ingångs-action (eng. default action) kallad index(). I den här metoden vill vi då hämta alla våra filmer och skicka vidare till vyn, så att vyn kan presentera dom på lämpligt sätt. Alla action-metoder deklareras som statiska, för att Play! ska kunna anropa dom. Play! använder Javas Reflection API för att hitta i våra klasser, och anropar de nödvändiga metoderna. Play!s modeller tillhandahåller metoder enligt Active Record-pattern, vilket gör det enkelt för oss att skapa/läsa/uppdatera/ta bort objekt i/till datakällan – känt under akronymen CRUD (create/read/update/delete). Man använder Hibernates egna SQL-dialekt HSQL för att göra urval, sortering eller gruppering på resultatet. Action-metoden index() i kontrollern Listing:
java:

package controllers;

import play.*;
import play.mvc.*;

import models.*;

import java.util.List;

public class Listing extends Controller {
public static void index() {
/* Metoden find() i vår modell Movie är ärvd från
Play!s Model-klass. Den kan ta en HSQL-fråga
som parameter och returnerar ett fråge-objekt.
Fråge-objektet (av typen JPAQuery) har en metod fetch()
som kör frågan och returnerar alla träffar från
vår datakälla */
List<Movie> movies = Movie.find(“order by title asc”).fetch();

/* För att vår vy ska kunna nå resultatet skickar vi med
vår film-lista till metoden render(), som i sin tur
parsar vyn och skickar den till besökaren */
render(movies);
}
}

Vi vill ju också kunna lista alla våra skådespelare, så vi skapar en till action-metod som vi kallar för actors():
java:

public static void actors() {
List<Actor> actors = Actor.find(“order by name asc”).fetch();
render(actors);
}

Hur visar vi dom nu då?

5. Vyer för vår kontroller

Då har vi två vyer att skapa, en som listar filmer och en som listar skådespelare. Först och främst editerar vi main.html så att den passar oss:
HTML:

<!DOCTYPE html>

<html>
<head>
<title>MovieDB - min egen filmdatabas!</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" media="screen"
href="@{'/public/stylesheets/main.css'}">
</head>
<body>
<div id=”page”>
#{doLayout /}
</div>
</body>
</html>

Då börjar vi med vyn för action-metoden index() - börja med att skapa katalogen Listing under views, och filen index.html i den nyligen skapade katalogen, med följande innehåll:
HTML:

<!-- Här säger vi till mallen att den ska injiceras i main.html //-->
#{extends 'main.html' /}

<ul>
<!-- Genom olika funktioner i template-språket, kan vi åstadkomma
diverse funktionalitet, kommandot 'list' itererar igenom
listan 'movies' och skapar en lokal variabel 'movie' som svarar
mot den nuvarande platsen i listan. //-->
#{list items:movies, as:'movie'}
<!-- Genom variabeln 'movie' kommer vi nu åt alla egenskaper
hos vår film //-->
<li>${movie.title}</li>
#{/list}
</ul>

Vi skapar en liknande template för våra skådespelare, skapa filen actors.html i samma mapp:
HTML:

#{extends 'main.html' /}

<ul>
#{list items:actors, as:'actor'}
<li>Skådespelare: ${actor.name}</li>
#{/list}
</ul>


6. URL-mappning och rutter

För att vi nu ska kunna besöka vår filmdatabas behöver vi ändra om lite bland URL-mappningen för Play!. Fortfarande anropas nämligen Application.java som standard-kontroller om vi kör vårat projekt, och så kan vi ju inte ha det! Öppna upp filen conf/routes och titta på hur sökvägar definieras.
Kod:
# Home page
GET     /                                       Application.index

# Map static resources from the /app/public folder to the /public path
GET     /public/                                staticDir:public

# Catch all
*       /{controller}/{action}                  {controller}.{action}
Vi kan alltså komma åt vår index()-metod i Listing-kontrollern genom att ange URL:en http://localhost:9000/listing/index – men vi vill ju nå den med ett rot-anrop! Det som behövs är alltså att ändra första rutten för GET / så att den pekar mot vår kontroller och metod:
Kod:
GET     /                                       Listing.index
Lägg även in en rutt till listan med skådespelare:
Kod:
GET     /actors                                 Listing.actors
GET     /actors/                                Listing.actors
Nu är rutterna klara, men vi har ju ingen data! Vi behöver ett sätt att lägga till information till vår databas.

7. Knyt ihop säcken

Vi gör det enkelt för oss och skapar ett formulär under listningen av filmer, där man kan lägga till en film och dess skådespelare. Editera views/Listing/index.html:
HTML:

#{form @Listing.addData()}
<p>
<b>Filmens namn:</b><br />
<input type="text" name="title" />
</p>
<p>
<b>Handling:</b><br />
<textarea name="plot"></textarea>
</p>
<p>
<b>Skådespelare:</b> (separera med kommatecken)<br />
<input type="text" name="actors" />
</p>
<p>
<b>Arbetstitlar:</b> (separera med kommatecken)<br />
<input type="text" name="workingTitles" />
</p>
<p>
<input type="submit" value="Lägg till film" />
</p>
#{/form}

Play! har i sitt template-språk färdig funktionalitet för att skapa fomulär. @-tecknet visar att det gäller en pekning till en kontroller och action-metod, annars byggs formuläret som vanligt. Som man säkert förstår behövs nu ytterligare en metod i Listing-kontrollern, nämligen addData(). Vi får in datat från formuläret till parameterlistan för metoden, i den ordning vi la till den i formuläret:

java:

public static void addData(String title, String plot, String actors, String workingTitles) {
String[] actorList = actors.split(",");
String[] wtList = (workingTitles.trim().length() > 0) ? workingTitles.split(",") : new String[0];

List<Actor> cast = new ArrayList<Actor>();
for (String s : actorList) {
/* Vi ser först om det skådespelaren redan finns i
databasen, annars skapar vi honom/henne */
Actor actor = Actor.find("byName", s.trim()).first();
if (actor == null) {
actor = new Actor(s.trim());
}

cast.add(actor);
}
/* Skapa filmen och spara den tillsammans med
skådespelarna */
Movie movie = new Movie(cast, title, plot);
movie.save();

/* Om filmen hade några arbetstitlar skapar vi dom här,
och sparar ner dom med relationen till filmen */
for (String s : wtList) {
new WorkingTitle(movie, s.trim()).save();
}
/* Rendera index()-metoden för besökaren */
index();
}

Nu kan vi skapa filmer, skådespelare och arbetstitlar! Filmerna listas under http://localhost:9000/ och alla skådespelare hittar man under http://localhost:9000/actors.

8. Avslutning
Play! Framework är väldigt enkelt och snabbt att jobba med, och jag har såklart bara skrapat lite på ytan i det här exemplet. I exempelkoden som finns för nedladdning är koden något mer genomarbetad och lite mer funktionalitet finns inlagt. Det finns flera moduler som kan vara av intresse att titta på, som jag inte går igenom, som t.ex. admingränssnittet som Play! åstadkommer lekande lätt! Hoppas att läsaren har fått ut något vettigt ur det tunna materiel jag skrivit ned, och att törsten av att lära sig mer om ramverket har infunnit sig.

Happy coding!
Björn Wikström

Play! Framework: http://playframework.org/
En mer genomgående introduktion hittas på http://www.playframework.org/documentation/1.0.2.1/home
__________________
"Knock off the hippie shit, strap on a helmet and start shooting. This is Malibu, baby! I want you to storm that beach like it's fuckin' Normandy!"

Senast redigerad av SPiN, 2011-04-20 klockan 16:37
SPiN besöker inte forumet just nu   Svara med citat
Äldre 2011-04-19, 17:35   #2
erciz
Medlem
 
Registrerad: 2001-05-07
Inlägg: 1 880
Lösningar: 18
Tack för en bra artikel. Play verkar vara ett intressant ramverk. Jag har precis börjat leka lite med det. Kanske kommer att använda det på nån liten sajt, men måste lära mig mer först.

Jag har inte helt förstått arkitekturen. Play verkar ju inte använda sig av Java Servlets. Som jag har förstått det så skapar Java Servlets-containrar en ny tråd per besökare, vilket kan ta upp en del minne. Play verkar använda Netty istället. Betyder det att Play är mer event-driven och inte skapar en ny tråd per besökare?

Det är nu nästan ett år sen artikeln skrevs, har du eller kanske nån annan använt Play Framework för nåt skarp projekt? Hur upplevde ni det?
erciz besöker inte forumet just nu   Svara med citat
Äldre 2011-04-19, 18:28   #3
SPiN
Medlem
 
Registrerad: 2000-03-12
Ort: Göteborg
Inlägg: 5 832
Lösningar: 179
Tack.

Helt riktigt, Play! använder inte J2EEs Servlet API. Då skulle det nämligen inte vara möjligt med "code hotswapping", och du skulle få publicera om dina projektfiler till en servlet container efter varje koduppdatering. I längden blir det ganska tradigt under utvecklingstiden, när man ibland vill göra snabba kodförändringar. Jag tror inte att minnesanvändningen var någon anledning till att strunta i Servlet APIet. Att förbigå Servlet API innebär också att Play! blir helt stateless, och lätt kan lastbalanseras.

Däremot har en utvecklare skrivit en Servlet-wrapper, som i stort sett enbart binder in Play!-projektet i en/flera servlets.

Jag har inte lyckats få in Play! på jobbet, så än så länge är det bara i små hobbyprojekt som inte gått live jag använt Play!. Tyvärr.
__________________
"Knock off the hippie shit, strap on a helmet and start shooting. This is Malibu, baby! I want you to storm that beach like it's fuckin' Normandy!"
SPiN besöker inte forumet just nu   Svara med citat
Äldre 2011-04-19, 20:00   #4
colione
Forumtekniker
 
Registrerad: 2001-06-13
Ort: Stockholm
Inlägg: 3 385
Lösningar: 197
Nu har ju även scala-versionen blivit riktigt intressant:
http://scala.playframework.org/
__________________
Yes, I Blag!
colione besöker inte forumet just nu   Svara med citat
Äldre 2011-04-20, 10:34   #5
SPiN
Medlem
 
Registrerad: 2000-03-12
Ort: Göteborg
Inlägg: 5 832
Lösningar: 179
Ja, den skulle jag gärna vilja känna lite mer på! När tid finnes...
__________________
"Knock off the hippie shit, strap on a helmet and start shooting. This is Malibu, baby! I want you to storm that beach like it's fuckin' Normandy!"
SPiN besöker inte forumet just nu   Svara med citat
Äldre 2011-04-20, 11:42   #6
Lasp
Medlem
 
Lasps avatar
 
Registrerad: 2000-07-29
Ort: Fredriksdal, Helsingborg
Inlägg: 9 902
Lösningar: 143
Tack för ett intressant uppslag. Jag försökte att ta hem dokumentationen igår. Nu ser jag att de andra länkarna fungerar men ditt eget är väl borttaget.
Snygg beskrivning , och lättförståelig säger Lasp
__________________
Livet är kort och Nu!
Läs mera!
!?
Lasp besöker inte forumet just nu   Svara med citat
Äldre 2011-04-20, 16:39   #7
SPiN
Medlem
 
Registrerad: 2000-03-12
Ort: Göteborg
Inlägg: 5 832
Lösningar: 179
Tack, och helt riktigt -- jag har lyckats plocka bort exempelfiler och PDF-versionen från min server. Jag hittar dom inte på någon disk heller, men någonstans ligger dom tror jag... Trodde att jag lyckats plocka bort alla länkar, men det var en kvar såg jag nyss
__________________
"Knock off the hippie shit, strap on a helmet and start shooting. This is Malibu, baby! I want you to storm that beach like it's fuckin' Normandy!"
SPiN besöker inte forumet just nu   Svara med citat
Svar
webForum > Artiklar och källkod > Artiklar > Webbrelaterade artiklar

Trådverktyg
Visningsalternativ Betygsätt tråden
Betygsätt tråden:

Forumregler
Du får inte posta nya trådar
Du får inte posta svar
Du får inte bifoga filer
Du får inte redigera dina inlägg

BB-kod är
Smilies är
[IMG]-kod är
HTML-kod är av

Forumhopp


Alla tider är i GMT +1. Klockan är nu 06:41.


Powered by: vBulletin Version 3.8.6
Copyright © webForum