Showing posts with label Play. Show all posts
Showing posts with label Play. Show all posts

2010/02/13

Play!(3)

從上次的教學我們已經能夠瞭解到MVC的基本部份了。這次我們說明多個MODEL的互相連帶處理「一對多」「多對一」和使用
JUnit來測試Applicaiton.

Model的連帶處理考量

從上回簡單的訊息表示Model(MsgData),這次我們再加上一個新的使用者情報Model(PersonData),這樣子顯示訊息時
不僅可以顯示使用者名稱,通常是使用SQL的JOIN句子,來互相關連,不過在Play!裡是使用JPA,Data並不是SQL table,
都是作為物件永續化管理,Model的關聯也是被設計成物件和物件的互相關聯。

首先在「models」裡作成PersonData類別

package models;

import java.util.*;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import play.db.jpa.Model;

@Entity
public class PersonData extends Model {
        public String name;
        public String mail;
        @OneToMany
        public List<MsgData> messages;
        
        public PersonData(String name,String mail){
                this.name = name;
                this.mail = mail;
                this.messages = new ArrayList<MsgData>();
        }

}

在這裡除了name和mail兩個欄位以外,還有保管MsgData實例的List欄位,這個List就是用來整合關聯MsgData物件。
這裡一定要注意的是「@OneToManay宣告」,JPA裡物件的永續化時,如果沒加上@OneToMany的話,就無法達成永續化。
藉由加上@OneToManay,這就告訴JPA這個欄位成了一對多對應的物件參照欄位。

MsgData的修正

接下來MsgData裡使用PersonData來取代name

package models;

import java.util.Calendar;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import play.db.jpa.Model;

@Entity
public class MsgData extends Model {
        private static final long serialVersionUID = 1L;
        public String message;
        @ManyToOne
        public PersonData person;
        public Date time = Calendar.getInstance().getTime();
        
        public MsgData(String message,PersonData person){
                this.person = person;
                this.message = message;
                person.messages.add(this);
        }
}

在這裡面有保管PersonData實例的person欄位,並加上了「@ManyToOne」的宣告,這樣一來就能夠將MsgData永續化。
new的時候,傳入引數裡的PersonData實例,在設定person屬性的同時,呼叫出person的message.add,在person
這邊將訊息保管起來。

PersonData的Controller

接下來作成PersonData的Controller,在「controller」資料夾裡做一個新的「Person.java」檔案。
這次就先加入add和index兩個基本的方法。

package controllers;

import java.util.List;
import play.mvc.Controller;
import models.*;

public class Person extends Controller {

        public static void index(String name) {
                List<PersonData> datas = null;
                datas = PersonData.findAll();
                render(datas);
        }
        
        public static void add(String name,String mail){
                String msg = "請輸入資料。";
                if (request.method.equals("POST")) {
                        PersonData person = new PersonData(name,mail);
                        person.save();
                        msg = "資料已經被保存了";
                }
                render(msg);
        }
}

準備PersonData用的Template

接下來在「views」資料夾裡做一個新的「Person」資料夾,然後加入兩個檔案「index.html」「add.html」

#index.html的程式碼
#{extends 'main.html' /}
#{set title:'Home' /}
<h1>表示訊息</h1>
#{list items:datas, as:'data'}
    <li>${data.id}: ${data.name}(${data.mail})</li>
#{/list}

#add.html的程式碼
#{extends 'main.html' /}
#{set title:'Home' /}
<h1>作成訊息</h1>
${msg}
<form method="post" action="@{Person.add}">
<table>
        <tr><td>name:</td><td><input type="text" id="name" name="name" /></td></tr>
        <tr><td>mail:</td><td><input type="text" id="mail" name="mail" /></td></tr>
        <tr><td></td><td><input type="submit" value="送出" /></td></tr>
</table>
</form>

接下來修正MsgData的Controller

package controllers;

import java.util.List;
import models.*;
import play.mvc.Controller;


public class Application extends Controller {
        
        public static void index(String name) {
                List<MsgData> datas = null;
                datas = MsgData.findAll();
                render(datas);
        }
        
