位于上海,服务全国!

位于上海,服务全国!

将ObjectDB集成到基于JPA的Java Web App中

作者:admin 分类: 时间:2017-03-15 11:58:54 点击量:2213

在本文中,你将了解如何将ObjectDB集成到基于Java Persistence API(JPA)及NetBeans的Java Web应用程序中。 如果这是你第一次听说ObjectDB,它是使用JPA的Java应用程序对象数据库。 ObjectDB网站声称,该产品“比其他JPA / DBMS解决方案快10倍。” 但是,正如你将看到的,ObjectDB有许多其他属性,使其成为Java桌面或Web应用程序的数据库层的绝佳选择。 它易于配置和使用,非常强大,并且不需要JDBC,驱动程序或第三方应用程序。 ObjectDB实际上是一个强大的数据库,且在一个产品中具有完全的JPA支持。

在本文末尾,你将能够通过NetBeans将ObjectDB下载并配置为基于JPA的Web应用程序。

下载和配置ObjectDB
首先从ObjectDB.com下载ObjectDB。我使用ObjectDB版本2.3.7作为一个ZIP存档。 下载后,将归档内容提取到你最喜欢的地方。 根据你阅读本文的时间,你可能需要下载最新版本。

ObjectDB包含一套用于一般功能,日志记录,数据库管理,实体管理,模式更新,服务器配置,服务器用户列表和SSL的可配置参数。 显然,所有这些参数都有默认值,你不需要自定义每个参数。 为了快速查看,你可以在ObjectDB根文件夹下的objectdb.txt文件中查看它们。 每个部分由一个建议的XML标签所限定,并包含几个参数。

最常修改的参数可能是服务器配置部分下的<data>元素,它由<server>元素标记。 <data>元素有一个属性path,它指定服务器管理的ObjectDB数据库的位置。 $objectdb的值>(ObjectDB主目录)派生自objectdb.jar文件的位置。 它被定义为objectdb.jar所在的目录路径,有一个例外 - 如果该目录的名称是/ bin,/ lib或/ build,则父目录被认为是ObjectDB主目录($ objectdb>)。 你还可以通过设置“objectdb.home”系统属性来显式定义$ objectdb>:


System.setProperty("objectdb.home", "/mydatabase/odb");

标注: 除了ObjectDB之外,还需要Java 1.6 / 1.7和NetBeans IDE,最好是附带GlassFish v3的最新版本。

将ObjectDB放入NetBeans / JPA应用程序
在本节中,你将开发一个NetBeans/JPA/ObjectDB Web演示应用程序。 这个应用程序将在网站主页上提供一组ATP网球选手,并且将提供一种形式,其可用于将更多的玩家记录到ObjectDB数据库中。

创建一个新的Java Web应用程序框架

你以NetBeans样式创建一个新的Java Web应用程序框架。 这可以通过以下步骤完成:

启动NetBeans IDE。
从文件主菜单中,选择新建项目。
在“新建项目”向导中,从“类别”面板中选择“Java Web”,然后从“项目”面板中选择“Web应用程序”。 点击下一步。


图1.创建一个新的Web应用程序,步骤3

在此步骤中,将项目名称添加为atpPlayers并选择项目位置。 点击下一步。


图2.创建一个新的Web应用程序,步骤4

接下来,选择GlassFishServer 3作为应用程序的服务器,并选择Java EE 6 Web作为Java EE版本。 单击“完成”。

图3.创建一个新的Web应用程序,步骤5

在几秒钟后,将生成一个全新的空项目,并显示在“项目”选项卡下。

为项目添加ObjectDB / JPA支持
现在是添加任何业务逻辑之前,添加ObjectDB / JPA支持的好时机:

为此,在Projects选项卡下,展开主atpPlayers项目节点并本地化Libraries节点。
右键单击它,然后从上下文菜单中选择添加JAR /文件夹。
导航到ObjectDB文件夹/ bin,然后选择objectdb.jar存档。

图4. 增加ObjectDB/JPA支持

