간단한 화면도 DB를 이용한 CRUD 중 'C'를 학습해 보도록 하겠다 Play Framework는 기본적으로 H2를 임베딩하고 있기때문에 주석을 단3줄만 제거하는것으로 설정을 끝낼수 있다.


1. application.conf 의 수정

# Database configuration
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
# Ebean configuration ebean.default="models.*"

한줄 한줄 설명하기 보단 따라하다보면 언젠가는 이해할 수 있을 것이다.

기본 DB명을 [message] 로 정하고 위의 3줄을 입력하였다. (기존 주석 처리된 라인을 이용해도 된다)

default DB가 없이는 다른 Database name을 지정할 수 없다. 즉 첫 번째는 무조건 default이다. 아... 삽질이여 ㅠ_ㅠ

db.default.url="jdbc:h2:mem:play" 는 H2 디비 메모리 모드, 만약 파일로 설정할경우는 

db.default.url="jdbc:h2:path_db_name.db" 처럼 사용하자

* 참고#1 : http://www.h2database.com/html/cheatSheet.html



2. .Model 생성

기본 프로젝트에서는 Models 패키지가 없으므로 app.models 패키지를 추가한다. 그리고 Message.java를 입력한다.

package models;
 
import java.util.List;
import javax.persistence.*;
import play.data.validation.Constraints.Required;
import play.db.ebean.Model;
 
@Entity
public class Message extends Model {
 
    @Id Long id;
    @Required String content;
     
    static Finder<Long, Message> find = new Finder(Long.class, Message.class);
     
    public Message(String content){
        this.content = content;
    }
     
    public static List<Message> all(){
        return find.all();
    }
     
    public static Message findById(Long id){
        return find.ref(id);
    }
 
}

3. Routes 수정

GET     /  는 필요없다고 삭제하는 그런 사소한 얘가 아니다. 얘는 나두고 한 줄 더 추가하자.

# Home page
GET     /	controllers.Application.index()
GET 	/list	controllers.Application.getList()



4. Application.java의 수정

index()는 /list으로 리다이렉트 하도록 수정하고, /list에 매핑되는 Entry Point Method를 하나 작성하자.

package controllers;

import java.util.List;

import models.Message;
import play.mvc.Controller;
import play.mvc.Result;

public class Application extends Controller {
  
  public static Result index() {
    return redirect(routes.Application.getList());
  }
  
  public static Result getList(){
	  List messages = Message.all();
	  return TODO;
  }
  
}


5. 중간 실행 단계

위의 코드를 정상적으로 작성하고 http://localhost:9000를 호출하면 아래와 같은 화면을 볼 수 있을 것이다. 

붉은 화면이라고 해서 노여워하거 슬퍼하지 말고 Apply this script now! 버튼을 누른다. models의 해당 Model Object를 기반으로 DDL을 생성해 준다. 이후 return TODO로 작성을 하였기 때문에 TODO의 화면을 볼 것이다. 그리고 콘솔에서는 database [default]가 운영중인 메세지를 노출한다

[info] play - database [default] connected at jdbc:h2:mem:play
[info] play - Application started (Dev)


6. 간단한 View 파일의 생성

Application.java 의  getList() 를 수정해보자

  public static Result getList(){
	  List messages = Message.all();
	  return ok(views.html.message.list.render(messages) );
  }


다음 app/views/message 폴더에 list.scala.html 파일을 생성한다

@(messages: List[Message])
[html]
	[head][/head]
	
	[body]
		[h1]@if( messages.size() == 0) { 
			No Message 
		} else { 
			@messages.size() POST(s) 
		}[/h1]
	[/body]
[/html]


먼가 Message 데이터가 없기 때문에 Size = 0 일꺼고, No Message 를 화면에 출력한다는것을 어렴풋이 생각할 수 있다.

message 폴더에 list.scala.html 이기 때문에 Action Method에서는 message.list.render(값) 으로 사용한다. 그리고 Action Method에서 넘어오는 인자들은 view page의 1라인에서 각 변수에 할당하여 사용하고 있다.

데이터가 없으니 이거 뭐 확인 할 길이 있나...? 더미 데이터를 한번 넣어보자.


application.conf 를 보면 아래 부분을 볼 수 있다.

# Global object class
# ~~~~~
# Define the Global object class for this application.
# Default to Global in the root package.
# global=Global
root package (app) 에 Global 이름으로 생성할 수도 있지만, 간지를 위해 #global=Global 을 global=InitSampleData 으로 수정하고 /app/InitSampleData.java 파일을 작성하자
import java.util.List;
import java.util.Map;

import models.Message;
import play.Application;
import play.GlobalSettings;
import play.libs.Yaml;
import com.avaje.ebean.Ebean;

public class InitSampleData extends GlobalSettings {
	@Override
	public void onStart(Application app) {
		Map> samples = (Map>)Yaml.load("sample.yml");
		Ebean.save(samples.get("message"));
	}
	
}
다음 conf/sample.yml 파일에 샘플 데이터를 입력한다
message:

    - !!models.Message
        id:     11
        content:  content from sample.yml #1

    - !!models.Message
        id:     12
        content:  content from sample.yml #1