        public static void add(String message,String name){
                String msg = "請輸入資料。";
                if (request.method.equals("POST")) {
                        PersonData person = PersonData.find("name",name).first();
                        if (person != null){
                                MsgData data = new MsgData(message,person);
                                data.save();
                                person.save();
                                msg = "資料已經被保存了。";
                        } else {
                                msg = "個人資料尚未登入。";
                        }
                }
                render(msg);
        }

}

作成MsgData用的Template

#index.html的原始碼
#{extends 'main.html' /}
#{set title:'Home' /}
<h1>表示訊息</h1>
#{list items:datas, as:'data'}
    <li>${data.id}: ${data.message}(${data.person.name}, ${data.person.mail})</li>
#{/list}

#add.html的原始碼
#{extends 'main.html' /}
#{set title:'Home' /}
<h1>作成訊息</h1>
${msg}
<form method="post" action="@{Application.add}">
<table>
        <tr><td>name:</td><td><input type="text" id="name" name="name" /></td></tr>
        <tr><td>message:</td><td><input type="text" id="message" name="message" /></td></tr>
        <tr><td></td><td><input id="submit" type="submit" value="送出" /></td></tr>
</table>
</form>

顯示使用者投稿的全部訊息

從MsgData裡取得PersonData的@ManyToOne處理已經明白了之後。接下來利用看看@OneToMany關聯的實例。
稍微修正剛才Person的index.html,將它改成可以顯示所有使用者的訊息。

#{extends 'main.html' /}
#{set title:'Home' /}
<h1>表示訊息</h1>
#{list items:datas, as:'data'}
        <li>${data.id}: ${data.name}(${data.mail})
        <ul>
        #{list items:data.messages, as:'message'}
                <li>${message.message}</li>
        #{/list}
</ul>
</li>
#{/list}

完全不需要改動到Controller,在#{list items:datas, as:'data'}的重複操作中,又重複操作
#{list items:data.messages, as:'message'}來取出PersonData裡的messages全部元素。

有關測試

在Play!裡備有JUnit的標準測試機能,在作成的專案裡都會有「test」這個資料夾,這個資料夾就是為了要配置測試用的
程式碼的地方。裡面有標準的「ApplicationTest.java」「BasicTest.java」「Application.test.html」等名稱
的程式碼檔案。這是在專案作成時自動生成的測試用程式碼,當然也可以修正這些檔案來做自己想要的測試。

在Play!裡有三種測試種類。「UnitTest(單元測試)」「FunctionalTest(功能測試)」「SeleniumTest」。
想要實行測試模式時,只要輸入

play test sampleapp

然後測試下面的網址

http://localhost:9000/@tests

檢查UnitTest程式碼

首先先看實行UnitTest的「BasicTest.java」檔案

import org.junit.*;
import java.util.*;
import play.test.*;
import models.*;

public class BasicTest extends UnitTest {

    @Test
    public void aVeryImportantThingToTest() {
        assertEquals(2, 1 + 1);
    }

}

在這裡「assertEquals」方法傳入兩個引數比較是否相等。這個UnitTest類別是直接繼承JUnit的org.junit.Assert類別,
並直接使用JUnit的assert方法。

檢查FunctionalTest程式碼

import org.junit.*;
import play.test.*;
import play.mvc.*;
import play.mvc.Http.*;
import models.*;

public class ApplicationTest extends FunctionalTest {

    @Test
    public void testThatIndexPageWorks() {
        Response response = GET("/");
        assertIsOk(response);
        assertContentType("text/html", response);
        assertCharset("utf-8", response);
    }
    
}

接下來在FunctionalTest裡加上一些各自的定義。頁面的存取已經在上面的範例測試過了,這次就定義測試Model的方法。

@Before
public void setup() {
        Fixtures.deleteAll();
}

