下面的简单例子借鉴了Java EE 5 tutorial中的例子,目的是看一看JPA(Java Persistence API)在WEB中的开发形式.例子中是在HTML中输入一个书籍ID,通过它来查询书籍的名字显示在页面上。
1.环境配置
1.1 JDK 5.0. 下载: http://java.sun.com/j2se/1.5.0/download.jsp
1.2 Java EE 5.0 App Server: 下载: https://glassfish.dev.java.net/public/downloadsindex.html
并且把install root设为$GLASSFISH_HOME.
启动App Server的命令是:
$GLASSFISH_HOME/bin/asadmin.bat start-domain
Glassfish App Server捆绑了一个数据库叫Derby,启动的命令是:
$GLASSFISH_HOME/bin/asadmin.bat start-database
2.编写服务端文件
2.1 在数据库中创建数据
CREATE TABLE WEB_BOOKSTORE_BOOKS
(bookId VARCHAR(8),
surname VARCHAR(24),
firstName VARCHAR(24),
title VARCHAR(96),
price FLOAT,
onSale SMALLINT,
calendar_year INT,
description VARCHAR(30),
inventory INT);
INSERT INTO WEB_BOOKSTORE_BOOKS VALUES('201', 'Duke', '',
'My Early Years: Growing up on *7',
30.75, 0, 1995, 'What a cool book.', 20);
INSERT INTO WEB_BOOKSTORE_BOOKS VALUES('202', 'Jeeves', '',
'Web Servers for Fun and Profit', 40.75, 1,
2000, 'What a cool book.', 20);
INSERT INTO WEB_BOOKSTORE_BOOKS VALUES('203', 'Masterson', 'Webster',
'Web Components for Web Developers',
27.75, 0, 2000, 'What a cool book.', 20);
INSERT INTO WEB_BOOKSTORE_BOOKS VALUES('205', 'Novation', 'Kevin',
'From Oak to Java: The Revolution of a Language',
10.75, 1, 1998, 'What a cool book.', 20);
INSERT INTO WEB_BOOKSTORE_BOOKS VALUES('206', 'Gosling', 'James',
'Java Intermediate Bytecodes', 30.95, 1,
2000, 'What a cool book.', 20);
打开Derby数据库的对话窗,
$GLASSFISH_HOME/javadb/frameworks/NetworkServer/bin/ij.bat
创建一个叫bookstoredb数据库,然后创建表格.
ij> connect 'jdbc:derby://localhost:1527/bookstoredb;create=true';
ij> run 'bookstore.sql';
2.2 Entity类
Entity类实际上是一个JavaBean,它表示了一个数据库中的表.下面的Book类对应了表"TABLE WEB_BOOKSTORE_BOOKS".类中使用了以下3个annotation.
@Entity: 指定这个类为Entity.
@Table : 指定mapping的表.
@Id : 指定表中的主键.
package database;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "WEB_BOOKSTORE_BOOKS")
public class Book implements Serializable {
private String bookId;
private String description;
private String firstName;
private String surname;
private String title;
private boolean onSale;
private float price;
private int calendar_year;
private int inventory;
public Book() {
}
public Book(
String bookId,
String surname,
String firstName,
String title,
float price,
boolean onSale,
int calendar_year,
String description,
int inventory) {
this.bookId = bookId;
this.title = title;
this.firstName = firstName;
this.surname = surname;
this.price = price;
this.onSale = onSale;
this.calendar_year = calendar_year;
this.description = description;
this.inventory = inventory;
}
@Id
public String getBookId() {
return this.bookId;
}
public String getTitle() {
return this.title;
}
public String getFirstName() {
return this.firstName;
}
public String getSurname() {
return this.surname;
}
public float getPrice() {
return this.price;
}
public boolean getOnSale() {
return this.onSale;
}
public int getCalendar_year() {
return this.calendar_year;
}
public String getDescription() {
return this.description;
}
public int getInventory() {
return this.inventory;
}
public void setBookId(String id) {
this.bookId = id;
}
public void setTitle(String title) {
this.title = title;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setSurname(String surname) {
this.surname = surname;
}
public void setPrice(float price) {
this.price = price;
}
public void setOnSale(boolean onSale) {
this.onSale = onSale;
}
public void setCalendar_year(int calendar_year) {
this.calendar_year = calendar_year;
}
public void setDescription(String description) {
this.description = description;
}
public void setInventory(int inventory) {
this.inventory = inventory;
}
}
2.3 数据库操作类
这个类提供了对数据库操作的方法,实际上是通过EntityManager类中的方法进行操作的.而EntityManager类是由EntityManagerFactory生成的.
package database;
import java.util.*;
import javax.persistence.*;
import database.Book;
import exception.BookNotFoundException;
public class BookDBAO {
private ArrayList books;
private EntityManager em;
public BookDBAO(EntityManagerFactory emf) throws Exception {
em = emf.createEntityManager();
}
public void remove() {
try {
em.close();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
public Book getBook(String bookId) throws BookNotFoundException {
Book requestedBook = em.find(Book.class, bookId);
if(requestedBook == null) {
throw new BookNotFoundException("Couldn't find book: " + bookId);
}
return requestedBook;
}
}
2.4 BookNotFoundException类
BookDBAO.java中所使用的类.
package exception;
public class BookNotFoundException extends Exception {
public BookNotFoundException() {
}
public BookNotFoundException(String msg) {
super(msg);
}
}
2.5 Servlet类
在这个类中由container注入一个EntityManagerFactory并且把它传递给BookDBAO类.注意EntityManagerFactory 的注入需要在由容器管理的实体中进行(比如Servlet).
package servlets;
import java.io.PrintWriter;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import database.Book;
import database.BookDBAO;
import exception.BookNotFoundException;
public class BookStoreServlet extends HttpServlet {
private BookDBAO bookDBAO;
@PersistenceUnit
private EntityManagerFactory emf;
public void init() throws ServletException {
try{
bookDBAO = new BookDBAO(emf);
}catch(Exception ex){
System.out.println("Couldn't create bookstore database bean: "
+ ex.getMessage());
}
if (bookDBAO == null) {
throw new UnavailableException("Couldn't get database.");
}
}
public void destroy() {
bookDBAO = null;
}
public void doGet(
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//set content-type header before accessing the Writer
response.setContentType("text/html");
response.setBufferSize(8192);
PrintWriter out = response.getWriter();
String bookId = request.getParameter("bookid");
try {
Book bd = bookDBAO.getBook(bookId);
out.println(bookId+": "+ bd.getTitle());
}catch(BookNotFoundException bnf){
out.println("The book not found.");
}catch(Exception e){
e.printStackTrace();
}
out.close();
}
}
2.6 web.xml
部署时的文件.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>BookStoreServlet</servlet-name>
<servlet-class>servlets.BookStoreServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BookStoreServlet</servlet-name>
<url-pattern>/bookstore</url-pattern>
</servlet-mapping>
</web-app>
2.7 persistence.xml
用描述文件persistence.xml来定义persistence unit.打包做成WAR文件,可以把它放在WEB-INF/classes/META-INF之下.在这使用了Glassfish预先定义好了的DataSource--jdbc/__default.
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name ="bookstore">
<jta-data-source>jdbc/__default</jta-data-source>
</persistence-unit>
</persistence>
3.客户端的HTML文件
<html>
<head>
<title>JPA in Web example</title>
</head>
<body>
<form action="bookstore" method="GET">
BookId: <input type="text" name="bookid"> <br/>
Search: <input type="submit" value="submit">
</form>
</body>
</html>
4.编译,部署,运行.
$ javac -classpath .\;$GLASSFISH_HOME/lib/javaee.jar servlets/BookStoreServlet.java
编译好文件,按照WEB格式打成WAR包,把这个包直接拷贝到$GLASSFISH_HOME/domains/domain1/autodeploy下,这样就可以测试了.
BookId:Search:
输入206,会看到如下反馈.
206: Java Intermediate Bytecodes
通过调用EntityManager的一些其他方法,还可以进行对数据库的其他操作.
5.其他
数据库停止命令,
$GLASSFISH_HOME/bin/asadmin.bat stop-database
服务器停止命令,
$GLASSFISH_HOME/bin/asadmin.bat stop-domain