데이터 형식은 Yaml로 작성해야 하고, play.libs.Yaml.load(String fileName) 으로 로딩할 수 있다. 그리고 GlobalSettings 를 상속 받으면 application start-up / shut-down 에  작업을 할 수 있다.

(물론 application start-up될때마다 수행되므로, shut-down할때 삭제하던지 하는 방법등으로 중복 insert를 방지하는건 기본센스)

이제 실행해보면, 기본적으로 2개의 데이터가 있다는 결과 화면을 볼 수 있다~!


테스트 데이터를 넣는 방법은  Evolutions scripts 으로도 가능한데, 이건 다른 포스팅에서 작성한다. 


추가.

SBT에서 [package-src]로 추출한 소스를 첨부한다. 받아서 jar를 푼다음, eclipsify 를 이용한다면 쉽게 볼 수 있을것이다. 


tutorial_2.9.1-1.0-SNAPSHOT-sources.jar




1. 기본 프로젝트 실행하기

C:\workspace_spring3\tutorial>play new tutorial

커맨드로 tutorial 이름을 가지는 java 프로젝트를 생성하였다.  

C:\workspace_spring3\tutorial>play

[info] Loading project definition from C:\workspace_spring3\tutorial\project

[info] Set current project to tutorial (in build file:/C:/workspace_spring3/tutorial/)

       _            _

 _ __ | | __ _ _  _| |

| '_ \| |/ _' | || |_|

|  __/|_|\____|\__ (_)

|_|            |__/


play! 2.0.2, http://www.playframework.org


> Type "help play" or "license" for more information.

> Type "exit" or use Ctrl+D to leave this console.


[tutorial] $ run


--- (Running the application from SBT, auto-reloading is enabled) ---


[info] play - Listening for HTTP on port 9000...


(Server started, use Ctrl+D to stop and go back to the console...)

이후 Play Command Line에서 [run]을 실행하면 하단의 메시지 처럼 9000 port에서 서버가 실행되었다는 메세지를 확인 할 수 있다. (Ctrl + D를 통하여 Play Command Line으로 복귀 할 수 있으며, 다양한 작업을 수행 할 수 있다)

 http://localhost:9000  에서 해당 서버의 실행 모습을 확인 할 수 있다. 해당 웹어플리케이션은 Play framework가 제공하는 기본 skeleton code가 근본이며, 이것을 실행하고 해당 내용을 읽는 정도로도 많은 부분을 파악 할 수 있을 것이다.


2. 기본 Controller

위치 : conf 폴더의 routes 파일

# Home page

GET     /                           controllers.Application.index()

Get Method로 / URL에 접근하면, controllers.Application.index()를 Action Method로 인지하여, 해당 메소드를 수행한다. 해당 메소드는 app/controllers 폴더에 Application.java 내에 위치하고 있다.

package controllers;

import play.*;


public class Application extends Controller {


  public static Result index() {

    return ok(index.render("Your new application is ready."));

  }

}

CoC ( Convention Over Configuration ) 는 설정이상, 설정을 넘은 관례라고 생각할 수 있다. 개발자가 일일히 지정해야 하는 설정이 아닌 관례를 따른다면, 많은 결정들을 하지 않고 단순함과 유연함을 추구할 수 있다. 많은 부분에서 이러한것을 확인 할 수 있을 것이다.


예로, Get /main 으로 접근하는 페이지를 추가해보록 하자.

routes 에 1줄 추가

# Home page

GET     /                           controllers.Application.index()

GET   /main         controllers.HelloApplication.main()


app/controller/HelloApplication.java 파일 생성후 입력

public class HelloApplication extends Controller {

public static Result main(){

return TODO;

}

}

a. Action Method는 public static 이어야 하는점

b. routes의 Action Method정의 부분은 JavaClass.MethodName 호출하는 것은 어떤 설정이 아닌, 원래 그렇게 하기 때문이다.CoC


코딩을 완료한후 http://localhost:9000 을 다시 브라우저에서 확인해보면  (Ctrl+D를 누르고 Clean->Compile->Run 해도 되지만, Play의 강점중 하나는 그러한 서버 재시작을 안하는거다!)

Console에는 아래의 메시지가 나타나고

[info] Compiling 4 Scala sources and 3 Java sources to C:\workspace_spring3\tutorial\target\scala-2.9.1\classes..

--- (RELOAD) ---

[info] play - Application started (Dev)

아래의 기본적은 TODO layer를 확인할 수 있다. 아래페이지는 어떻게 만드냐고 고민하지 말자. 기본적으로 return TODO로 볼수 있고 해당 템플릿은 play-2.0.2\framework\src\play\src\main\scala\views\defaultpages 에 위치한다.


3. 기본 View 