完成! 非常简单及快速! ObjectDB已设置,现在可以开始开发应用程序。

创建一个实体类
要使用JPA在一个ObjectDB数据库中存储对象,我们需要定义一个实体类。 这个简单的步骤可以通过NetBeans帮助完成:

在atpPlayers项目节点下,本地化源包节点。
右键单击此节点,并且选择新建|上下文菜单中的实体类。 如果实体类不存在,请选择其他,并且在类别下选择持久性。 在右侧选项卡中,你将看到实体类选项。
在实体类向导中,键入Player作为实体类名称,并键入ATP包。 点击下一步。


图5.创建一个实体类

接下来,只需单击生成实体类的完成按钮和具有默认持久性单元(将稍后配置)的persistence.xml文件。
现在,应该生成实体类Player.java并自动打开以进行编辑。 只需删除生成的内容并粘贴以下内容:


package ATP;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Player implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private int ranking;
  private String img;
  private String name;
  private String country;
  private int points;
  
  public Player(){    
  }


  public Player(String name, String country, int ranking, int points, String img) {
    this.ranking = ranking;
    this.img = img;
    this.name = name;
    this.country = country;
    this.points = points;
  }

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }


  public String getCountry() {
    return country;
  }


  public void setCountry(String country) {
    this.country = country;
  }


  public String getName() {
    return name;
  }


  public void setName(String name) {
    this.name = name;
  }


  public String getImg() {
    return img;
  }


  public void setImg(String img) {
    this.img = img;
  }


  public int getRanking() {
    return ranking;
  }


  public void setRanking(int ranking) {
    this.ranking = ranking;
  }


  public int getPoints() {
    return points;
  }


  public void setPoints(int points) {
    this.points = points;
  }


  @Override
  public int hashCode() {
    int hash = 0;
    hash += (id != null ? id.hashCode() : 0);
    return hash;
  }


  @Override
  public boolean equals(Object object) {
    // TODO: Warning - this method won't work in the case the id fields are not set
    if (!(object instanceof Player)) {
      return false;
    }
    Player other = (Player) object;
    if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
      return false;
    }
    return true;
  }


  @Override
  public String toString() {
    return "ATP.Player[id=" + id + "]";
  }
}
正如你可以看到,实体类映射播放器属性,如名称,国家,点数,排名和照片链接。 这些属性表示将在atp.odb数据库中命名为Player的表数据库列。

根据ObjectDB定义持久性单元
如果在“配置文件”节点下查看,你会注意到NetBeans已生成默认持久性单元。 在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="atpPlayersPU" transaction-type="JTA">
  <provider>com.objectdb.jpa.Provider</provider>
  <properties>
   <property name="javax.persistence.jdbc.url" value="$objectdb/db/atp.odb"/>
   <property name="javax.persistence.jdbc.user" value="admin"/>
   <property name="javax.persistence.jdbc.password" value="admin"/>
  </properties>
 </persistence-unit>


</persistence>
你应该获得类似于下面图6的内容。

图6.持久化单元


开发一个EJB会话Bean
现在是为我们的应用程序添加一些业务逻辑的时候了。 从将放入EJB会话bean的数据库操作开始。  开始生成一个空的EJB会话bean,如下所示:

在项目主节点下,右键单击源软件包并选择新建|会话Bean。 如果会话Bean不存在,请选择其他,并且在类别下选择J2EE。 在右侧选项卡中,你将看到会话Bean选项。
在“新建会话Bean”向导中,键入“atpDAO”作为会话bean名称,然后按完成。
现在,生成的无状态bean代码应该被下面的代码替换。 我们有一个方法来将数据保存到数据库中,名为persist(),一个用于从数据库获取名为getAllPlayers()的所有记录:

package ATP;


import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;


@Stateless
public class atpDAO {
  
  // Injected database connection:
  @PersistenceContext private EntityManager em;


  // Stores a new player
  public void persist(Player player) {
    em.persist(player);
  }