@Test
public void testModelData() {
        PersonData p = new PersonData("測試", "test@test.com");
        p.save();
        MsgData m = new MsgData("這是測試。", p);
        m.save();
        p.messages.add(m);
        p.save();
        assertNotNull(p);
        assertNotNull(m);
        assertEquals(p.name, m.person.name);
        assertEquals(m.id,p.messages.get(0).id);
        List<PersonData> plist = PersonData.find("name", "測試").fetch();
        assertEquals(1, plist.size());
        List<MsgData> mlist = MsgData.find("person", plist.get(0)).fetch();
        assertEquals(1, mlist.size());
}

在這裡作成PersonData和MsgData,首先作成PersonData實例並保存,接下來將訊息和PersonData作為
引數作成MsgData實例,然後確認p和m的依存關係。assertNotNull確認引數是不是null。
assertEquals確認PersonData和MsgData的相同參照物件的name和id是否是參照到正確的物件。

這個測試之前,有一個setup的方法,並使用了「@Before」的宣告,這是表示說這是在測試前的前置動作,這裡用「Fixtures.deleteAll();」
就是將之前測試用的資料全部刪除、在每一個測試開始之前基本上都要先像這樣將資料初始化。

透過data.yml來生成測試資料

如果像之前生成資料、確認資料都還要寫一堆程式碼,在生成大量資料的時候就變得很麻煩。而且當要改變資料內容來驗證時
又還需要重新更改程式碼,如果可以的話,希望能夠把Model和程式碼切離。

在Play!的情況,「test」資料夾裡有一個「data.yml」檔案,紀錄了Model相關的情報,藉由這個來自動生成資料是可能的。

PersonData(tuyano):
  name: tuyano
  mail: tuyano@mac.com

PersonData(taro):
  name: taro
  mail: taro@yamada.com

MsgData(msg1):
  message: Hello
  person: tuyano

MsgData(msg2):
  message: Good-bye
  person: taro

把data.yml打開,然後以這樣的格式紀錄Model內容

Model名稱 ( 實例名稱 ):
屬性名稱: 値
屬性名稱: 値
……以下略……

測試用的程式碼

@Test
public void testFullData() {
        Fixtures.load("data.yml");
        assertEquals(2, PersonData.count());
        assertEquals(2, MsgData.count());
}

SeleniumTest的原始碼

SeleniumTest是在以HTML為基礎的Template檔案裡嵌入特殊的標籤來實行的。打開「Application.test.html」就能知道了。

#{selenium}
        open('/')
        waitForPageToLoad(1000)
        assertNotTitle('Application error')
#{/selenium}

使用seleniumTest測試add頁面

在Application.test.html裡加入

#{fixture delete:'all', load:'data.yml' /}
#{selenium}
        open('/add')
        waitForPageToLoad(1000)
        type('name','test')
        type('message','*** this is selenium test.***')
        clickAndWait('submit')
#{/selenium}

參考文章:http://codezine.jp/article/detail/4752

2010/01/31

Play!(2-4)

資料的修正


接下來為保存好得資料作成修正功能吧。這就是將資料的作成和檢索組合起來。換句話說,把要再次編輯的資料藉由檢索取出
然後改變值之後存入的作業。

那麼來製作模板吧。在「views」的「Application」裡作成一個新的「edit.html」檔案,然後加入下面的原始碼。

#{extends 'main.html' /}
#{set title:'Home' /}
<h1>Editing Message</h1>
${msg}
#{if data != null}
<form method="post" action="@{Application.edit}">
<input type="hidden" name="id" value="${data.id}" />
<table>
        <tr><td>id:</td><td>${data.id}</td></tr>
        <tr><td>name:</td><td><input type="text" name="name" value="${data.name}" /></td></tr>
        <tr><td>message:</td><td><input type="text" name="message" value="${data.message}" /></td></tr>
        <tr><td></td><td><input type="submit" value="Submit" /></td></tr>
</table>
</form>
#{/if}

這裡準備了修改特定資料的編輯表單,這個表單裡id號碼是用隱藏起來不給人修改,其他的
name和message用<input type="text">的可編輯顯示。分別把${data}的值設給value的話,編輯的資料值在一
開始就會顯示之前的訊息值。

後來的Controller部份,把再度編輯後的資料取得,作為${data}處理,然後用POST送出的話,這個資料就被
修正、保存了。那麼來實際寫edit方法吧。

