Play Framework 1.2 가 새로 릴리즈 되어, 기존에 Play 1.1.1 로 구현이 되어 있는 어플리케이션을 마이그레이션 하려고 하는데, 문제가 발생하였다. 릴리즈 문서에 보면, 레이아웃이 변경된 것이 없기 때문에, 바로 동작 될 것이라는 부분이 있긴 하지만, 역시 문제가 있다. ^^; 문제가 있는 부분은 모델 쪽이었으며, DBMS를 PostgreSQL을 사용하고 동시에 아래와 같이 @Lob 어노테이션을 사용하는 경우에

@Lob
@Column(name = "memo")
public String memo;

아래와 같은 에러 메시지를 보이며 멈추는 현상이 발견되었다. Play 1.1.1 에서는 문제가 없던 것이 1.2에서는 문제가 된 것이다.

JPAQueryException occured : Error while executing query from models.IPGroups order by name asc: Bad value for type long :

이 문제를 해결하려면, 아래의 @Type 어노테이션을 추가해주면 된단다.

@org.hibernate.annotations.Type(type="org.hibernate.type.TextType")

참고 : http://groups.google.com/group/play-framework/browse_thread/thread/3828ace657b9eed5/0db5cf625fc14049?lnk=gst&q=Lob#0db5cf625fc14049

CentOS 5.x 버전이 많은 곳에서 사용되고 있지만, 패키지들이 너무 오래전 것들이라, 실전에 적용하기가 그리 만만치 않다. 이번에는 최신 웹프레임워크로 인기(?)를 끌고 있는 Play Framework를 사용할 수 있는 방법을 기술해보았다. 다른 것은 특별히 문제가 없는데, python 버전 한가지 말썽이다. ^^ 해결책은 간단하니, 한번 보기 바란다. 빨리, CentOS 6.0 이 출시되기만을 바랄뿐이다.

  • 먼저 Play Framework는 Java기반 프레임워크이므로 OpenJDK를 설치한다.
    # yum install java-1.6.0-openjdk java-1.6.0-openjdk-devel
    
  • http://playframework.org에서 play-1.1.1.zip 을 다운로드 받고, 적당한 곳(/opt/play)에 압축을 푼다. 그리고, PATH 환경 변수에 등록한다.
  • Play 의 관리툴은 Python 으로 되어 있는데, 버전 2.5 이상이어야만 한다. 그런데, CentOS 에 설치되어 있는 Python 은 2.4 이다.
  • 두가지 버전의 Python을 사용하기 위해서 이렇게 하자.
    - 기존에 설치된 Python 2.4 는 root 에서, CentOS 관리툴을 위한 것으로 사용하며,
    - 새로 설치할 Python 은 새로운 계정을 만들어서 사용하며, 새로운 계정으로 play 프레임워크 프로젝트를 만들고, 실행하는 데 사용한다.
  • 새로운 계정 play를 만들고, 이 계정으로 로그인 한다. 당연히 /opt/play 디렉토리가 PATH에 등록이 되어 있어야 한다.
  • 새로운 계정 play로 로그인 한 후에, http://python.org 에서 2.5 이상의 원하는 python 소스 파일을 다운로드 하여 적당한 위치에 풀어놓는다.
  • 풀려진 디렉토리에 들어가서 설치를 진행하자. 소스 설치를 진행하려면, 당연히 gcc, make 등은 미리 설치되어 있어야 하겠지?
    $ configure --prefix=/opt/python
    $ make; make install
    
  • 마지막으로 /opt/python 을 PATH의 맨 앞쪽으로 추가시킨다.
  • 이제 명령창에서 play 라고 입력해보자. 다음과 같이 나오면 성공이다. ^^
    $ play
    ~        _            _
    ~  _ __ | | __ _ _  _| |
    ~ | '_ \| |/ _' | || |_|
    ~ |  __/|_|\____|\__ (_)
    ~ |_|            |__/
    ~
    ~ play! 1.1.1, http://www.playframework.org
    ~
    ~ Usage: play cmd [app_path] [--options]
    ~
    ~ with,  new      Create a new application
    ~        run      Run the application in the current shell
    ~        help     Show play help
    ~
    