  // Retrieves all the players
  public List<Player> getAllPlayers() {
    TypedQuery<Player> query = em.createQuery("SELECT p FROM Player p ORDER BY p.id", Player.class);
    return query.getResultList();
  }
 
}


使用这种方法有多个优点,因为应用程序服务器将管理EJB类的实例化并将EJB类的实例注入到Servlet中(请参见下一部分),自动准备EntityManager并将其注入em字段(因为它是使用@PersistenceContext注释注释),并使用JTA自动处理事务。 没有必要使用事务begin和commit来包装修改数据库的每个操作。 为此,你需要一个支持EJB的应用程序服务器,例如GlassFish或JBoss,而不是Servlet容器,例如Tomcat和Jetty。 我在GlassFish v3上测试了它,它与NetBeans IDE捆绑在一起。
开发一个Servlet类来管理HTTP请求

接下来,你需要一个组件来处理Web请求并与EJB组件进行通信。 在这种情况下,Servlet可以是一个好的选择。 要创建一个,你需要遵循以下步骤:

在项目主节点下,右键单击源软件包并选择新建| Servlet。如果Servlet不存在,然后选择其他,并在类别下选择Web。在右侧选项卡中,你将看到Servlet选项。
在New Servlet向导中,键入“atpServlet”作为Servlet名称,并将ATP作为包。 单击“完成”。

图7.创建一个 New Servlet


现在,Servlet内容必须替换为以下内容:

package ATP;

import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet(name = "atpServlet", urlPatterns = {"/atpServlet"})
public class atpServlet extends HttpServlet {


  // Injected DAO EJB
  @EJB
  atpDAO ejbDao;


  /** 
   * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
   * @param request servlet request
   * @param response servlet response
   * @throws ServletException if a servlet-specific error occurs
   * @throws IOException if an I/O error occurs
   */
  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {


      String name = request.getParameter("name");
      String country = request.getParameter("country");
      String sranking = request.getParameter("ranking");
      String spoints = request.getParameter("points");
      String photo = request.getParameter("photo");


      if ((name != null) && (country != null) && (sranking != null) && (spoints != null) && (photo != null)) {
        int ranking = Integer.valueOf(sranking);
        int points = Integer.valueOf(spoints);
        ejbDao.persist(new Player(name, country, ranking, points, photo));
      }


      // Display the list of guests:
      request.setAttribute("players", ejbDao.getAllPlayers());
      request.getRequestDispatcher("/atp.jsp").forward(request, response);
    } finally {
      out.close();
    }
  }


  // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
  /** 
   * Handles the HTTP <code>GET</code> method.
   * @param request servlet request
   * @param response servlet response
   * @throws ServletException if a servlet-specific error occurs
   * @throws IOException if an I/O error occurs
   */
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }


  /** 
   * Handles the HTTP <code>POST</code> method.
   * @param request servlet request
   * @param response servlet response
   * @throws ServletException if a servlet-specific error occurs
   * @throws IOException if an I/O error occurs
   */
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }


  /** 
   * Returns a short description of the servlet.
   * @return a String containing servlet description
   */
  @Override
  public String getServletInfo() {
    return "Short description";
  }// </editor-fold>
}


注意,数据库操作由atpDao会话bean执行,它由应用程序服务器自动实例化并注入到ejbDao字段中,因为该字段标有@EJB注释。 现在,当你的Servlet接收到HTTP请求时,它会检查这是否是把新的ATP播放器存储到ObjectDB数据库的请求。 如果设置了播放器的参数,那么将调用EJB业务方法persist()方法来存储新播放器。 之后,Servlet调用EJB getAllPlayers()业务方法,并将控制转发到呈现ATP播放器的JSP页面,你可以在下一部分中看到。 如果插入了一个新的播放器,它将由JSP显示。
开发输出渲染的JSP页面
Web应用程序的最后组件是一个在屏幕上呈现ATP播放器的JSP页面。 为此,你需要按照以下步骤操作:

在项目主节点下,右键单击网页,然后选择新建| JSP。 如果JSP不存在,请选择其他,然后在类别下选择Web。 在右侧选项卡中,你将看到JSP选项。键入atp作为JSP名称,然后按完成。

图8.创建一个新的JSP页面

接下来,将默认生成的代码替换为以下代码:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page import="java.util.*,ATP.Player"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">


<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>ATP Men's Rankings</title>
  </head>
  <body>
    <table align="center">
      <tr>        
        <%
         List<Player> players = (List<Player>) request.getAttribute("players");
         if (players != null) {
          for (Player player : players) {
        %>
        <td>
          <table>
            <tr>
              <td rowspan="5">
                <img src="images/<%= player.getImg()%>" alt="">
              </td>
            </tr>
            <tr>
              <td>
                Ranking:<b> <%= player.getRanking()%> </b>
              </td>
            </tr>
            <tr>
              <td>
                ATP points:<b> <%= player.getPoints()%> </b>
              </td>
            </tr>
            <tr>
              <td>
                Name:<b> <%= player.getName()%> </b>
              </td>
            </tr>
            <tr>
              <td>
                Country:<b> <%= player.getCountry()%> </b>
              </td>
            </tr>
          </table>
        </td>
        <%
         }
        %>
        <%
         }
        %>
      </tr>
    </table>
    <form method="POST" action="atpServlet">
      <table align="center">
        <tr>
          <td colspan="2">
            Insert a new player:
          </td>
        </tr>
        <tr>
          <td>
            Name:
          </td>
          <td>
            <input type="text" name="name" />
          </td>
        </tr>
        <tr>
          <td>
            Country:
          </td>
          <td>
            <input type="text" name="country" />
          </td>
        </tr>
        <tr>
          <td>
            Ranking:
          </td>
          <td>
            <input type="text" name="ranking" />
          </td>
        </tr>
        <tr>
          <td>
            Points:
          </td>
          <td>
            <input type="text" name="points" />
          </td>
        </tr>
        <tr>
          <td>
            Photo:
          </td>
          <td>
            <input type="text" name="photo" />
          </td>
        </tr>
        <tr>
          <td colspan="2">
            <input type="submit" value="Add" />
          </td>
        </tr>
      </table>
    </form>
  </body>
</html>
在Web浏览器窗口的顶部,JSP从数据库呈现当前播放器。 在底部,它呈现用于存储新玩家的形式。 当你储存一个新的播放器时,你需要指定代表播放器照片的图像文件的名称。 通常,应该上传该照片,但由于这里不相关,你可以使用手动存储它们的/ images文件夹中的照片。

最后应该进行的一个调整 - 在网页节点下,你有应用程序起始页,被称为index.jsp。只需编辑它并添加一个转发到你的Servlet,如下所示:

 ...
<body>
    <jsp:forward page="atpServlet" />
</body>
...
运行应用程序
运行应用程序非常简单! 确保atpPlayers是主项目,并从NetBeans工具栏中单击大的绿色“运行”按钮,或按F6。 在GlassFish启动并成功部署应用程序后,浏览器应自动打开。 在图9和10中,你可以看到应用程序的两个屏幕截图。

浏览ObjectDB数据库
你可以使用ObjectDB位置中的 bin文件夹内的ObjectDB Explorer工具(如explorer.exe)浏览ObjectDB数据库。双击它以启动应用程序,并导航到atp.odb数据库。 如果你使用与本文中相同的路径,则atp.odb位于D:\ app \ atpPlayers \ build \ web \ WEB-INF \ db文件夹中。 在图11中,你可以看到我如何浏览它:


图11.使用ObjectDB Explorer工具浏览atp.odb

你可以在ObjectDB.com上找到有关ObjectDB工具的更多信息。

总结
在本文中,你已经学习了如何开发一款基于ObjectDB和JPA的Web应用程序。 你已了解如何下载和配置ObjectDB,如何查询ObjectDB数据库以及如何使用ObjectDB工具浏览数据库内容。