public static void edit(long id,String message,String name){
        String msg = "Please edit data";
        MsgData data = null;
        data= MsgData.findById(id);
        if (request.method.equals("POST")) {
                data.name = name;
                data.message = message;
                data.save();
                msg = "Data was updated";
        }
        render(data,msg);
}

編輯的資料用id這個成員來指定,存取的時候URL會像「http://localhost:9000/edit?id=1」這樣,edit的後面
接著「?id=號碼」這樣的形式來存取該id的資料並顯示出該id的資料內容表單,只要將裡面的內容改寫然後送信就能修
正資料了。

這裡首先先透過GET的存取、藉由引數id的指來取得資料,交由render來處理。從id取得資料只要用findById就可以。

data = MsgData.findById(id);

「findById」是用被指定的id號碼來取出資料。需要注意的是「引數不是int而是long」的這一點。用這樣的方法取出資料
然後改變值保存。POST時的處理就用下面這樣來處理。

data.name = name;
data.message = message;
data.save();

為實例的欄位作新的設定、用save保存。save不只用在加入新的資料,也在這樣資料更新的時候使用。

資料的刪除


剩下的就只有資料的刪除了。這也是直接利用資料的修正的介面。id=xx的形式把成員附加在後面來然後顯示、按下按鈕送
出後就會將那個資料刪除的作業流程。

首先從模板開始。「views」的「Application」裡作成一個「del.html」檔案

#{extends 'main.html' /}
#{set title:'Home' /}
<h1>Delete Message</h1>
${msg}
#{if data != null}
<form method="post" action="@{Application.del}">
<input type="hidden" name="id" value="${data.id}" />
<table>
        <tr><td>id:</td><td>${data.id}「${data.message}」</td></tr>
        <tr><td></td><td><input type="submit" value="Delete" /></td></tr>
</table>
</form>
#{/if}

基本的形式跟edit.html一樣。不同的地方是表單裡只有送出的id而已。只要削除的id號碼
就足夠了。

接下來在Controller裡準備Application要存取的「del」方法。

public static void del(long id,String message,String name){
        String msg = "Do you want to delete data?";
        MsgData data = null;
        data= MsgData.findById(id);
        if (request.method.equals("POST")) {
                data.delete();
                msg = "data was deleted";
        }
        render(data,msg);
}

跟剛才的edit一樣「del?id=1」這樣的URL形式,將id作為成員接在後面來存取後將資料表示出來。確認之後按下按鈕
資料就會被刪除。這裡用MsgData.findBy(id)取得資料然後刪除。

data.delete();

只是這樣就將資料刪除了,相當的單純。

Play!(2-3)

展現資料


那麼來展現我們已經儲存的資料吧,這要修改index動作來達成。首先先修正動作方法。

public static void index() {
        List<msgdata> datas = MsgData.findAll();
        render(datas);
}

非常的簡單。要取得MsgData的全部資料,只要呼叫「findAll」這個方法就可以了。這將MsgData的實例作為List將值返回。
這裡將datas這個變數交由render的引數呼叫出來。之後在模板那一邊只要從datas順序取出MsgData,然後將必要的值顯
示出來就好。修改index.html如下:

#{extends 'main.html' /}
#{set title:'Home' /}
<h1>Message List</h1>
#{list items:datas, as:'data'}
    <li>${data.id}: ${data.message}(${data.name})</li>
#{/list}

在這裡的#{list itmes:datas, as:'data'}~#{/list}的部份,從datas順序取出的值設定為data這個變數,
然後重複的執行。語法就像下面這樣的型態。

#{list items:$Container, as:'$var'}

items:的後面的$Container指定收納的容器名稱,這樣一來就會從裡面順序取出物件,並代入用as:指定的變數$var,
不斷重複直到#{/list}為止的處理。因為取出的值為MsgData的實例,所以${data.message}可以寫出message欄位
的值。

話說回來,再更清楚的來看,最一開始寫著${data.id}。這是寫出實例的「id」的值。但是想一下卻發現MsgData並沒有準
備id這個欄位才對。