기본 View 파일들은 app/views 폴더에 위치 한다 물론, 자바의 package처럼 폴더를 이용하여 패키징 할수 있다. 기존에 Play Framework가 Groovy를 템플릿언어로 이용하였다면, 2.0에서는 Scala를 완전히 흡수하여, 기본 언어 및 템플릿 언어로 사용한다. 그 이유일까?  suffix는 .scala.html으로 따르면 된다

사용자의 요청에 의해서(GET /)에 의하여 Application.java 의 index() 펑션을 호출하게 되는데  뷰 파일명.redner(arguments) 형식으로 랜더링할 뷰파일을 정할 수 있다.

Eclipse에서 쓰다보면 신기하다. 단순히 Text 파일인데 이클립스의 Java Editor는 코드 어시스트를 계속 지원해준다. 해당 index.scala.html은  target/scala-2.9.1/classes/view/html 으로 컴파일되어서 class 파일로 존재하고 index.class를 확인해보면

C:\workspace_spring3\tutorial\target\scala-2.9.1\classes\views\html>javap index

Compiled from "index.template.scala"

public final class views.html.index extends java.lang.Object{

    public static final views.html.index$ ref();

    public static final scala.Function1 f();

    public static final play.api.templates.Html render(java.lang.String);

    public static final play.api.templates.Html apply(java.lang.String);

    public static final scala.collection.Iterator productElements();

    public static final scala.collection.Iterator productIterator();

    public static final boolean canEqual(java.lang.Object);

    public static final java.lang.Object productElement(int);

    public static final int productArity();

    public static final java.lang.String productPrefix();

    public static final boolean equals(java.lang.Object);

    public static final java.lang.String toString();

    public static final int hashCode();

    public static final play.templates.Format copy$default$1();

    public static final play.templates.BaseScalaTemplate copy(play.templates.Format);

    public static final play.templates.Appendable _display_(java.lang.Object, scala.reflect.Manifest);

    public static final play.templates.Format format();

}

위와 같은 method 들을 확인 할 수 있다. (이제 이러한 것을 천천히 알아가는게 목표다)

index.scala.html 과 main.scala.html

file - index.scala.html

@(message: String)

@main("Welcome to Play 2.0") {

    @play20.welcome(message, style = "Java")

}


file - main.scala.html

@(title: String)(content: Html)

<!DOCTYPE html>

<html>

    <head>

        <title>@title</title>

        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">

        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">

        <script src="@routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>

    </head>

    <body>

        @content

    </body>

</html>



각 1라인은 Action Method의 Parameter를 할당한다. CoC  변명이 아니다. 단순한 스트링뿐 아니라 @(tasks: List[Task], taskForm: Form[Task]) 처럼 Object도 어사인 할 수 있다. 

템플릿언어로서 Scala를 사용하기 때문에 변수명:타입 의 형식을 사용하고 @는 special character로서 많이 사용하게 될것이다.


2라인에는 main 템플릿에 String, Html 의 파라미터를 넘겨준다. 

@play20.welcome이라는 상식스럽지 않은 네이밍은 무시하자. (기본 웹 어플리케이션의 화면 랜더링을 위한 예약어 정도로 생각하면 되겠다 - play-2.0.2\framework\src\play\src\main\scala\views\play20\welcome.html 파일을 보면 내가 거짓말 안하는거 알꺼다)



지금까지 기본적으로 생성되는 Play Framework의 [ Welcome to Play 2. ] 웹어플리케이션을 살펴 보았다.

단순하고 유연하고 빠르게 개발을 할수 있는 Play Framework라는데 벌써 SBT Scala Ivy 좀 있으면 Ebean Akka등이 나온다 제기랄 참 쉽다


다음에는 CRUD나 Dummy Data의 사용등에 대해서 한번 해볼련다.





플레이 프레임워크는 ivy로 디펜던시 관리가 가능하다. (마치 pom.xml 의 dependencies 부분을 Build.scala에서 핸들링 가능하다.)


spring-webmvc를 한번 추가해보도록 하자. Build.scala 에 다음의 한줄을 추가하도록 한다.

...

    val appDependencies = Seq(

      // Add your project dependencies here,

    "org.springframework" % "spring-webmvc" % "3.1.2.RELEASE" 

    )

...

입력 형식  [ "그룹"  % "아티펙트" % "리비전" % ("옵션") ]


이후 play command에서 [update]를 수행하면 된다.

(물론 eclipse에서 사용하는 유저는 [eclipsify with-source=true] 를 한번 더 수행해주면 .classpath 가 업데이트 됨을 확인 할 수 있을 것이다)


*참고#1 repository : http://repo.typesafe.com/typesafe/releases/

*참고#2 Managing library dependencies : http://www.playframework.org/documentation/2.0.2/SBTDependencies

*참고#3 Play 2.0: Akka, Resaat, Json and dependencies : http://www.smartjava.org/content/play-20-akka-rest-json-and-dependencies



티스토리 툴바