JavaEE 6 をテキストエディタだけで(3) - JPA編


前回作成したEJBJPAによるDB操作を組み込む

DBサーバの起動

glassfish 同梱の Derby を使う。glassfish の asadmin コマンドで

asadmin start-database

とすることで Derby が起動する。DBは以下のフォルダに sun-appserv-samples という名前で作成される
\glassfish\databases

glassfish の管理コンソールで見るとJDBCリソースができてる


POM の編集

pom に JPA の依存関係を定義

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>javax.persistence</artifactId>
    <version>2.0.0</version>
    <scope>provided</scope>
</dependency>


pom は今までのものと合わせて以下

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>etc9</groupId>
    <artifactId>webapp001</artifactId>
    <version>0.1</version>
    <packaging>war</packaging>

    <name>webapp001</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>javax.ejb</artifactId>
            <version>3.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

persistence.xml の作成

src/main/resources/META-INF に persistence.xml を作成

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
             xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="webapp001PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/__default</jta-data-source> <!-- Glassfish Default Datasource -->
        <class>etc9.domain.Book</class>
        <properties>
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
            <property name="eclipselink.logging.level" value="INFO"/>
        </properties>
    </persistence-unit>
</persistence>
  • persistence-unit の名前に webapp001PU を定義して、JPAプロバイダには eclipselink を指定
  • jta-data-source には先程起動した Derby のデフォルトデータソース名を指定
  • Entity の対象として後で作成する Book を指定
  • eclipselink 固有のオプションにてテーブルの自動再作成を指定


etc9.domain.Book の指定は以下のようにすることで、クラスを個別に指定しなくても良くなる

<exclude-unlisted-classes>false</exclude-unlisted-classes>

Bookエンティテイの作成

package etc9.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Book implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private Long id;
    private String title;
    private String description;
    
    @Id @GeneratedValue
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    @Column(nullable = false)
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    
    @Column(length = 1000)
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public String toString() {
        return getClass().getSimpleName() + 
                "[" + getId() + ", " + getTitle() + ", " + getDescription() + "]";
    }
}
  • @Entity にてエンティティ指定
  • その他必要に応じてプロパティにアノテーションを付与

EntityManager からのエンティテイ操作

簡単のために EJB に直接 SELECT と INSERT 用のメソッドを作成する。
インターフェースを以下

package etc9.service;

import java.util.List;
import etc9.domain.Book;

public interface BookService {
    List<Book> findAll();
    Book create(Book book);
}


インターフェースを EJB で実装

package etc9.service;

import java.util.List;

import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import etc9.domain.Book;

@Stateless @Local(BookService.class)
public class BookServiceImpl implements BookService {
    
    @PersistenceContext(unitName = "webapp001PU")
    private EntityManager em;

    @Override
    public List<Book> findAll() {
        TypedQuery<Book> query = em.createQuery("SELECT b from Book b", Book.class);
        return query.getResultList();
    }

    @Override
    public Book create(Book book) {
        em.persist(book);
        return book;
    }
}
  • @PersistenceContext にて persistence.xm で指定したユニット名を指定して EntityManager を DI

サーブレットの追加

とりあえず、WebServlet として検索用と登録用のサーブレットを作成(あとでJSFに変える)

@WebServlet(urlPatterns={"/book/find"})
public class BookFindServlet extends HttpServlet {

    @EJB 
    private BookService bookService;
    
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        PrintWriter pw = res.getWriter();  
        pw.println("<h1>Book List</h1><br>");
        List<Book> books = bookService.findAll();
        for (Book b : books) {
            pw.println(b.toString() + "<br>");
        }
    }
}


DB に固定的にレコード入れるサーブレットを作成

@WebServlet(urlPatterns={"/book/create"})
public class BookCreateServlet extends HttpServlet {
    
    @EJB
    private BookService bookService;
    
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        Book book = new Book();
        book.setTitle("Learning Perl");
        book.setDescription("3rd Edition");
        book = bookService.create(book);
        
        PrintWriter pw = res.getWriter();  
        pw.println(book.toString());
    }
    
}

デプロイと実行

前回までと同じでデプロイ

mvn package
asadmin undeploy webapp001-0.1.war
asadmin deploy target/webapp001-0.1.war

http://localhost:8080/webapp001-0.1/book/find にアクセス。まだ登録されていない

http://localhost:8080/webapp001-0.1/book/create にアクセス。

http://localhost:8080/webapp001-0.1/book/find にアクセス。DB に登録されている



DBには \javadb\bin にある ij を使うと見れる

ij
ij> connect 'jdbc:derby://localhost:1527/sun-appserv-samples';
ij> show tables
ij> describe book;


次回は、適当に作ったサーブレットJSF に変更する