우리나라에서는 아직 Play Framework 사용자가 거의 없는 듯 하다. 이렇게 좋은 웹프레임워크를 쓰는 사람이 없다니 안타깝다. 최근 간단하게 이것을 이용해서 IP관리 프로그램을 만들었는데, 실제로 만들어보니, Rails 정도까지는 아니지만, 다른 웹프레이워크들(Django, CakePHP 등) 정도로 너무 쉽게 개발이 가능하여 생산성이 아주 좋다는 것을 확인하였다. Play Framework 내부적으로 Hibernate 를 사용하여 DB에 접근을 하고 있다. 각 테이블의 레코드를 구분하기 위하여 id 라는 필드를 사용하고 있는데, Oracle/PostgreSQL 에서는 hibernate_sequence 를 생성하여 모든 테이블에 적용하고 있다. 아무래도 하나의 시퀀스를 이용하기 때문에, 대용량처리/부하 등의 문제가 발생할 수 있을 것이라 판단된다. 이 때문에 각 테이블별로 시퀀스를 생성해서 사용할 수 없는지 방법을 찾아서 아래와 같이 정리하였다. 이 밖에 몇가지 방법이 있는 듯 하나, 복잡하여 일단 쉽게 쓸 수 있는 방법부터 알아보자.

    일반적으로 Play 에서 Model 을 생성할 때 아래와 같이 작성한다.
    package models;
     
    import java.util.*;
    import javax.persistence.*;
    import play.*;
    import play.db.jpa.*;
    import play.data.validation.*;
     
    @Entity
    @Table(name = "users")
    public class Users extends Model {
        public String userid;
        public String password;
        public String name;
    }
    
    그런데, Oracle 이나 PostgreSQL 처럼 Sequence 를 이용하여 id 를 자동증가를 시키면, hibernate_sequence 라는 공통 시퀀스를 모든 테이블에서 사용하게 된다. 상당히 값을 지원하긴 하지만, 대용량 처리에서는 불리하다고 할 수 있다. 테이블당 자신의 시퀀스를 사용하는 것이 일반적이다. 테이블 자신만의 시퀀스를 사용하여 id 컬럼을 사용하려면 아래와 같이 설정한다. 우선, conf/application.conf 에 를 추가한다.
    jpa.dialect=org.hibernate.dialect.PostgreSQLDialect
    
  1. 모델은 아래와 같이 변경한다.
    package models;
     
    import java.util.*;
    import javax.persistence.*;
    import play.*;
    import play.db.jpa.*;
    import play.data.validation.*;
     
    @Entity
    @Table(name = "users")
    public class Users extends GenericModel {
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        public Long id;
     
        public String userid;
        public String password;
        public String name;
    }
    
    Model → GenericModel 로 바뀌었으며, id 필드가 추가되었다.
  2. 이렇게 하고 실행해보면, DB에서 users 라는 테이블과 users_id_seq 라는 시퀀스가 생성된 것을 확인할 수 있다.

원문 : http://www.playframework.org/documentation/1.1/5things

본 문서에서는 Play 프레임워크의 철학을 보여주는 다것가지 예제들을 확인할 수 있다.

HTTP 파라미터와 Java 메소드 파라미터 바인딩

Play로 Java 코드에서 HTTP 파라미터를 가져오는 것은 정말 간단하다. HTTP 파라미터와 같은 이름의 메소드 파라미터를 선언하기만 하면 된다.

예를 들어, 다음과 같은 요청이 있다고 하자:

/articles/archive?date=08/01/08&page=2

Java 메소드 파라미터를 선언함으로써 date 와 page 파라미터를 가져올 수 있다:

public static void archive(Date date, Integer page) {
    List<Article> articles = Articles.fromArchive(date, page);
    render(articles);
}

Play는 메소드 파라미터의 정적 타입을 이용할 것이며, HTTP 값을 Java 객체로 변환할 것이다.

똑똑한 바인딩은 어느 클래스와도 또한 동작한다.

public class Person {
    public String name;
    public Integer age;
}

다음은 Person 객체를 추가하는 아주 단순화한 컨트롤러 액션이다:

public static void add(Person p) {
    p.save();
}

HTML 폼은 합성 이름으로 필드를 정의한다:

<form action="/Directory/add" method="POST">
    Name: <input type="text" name="p.name" />
    Age: <input type="text" name="p.age" />
</form>
상응하는 Java 메소드를 호출함으로써 액션으로 리다이렉트하기

Play 에는 Java 서블릿 forward 에 대응되는 것이 없지만, 다른 액션으로 리다이렉트하는 것은 정말 쉽다. 단지 대응하는 Java 메소드를 호출하는 것으로 HTTP 'Redirect' 응답을 발생시킨다.

public static void show(Long id) {
    Article article = Article.findById(id);
    render(article);
}
 
public static void edit(Long id, String title) {
    Article article = Article.findById(id);
    article.title = title;
    article.save();
    show(id);
}

edit 액션의 마지막에 어떻게 되어 있는지 확인해보기 바란다. show 액션을 호출하여 리다이렉트하고 있다.

어떠한 템플릿에서도 링크를 생성하기 위해서 같은 문법을 사용할 수 있다:

<a href="@{Article.show(article.id)}">${article.title}</a>

이것은 아래와 같은 HTML 을 생성할 것이다 :

<a href="/articles/15">My new article</a>
Java 객체를 템플릿에 전달할 때, 반복하지 마라

대부분 Java 프레임워크에서, Java 객체를 템플릿 시스템에 전달할때, 다음과 같은 것들을 작성할 필요가 있다:

Article article = Article.findById(id);
User user = User.getConnected();
Map<String, Object> model = new HashMap<String,Object>();
model.put("article", article);
model.put("user", user);
render(model);

Play에서는 단지 아래와 같이 간단히 작성하기만 하면된다:

Article article = Article.findById(id);
User user = User.getConnected();
render(article, user);

그리고, 템플릿에서는 Java 로컬이름으로부터 객체를 가져온다. 이런 것들이 많은 필요없는 코드들을 줄여준다.

스테로이드 주입한 JPA

JPA는 Java 환경에서 확실하게 가장 좋은 객체-관계 매핑 (ORM) API 이다. 만약 당신이 벌써 알고 있다면, 당신은 Play와 함께하면서 얼마나 더욱 간단하게 되었는지 놀라게 될 것이다. 설정할 것 없이, Play는 자동으로 JPA 엔티니 매니저를 시작하고 코드가 리로드 되는 동안에 마술적으로 동기화한다.

게다가, 당신이 제공되는 play.db.jpa.Model 수퍼클래스를 사용한다면, 그것은 더욱 당신의 코드를 예쁘게 만들어줄 것이다:

public void messages(int page) {
    User connectedUser = User.find("byEmail", connected()).first();
    List<Message> messages = Message.find(
        "user = ? and read = false order by date desc",
        connectedUser
    ).from(page * 10).fetch(10);
    render(connectedUser, messages);
}
직관적인 파일 업로드 관리

Play에서 파일 업로드 관리는 매우 간단하다.

HTML 폼:

<form action="@{Article.uploadPhoto()}" method="POST" enctype="multipart/form-data">
    <input type="text" name="title" />
    <input type="file" id="photo" name="photo" />
    <input type="submit" value="Send it..." />
</form>

그리고 Java 코드는:

public static void uploadPhoto(String title, File photo) {
   ...
}

이것보다 쉬울 수 있을까?

+ Recent posts