`
jerryqiu007
  • 浏览: 232429 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用 Apache Derby 构建脱机 Ajax

阅读更多

人们非常喜爱 Ajax 应用程序,以至于他们十分乐于使用 Ajax 应用程序而不想使用等效的桌面程序。但惟一的问题是出现在网络无法访问的时候怎么办。这是必须要用脱机功能的场景。Apache Derby 是支持 Ajax 应用程序实现脱机访问的优秀选择。了解如何使用 Apache Derby 作为本地数据库,该数据库可以实现 Ajax 应用程序的脱机使用。

 

Apache Derby

Apache Derby 是任何一个 Java 应用程序都可以使用的嵌入式数据库。它是非常有用的工具,因此绑定在 Java Platform, Standard Edition (Java SE) V6 中。虽然嵌入式数据库的应用不计其数,但是许多人都不知道用 Derby 可以实现的一些客户端功能。我们将通过构建一个简单的地址本应用程序研究其中一些应用。我们将从利用 Apache Derby 的 Java Applet 开始,最终实现一个使用 Derby 作为缓存的基于 Ajax 的应用程序。

 

数据访问

对于一篇有关数据库技术的文章,应当首先从数据库代码开始讨论。首先,让我们定义用于存储联系人的简单的表模式,如下所示:

 

您可以设想更复杂的联系人模式,如添加多个电话号码、地址等。但是,对于我们的应用程序来说,使用目前的这种模式刚刚好。当然,存在一个与 Contact 表相对应的 Java 类。在本例中,我们将遵循 Active Record 模式并用能够执行所有数据库操作的类封装数据库行。其代码如下所示:

public class Contact {
    
    private Integer id;
    private String firstName;
    private String lastName;
    private String email;
    
    public static List<Contact> getContacts(String clause){
        if (clause == null)
            clause = "";
        String sql = SELECT_SQL + clause;
        Connection conn = DbManager.getConnection();
        List<Contact> contacts = new ArrayList<Contact>();
        try {
            ResultSet cursor = conn.createStatement().executeQuery(sql);
            while (cursor.next()){
                Contact c = new Contact();
                c.setId(cursor.getInt(1));
                c.setFirstName(cursor.getString(2));
                c.setLastName(cursor.getString(3));
                c.setEmail(cursor.getString(4));
                contacts.add(c);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return contacts;
    }
    
    public static List<Contact> getAllContacts(){
        return Contact.getContacts(null);
    }
    
    public static Contact getContact(String clause){
        List<Contact> results = Contact.getContacts(clause);
        if (results == null || results.size() != 1){
            return null;
        }
        else return results.get(0);    
    }
    
    public void save(){
        if (id == null)
            insert();
        else
            update();
    }
    
    public void delete(){
        Connection conn = DbManager.getConnection();
        String sql = "delete from Contact where id=?";
        try{
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setInt(1, id);
            ps.executeUpdate();
            System.out.println("Deleted contact id="+id);
        } catch (SQLException e){
            e.printStackTrace();
        }
    }
    
    private void insert() {
        Connection conn = DbManager.getConnection();
        try {
            PreparedStatement ps = conn.prepareStatement(INSERT_SQL, 
                    PreparedStatement.RETURN_GENERATED_KEYS);
            ps.setString(1, firstName);
            ps.setString(2, lastName);
            ps.setString(3, email);
            ps.executeUpdate();
            ResultSet autoRs = ps.getGeneratedKeys();
            if (autoRs.next()){
                id = autoRs.getInt(1);
            }
            System.out.println("Contact saved new id = " + id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    private void update(){
        Connection conn = DbManager.getConnection();
        try{
            PreparedStatement ps = conn.prepareStatement(UPDATE_SQL);
            ps.setString(1, firstName);
            ps.setString(2, lastName);
            ps.setString(3, email);
            ps.setInt(4, id);
            ps.executeUpdate();
            System.out.println("Contact updated with id="+id);
        } catch (SQLException e){
            e.printStackTrace();
        }
    }

 

该类将完成很多任务,但是所有内容都非常简单。它有与数据库列对应的字段及用于每个字段的常用存取器(getter 和 setter)。它拥有执行所有创建/更新/删除(CReate Update Delete,CRUD)操作及其附带 SQL 查询的方法。例如,查询联系人的方法是静态方法,因此可以执行类似 Contact.getAllContacts() 的操作。保存和删除操作是实例方法,因此对个别联系人调用这些方法。此处没有显示查询,因为查询是标准的 SQL。该类还有常用的 getter 和 setter,但是为了简短起见并未显示。该类将用 Derby 构造基本的客户端存储。首先,我们将使用它作为 Applet UI 的一部分,但是稍后该 Applet 将把它用于 JavaScript。注意,对于每个方法,我们将调用实用程序类 DbManager 以获得连接。

 

package org.developerworks.addressbook;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DbManager {
	static {
		try {
			Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection(){
        try {
            Connection conn = DriverManager.getConnection("jdbc:derby:contacts;create=true");
            return conn;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

这是所有特定于 Derby 的代码所在的位置。实际上,并不是特别特定于 Derby。我们使用的是嵌入式数据库,但是我们处理它的方式和通过 JDBC 访问的其他数据库一样。我们将在类的静态初始化器中把 EmbeddedDriver 用于驱动程序类。另外对于 getConnection 方法,我们将添加额外的参数 create=true 来告诉 Derby 在数据库尚不存在时创建数据库。注意,不需要像使用 JDBC 那样用到用户名或密码 — 这是使用嵌入式数据库的优点之一。您看到了所有的数据访问代码。它看起来非常类似于在任何一个应用程序中都可以看到的数据库代码;而数据库刚好是嵌入式 Derby 数据库。您可以设想为应用程序创建其他模型,这样可以存储专用于应用程序的数据,但是位于客户端。让我们查看一个利用清单 2 中所示的数据访问代码的简单应用程序。

 

Applet UI

首先使用一个非常简单的 Applet,该 Applet 将使用数据访问代码。

public class AddressBookApplet extends JApplet {
    private static final long serialVersionUID = 1L;    
    private static final String[] columns = { "First Name", "Last Name", "Email", "Id"};
    
    public AddressBookApplet() {
        this.setLayout(new GridLayout(1,0));
        JPanel panel = buildUi();
        this.add(panel);
    }

    public Contact addContact(String firstName, String lastName, String email) {
        Contact c = new Contact();
        c.setFirstName(firstName);
        c.setLastName(lastName);
        c.setEmail(email);
        c.save();
        return c;
    }
    
    public void deleteContact(Integer id){
        Contact c= new Contact();
        c.setId(id);
        c.delete();
    }

    public Object[][] loadContacts() {
        List<Contact> book = Contact.getAllContacts();
        Object[][] contacts = new Object[book.size()][4];
        int cnt = 0;
        for (Contact contact : book){
            contacts[cnt++] = contact.toArray();
        }
        return contacts;
    }

    private JPanel buildUi() {
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        
        final DefaultTableModel dataModel = createDataModel();
        final JTable table = createTable(dataModel);
        
        //Lots of Swing/UI Code omitted for brevity    
      }
    
    private JTable createTable(final DefaultTableModel dataModel) {
        final JTable table = new JTable(dataModel);
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);
        return table;
    }

    private DefaultTableModel createDataModel() {
        Object[][] contacts = loadContacts();
        final DefaultTableModel dataModel = new DefaultTableModel(contacts, columns);
        return dataModel;
    }
}

 

这段代码大部分是构建 UI 的典型 Swing 代码。所有 UI 代码都是在位于类底部的私有方法中完成的。buildUi 方法处理 Swing 组件的创建,但是为了简短起见而省略了大部分内容。更有趣的是三个公共方法(除了构造函数之外):addContact、deleteContact 和 loadContacts。这三个方法实质上都是先前开发的数据访问代码的包装器。实际上,我们不需要将 Applet 用于最终应用程序的 UI,但是它提供了测试代码的简单方法。如果使用的是 Eclipse,则只需在 Applet 类上右键单击并选择 Run As > Java Applet。

 

安全性

我们将为 Applet 中使用的 JAR 设置签名。如果这里继续遵循计划,有一件事好到令人难以置信。Derby 将给我们提供嵌入到客户机中的持久数据库(所有内容都存储在客户机中)。它有几分像 HTTP Cookie,但是众所周知,那些 Cookie 在每个域中不可以超过 4 KB。客户机中的 Derby 数据库的限制是什么?答案是要么很多,要么很少。

默认情况下,Applet 无法访问本地文件系统,因此 Derby 无法在客户机中存储任何数据。那么使用 Derby 是做白日梦么?幸运的是,它不是。关键是您必须给 Applet 设置数字签名。有签名的 Applet 将获得本地文件系统的访问权,这样如果数据来自有签名的 Applet,则 Derby 可以持久存储这些数据。我们只需给 Applet 设置签名。

$ keytool -genkey -alias sigs -keystore sigstore -keypass password -storepass password
What is your first and last name?
  [Unknown]:  Michael
What is the name of your organizational unit?
  [Unknown]:  developerWorks
What is the name of your organization?
  [Unknown]:  IBM
What is the name of your City or Locality?
  [Unknown]:  San Jose
What is the name of your State or Province?
  [Unknown]:  CA
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Michael, OU=developerWorks, O=IBM, L=San Jose, ST=CA, C=US correct?
  [no]:  yes

$ jarsigner -keystore sigstore -storepass password -keypass password -signedjar 
addrbook.jar derby.jar sigs

Warning: The signer certificate will expire within six months.

 

正如您所见,我们使用两个 JDK 工具给 Applet(技术上是包含 Applet 的 JAR)设置签名。首先,使用 keytool 创建用于保存生成的加密密钥的密钥库。还可以使用它执行创建 SSL 证书之类的任务。在拥有密钥后,结合使用该密钥与 jarsigner 工具来给 JAR 设置签名。注意,我们包括了 Derby JAR,以及包含自定义代码的 addrbook JAR。最终获得了一个自签名 Applet 的示例。这对于开发来说没问题,但是通常不适用于任何面向用户的代码。在这种情况下,您将需要来自受信任提供商(如 VeriSign)的密钥/证书。关键原因是因为需要在客户机中存储数据,我们需要执行这些附加步骤才能符合 Java 语言的客户端安全模型。牢记这些安全事项并且拥有一颗可以正常工作的 Applet 后,我们现在已经准备好从 JavaScript 使用 Applet。


下载完整代码

分享到:
评论
4 楼 toafu 2010-09-02  
http://www.ibm.com/developerworks/cn/opensource/os-ad-offline-ajax/
3 楼 slaser 2010-04-19  
就是用derby进行本地数据存储?
我觉得关键技术是,本地数据库和服务器数据的同步,这像个C/S程序。
2 楼 david2083 2010-04-19  
你没听说过HTML5么
1 楼 jerryqiu007 2010-04-19  
图片怎么没了?

相关推荐

    apache derby 学习资料

    收集的学习资料,包括:Derby数据库(V10.9)用户手册(PDF版),用 Apache Derby 进行 Java 数据库开发,用 Apache Derby 进行数据库开发,03开源项目(三)嵌入式数据库Apache Derby(1)(开发指南).pdf ,Apache Derby ...

    Apache Derby 10.5版手册集

    Apache Derby的10.5版本提供了多本手册,这些手册涵盖了从入门到系统管理、开发指南以及工具使用等多个方面。其中: 1. Getting Started with Derby - 为10.5版本:这本手册是一本入门指南,适合初学者快速上手...

    Apache Derby 10.2版手册集

    Apache Derby 10.2版手册集包含了多个文档,每个文档都针对不同的使用场景和技术需求进行了详尽的说明: 1. **《Getting Started with Derby》(适用于10.2版本)** - **链接**:[Getting Started with Derby]...

    apache derby

    总之,这个压缩包很可能包含了一个定制版的Apache Derby数据库系统,具有特定版本的核心功能插件和用户友好的管理界面插件,适合需要轻量级数据库解决方案的开发者或团队使用。通过这些插件,用户可以更加便捷地管理...

    Eclipse下Apache Derby开发

    在Eclipse中开发Apache Derby应用程序涉及到一系列步骤和工具的使用。Apache Derby是一款开源的关系型数据库管理系统,它轻量级、嵌入式,适用于Java应用程序。Eclipse作为流行的Java集成开发环境,提供了丰富的工具...

    Apache Derby 10.4版手册集

    - GettingStartedwithDerby:这可能是一份指南,旨在帮助新用户快速上手使用Apache Derby。 - DerbyReferenceManual:作为参考手册,该手册可能为数据库管理员和开发人员提供了详细的API文档和数据库操作的参考...

    Apache Derby 10.10版手册集

    总之,Apache Derby 10.10版手册集是一个全面、系统的参考资料库,它覆盖了Derby数据库的安装、配置、使用、管理及性能调优等各个方面,旨在帮助用户更有效地利用Derby数据库管理系统来满足他们的数据存储和处理需求...

    Apache Derby(入门指南jar)

    Apache Derby,又称为IBM Cloudscape,是一款轻量级、开源的嵌入式关系型数据库管理系统,完全用Java语言编写,因此具有平台无关性。它的设计目标是为Java应用程序提供一个简单、高性能且易于管理的数据存储解决方案...

    嵌入式数据库Apache Derby(入门指南)

    嵌入式数据库Apache Derby是用 Java 语言编写的,所以可以在任何存在合适的 Java 虚拟机(JVM)的地方运行,Derby软件绑定在Java档案(JAR)文件中,只有2MB大小.

    用 Apache Derby 进行开发 —— 取得节节胜利

    【Apache Derby 开发详解——轻松获胜】 Apache Derby 是一款开源的、基于标准的轻量级Java数据库管理系统,由...通过学习和使用Apache Derby,开发者可以更高效地实现数据存储和管理,取得开发过程中的节节胜利。

    Apache Derby 10.1版手册集

    Apache Derby是一个开源的数据库管理系统(DBMS),由Apache软件基金会负责开发与维护。作为一款纯Java编写的应用程序,Apache Derby具备跨平台的特性,只要有Java虚拟机(JVM)运行环境的支持,它就可以在不同的...

    Apache Derby/Java DB 开发手册

    Derby Developer's Guide. Purpose of this guide This guide explains how to use the core Derby technology and is for developers building Derby applications. It describes basic Derby concepts, such as ...

    Apache Derby 10.9版手册集

    Apache Derby 10.9版是该数据库系统的一个特定版本,提供了多个重要的指南和文档,以帮助开发者和管理员更好地理解和使用这个系统: 1. **Getting Started with Derby**:这是针对10.9版本的入门指南,旨在帮助新...

    用Apache Derby、Apache MyFaces和Facelets开发应用程序

    学习如何使用 Apache Derby、Apache MyFaces 和 Facelets 来开发 Java:trade_mark:Server:trade_mark: Faces (JSF) 应用程序。本文中示例应用程序使用了 Model-View-Controller (MVC) 架构,用来说明 MyFaces 组件的...

    Apache Derby 10.6版手册集

    Apache Derby是一个由Apache软件基金会研发的开源关系数据库管理系统(RDBMS),它的特点在于完全用Java编写,这意味着它具有很好的可移植性。由于其纯Java的特性,Derby可以在任何支持Java虚拟机的操作系统上运行,...

    apache Derby jar包

    Apache Derby是一款轻量级、嵌入式的关系型数据库管理系统,完全用Java编写,遵循Apache软件基金会的开放源代码协议。它的设计目标是提供一个小型、高性能、易用且完全符合SQL标准的数据库解决方案,适用于各种应用...

    Apache Derby 10.7版手册集

    Apache Derby是一种由Apache软件基金会开发的开源关系数据库管理系统(RDBMS),其特点是完全用Java编写而成,因此也被称作Java DB。由于Derby是纯Java应用程序,这意味着它可以跨平台运行,只需要操作系统的Java...

Global site tag (gtag.js) - Google Analytics