因為這個id欄位是Model類別自動追加的特別欄位,所有的MsgData實例都有事先準備好這個id,自動分配給每個人唯一
的id值。簡單來說就是「自動生成的主鍵」。

資料的查詢


要取出所有的資料只要用findAll就能簡單的做到,但是符合特定的條件的搜索時要該怎麼辦呢。改寫剛才的index,使用
name來檢索看看吧。

#{extends 'main.html' /}
#{set title:'Home' /}
<h1>Message List/h1>
<form method="post" action="@{Application.index}">
name:<input type="text" name="name" />
<input type="submit" value="Submit" />
</form>
<hr />
#{list items:datas, as:'data'}
    <li>${data.id}: ${data.message}(${data.name})</li>
#{/list}

修改index.html,加入表單。在這裡輸入name送出,藉由這個來最資料的搜索然後表示。那麼、來修改index方法吧。

public static void index(String name) {
        List<msgdata> datas = null;
        if (request.method.equals("POST")) {
                datas = MsgData.find("name like ?", "%" + name + "%").fetch();
        } else {
                datas = MsgData.findAll();
        }
        render(datas);
}

這樣一來就完成了。從瀏覽器存取index,輸入名字然後送出看看吧。只有含有這個名字的資料會被搜尋出來。這裡如果被
POST送出後,會用下面這樣來取得資料。

datas = MsgData.find("name like ?", "%" + name + "%").fetch();

「find」透過引數,實際上是生成為了要從資料庫中取得資料的JPAQuery實例。這裡的從JPAQuery呼叫出「fetch」方法,
將資料作為List來取得。

find使用"name like ?"簡單的詢問作為第一個引數,這個?的部份裡、第2引數的"%"+name+"%"被埋在裡面。
也就是說、"name like %$text%"使用這樣的方法被實行。

這雖然跟SQL的語法相似,但是select什麼的並不需要被使用。這就是「JPQL詢問」,透過JPA使用的簡單語法。
可能會想說「雖然說不用SQL語法,結果還不是不得用相似的東西來寫嘛」,確實是這樣沒錯,可以看出Model部份
的實裝還不是很完全。資料的作成和修正、消除等雖然只是用方法呼叫出來,但是有關詳細的檢索還是得需要寫類似
SQL語法的部份還是有的。

雖然這樣,如果有單純「這個屬性值=檢查值」這樣簡單的檢索的話,像搜索一般的搜索語法也不需要了,只要簡單的輸入
「find(屬性、值)」就足夠了。請想也只有在要一些細節設定的搜索語句時才需要寫它們就好了。

2010/01/28

Play!(2-2)

資料的作成和保存

那麼、為MsgData類別準備一個新的應用程式吧,在這裡準備了一個「add」的動作。首先先製作好模板。「views」裡的「Application」內新增一個新的「add.html」文件,然後將如下內容加入:

#{extends 'main.html' /}
#{set title:'Home' /}
<h1>メッセージの作成</h1>
${msg}
<form method="post" action="@{Application.add}">
<table>
        <tr><td>name:</td><td><input type="text" id="name" name="name" /></td></tr>
        <tr><td>message:</td><td><input type="text" id~"message" name="message" /></td></tr>
        <tr><td></td><td><input type="submit" value="送信" /></td></tr>
</table>
</form>

這次準備了name和message這兩個輸入欄位,傳送目地指定為action="@{Application.add}"。這樣一來我們知道只要在Application類別裡準備好add方法就可以了。

這樣子模板就完成了,可是只有這樣子似乎讓人覺得少了些什麼、那麼讓我們使用Stylesheet吧。Play!裡像Stylesheet這樣的靜態檔案是配置在「public」資料夾內。在這裡面有個名為「stylesheets」的資料夾,在裡面作成一個「main.css」文件。這個是使用標準作成的Stylesheet的文件檔。把這個打開之後,加入下面的內容:

body {
        font-size:10pt;
        background-color:#F6FFFF;
        color:#003366;
}
h1 {
        font-size:12pt;
        background-color:#CCDDFF;
        padding: 3px;
}

因為這是Stylesheet,內容可以因人而異,請自己適當的調整。

那麼,接下來來製作Controller。來定義Application類別裡的add方法吧。

public static void add(String message,String name){
        String msg = "Please input data";
        if (request.method.equals("POST")) {
                MsgData data = new MsgData(message,name);
                data.save();
                msg = "data is saved";
        }
        render(msg);
}

這樣子就完成了。嘗試著存取http://localhost:9000/application/add看看就會表示出一個表單,在這裡面輸入值然後傳送的話,資料就會被保存起來(只是還沒顯示)。每次位置都得要輸入/application/add讓人覺得有點麻煩、所以我們在「routes」檔案裡加入下面這行內容:


* /{action} Application.{action}


這樣一來、Application類別的動作方法就全部都被映射到根目錄了。以後想要呼叫add的話就用http://localhost:9000/add

add方法的流程

那麼,來看看這裡的處理過程吧。首先、方法add(String message, String name)就像這樣有引數被設定好,
以動作方法而言,被送出的參數會將值交給同名的變數。這樣一來從表單送出的message和name的值就能作為引數取得

request.method.equals("POST")是為了要確認是否是POST送出,true的話就將MsgData保存到資料庫裡


MsgData data = new MsgData(message,name);
data.save();



這裡就連說明都不用說明了。用new MsgData來作成實例,然後呼叫出「save」方法。這樣一來MsgData的實例就被保存
在資料庫裡了。這就是Model類別的威力。為了將Model保存到資料庫的具體程式碼完全都不需要特別敘述什麼。

原文參考:http://codezine.jp/article/detail/4751?p=2

Play!(2-1)

說到Struct和JSF這些Java Framework,它們都沒有一個標準的資料庫關系的功能。但是從ROR(Ruby on Rails)以
後的MVC Framework,負責存取資料庫部份的「Model」卻佔有著重要的角色。

Play!的資料庫存取是使用「JPA(Java Persistance Architecture」,這是為Java EE所準備的,為了要使物件
永續化的技術,大多數的網頁應用程式的資料庫是使用傳送SQL詢問句來做存取的動作,但是在Play!裡,SQL幾乎都不會
出現。只要定義一個被稱為「Model」的類別,並呼叫它的方法就能進行資料庫操作。

而且,在使用資料庫的場合,資料庫的基本操作和根據特定的人連線進入操作的權限不同也變的是需要的。

資料庫的設定

網頁應用程式和資料庫的關係是不管怎麼切都切不斷的關係,在Java裡,從以前到現在的資料庫存取就是由「JDBC用
SQL的詢問送出來取得資料」的一般存取方法。Hibernate等的O/R映射並沒有改變太多這樣的概念,Structs等並
沒有這些標準的技術來存取資料庫,還需要自己組合才可以使用,在Play!裡就有準備了一個標準的資料庫存取機能

MVC架構裡,資料庫的存取是由「Model」所實行的,要操作資料庫,首先定義必要的Model類別,然後呼叫出來使用,這
樣子可以將資料庫的獨特的處理部份與程式本體分離開來,Play!也是一樣,定義Model這件事情成為了資料庫使用的
基本,讓我們來實際做做看吧。

首先,準備使用資料庫的相關設定,在Play!裡已經內藏一個名為HSQL的純Java資料庫程式,以學習等級而言,這個就
足夠了,打開application.conf,然後加入一行

db=men

這是表示使用HSQL在記憶體上保管資料的模式,因為是保管在記憶體裡,所以當Server終了的時候,資料也會跟著消失,
要確認程式是否動作,這樣就已經很足夠了,想要將資料完整的保存的場合請使用「db=fs」,這是表示使用檔案保存的模式

雖然這次並不使用,HSQL以外的資料庫也可以在Play!上使用,例如想要使用MySQL5的話,就如同下面這樣把設定加入

db=mysql:$UserName:$Password@$DatabaseName

不管怎麼說,只要簡單的一行設定就可以了。只需要改變設定,除此之外其他的程式完全都不需要變更就能夠切換資料庫,
這就是使用Model的最大的優點,「資料庫的切換並不是這麼常有的吧?」有時候會這樣想,但是例如開發的時候使用替代
的資料庫,而在正式釋出後可以存取正式的資料庫,這樣的事情不是經常發生嘛?這種時候如果是直接把SQL語句寫在程
式碼內的話,想你也能夠想像這樣事情是有多麼的糟糕。

Model的作成

那麼,來製作Model吧,這次先思考看看一個極為單純的訊息保管資料庫。來作成一個只保存名字、訊息內容還有發布時間
的簡單Model吧。在「app」內的「model」資料夾裡製作一個新的檔案叫做「MsgData.java」,然後加入下列內容:

package models;

import java.util.Calendar;
import java.util.Date;
import javax.persistence.Entity;
import play.db.jpa.Model;

@Entity
public class MsgData extends Model {
        private static final long serialVersionUID = 1L;
        public String message;
        public String name;
        public Date time = Calendar.getInstance().getTime();
        
        public MsgData(String message,String name){
                this.name = name;
                this.message = message;
        }
}

這就是這次用來保存訊息的類別,在類別的定義前加上「@Entity」這個宣告,這表示說這個類別是JPA的「Entity」,
Entity是Java EE使用的資料物件,為了要用JPA來把資料永續化,所以標明它是Entity是必要的。

這次作成的MsgData類別是繼承「play.db.jpa.Model」這個類別來作成的,記得每一個Model都要繼承這個類別,
類別裡有message、 name、 time等欄位,各自保管自己的資料。在這裡面,代表時間的date在實例作成的階段就
已經將現在的時間保管了起來。message和name這兩個常數是準備用來接受傳遞的引數並直接作成實例。

稱作Entity可能會讓你覺得不太熟悉,但是說它只不過是一個很一般的Bean就應該很明瞭了。完全沒有任何資料的查找
和保存等的相關處理,只是僅僅準備了資料保管的欄位和常數而已。

原文參考:http://codezine.jp/article/detail/4751

2010/01/25

「Play!」快速上手(1)

Play!是什麼?

Play是一個ROR-like的Java Framework,讓你可以快速的開發網頁程式。1.0版在2009年秋天的時候發布,是一個很新的框架,它有著簡單的Patch Program,使用這些可以讓你自動生成網頁程式的骨架(雖然我覺得現在IDE都有了XD),不過它重點是讓你簡單的編寫,簡單的設定就能寫出網頁。

還有Play將所有MVC都齊全了,這就是他的最大特徵,Java Framework有一大堆,但是都是一個一個的以不同的方面為主,無論是Structs或是JSF還是連接Database部份的「Model」其實都不夠充實,「那麼就使用Hibernate這種ORM映射框架就好了」這是Java現在所推崇的,但是「如果一個Framework就能將所有的東西都齊全,後面的處理都不需要了」這種框架當然是比較好的,「只要使用一個這個,就能夠馬上開發」,這就是Play的最大特徵

先到Play的官網下載1.0.1版本。
http://www.playframework.org/


  1. 下載完後解壓放到有寫入權限的資料夾下(這點通常是Linux才要注意的),在Window下,我將它放在C:\下面。
  2. 打開Command Line Mode,cd到play的資料夾下並輸入play new sampleapp來創造新的專案,它會再次詢問專案名稱,輸入一樣的名稱即可
  3. 馬上開始試跑看看吧~輸入 play run sampleapp
  4. Play預設的HTTP Port是9000,所以打開瀏覽器瀏覽 http://localhost:9000/
接下來讓我們研究一下play/sampleapp/資料夾下的架構吧,想必用過ROR的人都覺得這些資料夾的名稱很熟悉,因為這就是ROR-like的框架嘛XD。

  • app:這個資料夾是整個應用程式的本體(收藏MVC的基本部份),打開裡面就看的到三個資料夾,分別是controller, model, view
  • conf:設定文件集中的地方(例如說router)
  • lib:這裡存放一些Library...別跟我說不知道什麼是library
  • logs:就是log..不用說明了吧
  • public:這裡存放靜態網頁的東西,例如說HTML, JavaScript, CSS, 圖片等
  • test:這是用來測試應用程式的資料
  • tmp:暫時資料夾

為了開發方便,我們可以把Play跟IDE整合

如果想跟Eclipse整合請輸入 play eclipsify project-name
如果想跟Netbeans整合請輸入 play netbeansify project-name

Play會直接幫你轉成那個IDE的專案,再打開IDE直接開啟即可。

再來說明app資料夾


  • Application.java:「controllers」裡被作成的,藉由被指定的位置被連接之後,會呼叫出這個controller裡面的特定方法來做一些必要的處理。
  • main.html:這是layout的模板,大家都得跟著這個模板走就對了。
  • index.html:預設的連接頁面的範本,這裡面寫的是實際的內容。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        <head>
                <title>#{get 'title' /}</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'}" />
                <link rel="shortcut icon" type="image/png"
                                href="@{'/public/images/favicon.png'}" />
        </head>
        <body>
                #{doLayout /}
        </body>
</html>

觀察上面的main.html程式碼,發現title的部份是#{get 'title' /}而body的部份是#{doLayout /}
再看看index.html的程式碼,短短地三行。

#{extends 'main.html' /}
#{set title:'Home' /}

#{welcome /}

#extends就是看要用哪個layout
#set title就是設定剛剛main.html裡的title變數
#welcome就是body裡的東西~它會連到Framework的Homepage

來說說Application.java

package controllers;

import play.mvc.*;

public class Application extends Controller {

    public static void index() {
        render();
    }

}

controller class繼承了play.mvc.Controller來作成,裡面的方法是跟所要連接的網頁是同名的,因為我們要連接到index所以就有index方法。

這裡使用了一個render方法,這會從main.html這個模板和index.html互相結合然後給予出來。

這個「index」被稱作「動作」,我們可以這樣解釋,在預設對localhost:9000連接時index這個動作被設定要實行,然後這個應用程式準備了index這個行為來render index.html,這個index.html就被rendering了。

總之就是用名稱來互相約定該如何互相呼叫,這就是ROR類型的Framework的最大特徵,「約定勝於設定」。

來簡單說router(在conf資料夾下)



GET     /       Application.index
GET     /public/        staticDir:public
*       /{controller}/{action}  {controller}.{action}


這裡紀錄了該如何存取網頁。



  • GET / Applicaiton.index:這是存取/下的Application.index,藉由這個,存取根目錄時會實行Application這個Class裡的index方法。
  • GET /public/ staticDir:public:這是存取到/public/資料夾下,把靜態的東西直接呼叫出來,並不是透過Controller來存取的。
  • * /{controller}/{action} {controller}.{action}:這裡使用萬用字元*字號,意思就是說除了上面設定的那些之外,如果存取URL是/controller/action/的時候,就會用controller把action呼叫出來,例如說http://localhost:9000/application/index
這只是簡單的Router說明,Router還有更多複雜的設定和妙用。

為了等回而的Form傳遞教學,我們先在router裡加入一行



POST    /       Application.index

並將index.html改成





#{extends 'main.html' /}
#{set title:'Home' /}

<div>${val ? ('Hello、' + val + '!') : 'Please input your name。'}div>
<form method="post" action="@{Application.index}">
        <input type="text" name="val" />
        <input type="submit" value="Submit" />
form>

注意到form裡的action,就是使用controller.action的模式做連結。

將Application.java裡的index方法改成


public static void index(String val) {
        render(val);
}
代表說每次呼叫index的時候都會去取得val並render給index.html使用

這樣我們就可以開始嘗試我們辛苦做出來的應用程式了,第一次讀取的時候可能會比較花時間,因為不管再怎樣簡單,都脫離不了Servlet的概念,這是J2EE的定義,詳細情形請上Sun網站看JavaEE tutorial或是看一下我的JSF的文章,有地方有稍微提到。


參考文章:http://codezine.jp/article/detail/4750 (日文)