《JavaTM程序设计语言基 础》第 2 部分
第 4 课:串行化

[<<后退] [目录] [下一课>>]

示例程序的当前形式存在一个大问题:在接收客户机收到并处理一个发送客户 机的信息之前,其它发送信息的客户机就已用其所发信息覆盖了该信息。本课采 用服务器程序来确保所有订单都得到处理(不致被覆盖)并按照服务器接收顺序 进行处理。


关于示例程序的说明

示例程序采用 第 2 部分、第 2 课:再谈用户界面中 的示例程序把水果订购信息打包(Wrap)到单个的数据对象中,并通过网络把数据 对象发送给服务器。这样做比单独发送各个数据单元的效率要高。

打包数据

DataOrder.java 是一种非常简单的类。它定义用于打包和存放水果订单数据的域。这个类没有方 法。它实现 Serializable 接口方法,因此其数据可串行化并作为 一个单独的单元与文件之间进行读/写操作。

对象串行化(serialization)把对象的数据转换成表示数据状态的字节流。数 据的串行化形式所包含的数据足以用来重新创建对象,新对象的数据具有与其保存 时的状态相同的状态。

import java.io.*;

class DataOrder implements Serializable{
  String apples, peaches, pears, cardnum, custID;
  double icost;
  int itotal;
}

发送数据

RMIClient1.java 程序经过修改后,可利用 DataOrder 类在网络上发送订单数据。 RMIClient1.actionPerformed 方法创建 DataOrder 类的实例并使用从用户界面文本域和文本区检索到的订单数据对该域进行初始化。

  public void actionPerformed(ActionEvent event){
   Object source = event.getSource();
   Integer applesNo, peachesNo, pearsNo, num;
   Double cost;
   String number, text, text2;
   DataOrder order = new DataOrder();

   if(source == purchase){
    order.cardnum = creditCard.getText();
    order.custID = customer.getText();
    order.apples = appleqnt.getText();
    order.peaches = peachqnt.getText();
    order.pears = pearqnt.getText();
订购总数量采用 order.icost 域进行计算。
   if(order.apples.length() > 0){
     try{
       applesNo = Integer.valueOf(order.apples);
       order.itotal += applesNo.intValue();
     } catch (java.lang.NumberFormatException e) {
       appleqnt.setText("Invalid Value");
     }
   } else {
        order.itotal += 0;
   }
order.itotal 域中提取订购总数并将订购总数显示在用户界面 中。
  num = new Integer(order.itotal);
  text = num.toString();
  this.items.setText(text);
与此类似,总费用也是利用 order.icost 域进行计算并显示在用 户界面中。
 order.icost = (order.itotal * 1.25);
 cost = new Double(order.icost);
 text2 = cost.toString();
 this.cost.setText(text2);

 try{
   send.sendOrder(order);
 } catch (Exception e) {
    System.out.println("Cannot send data to server");
 }
总数计算完毕后,把 order 对象通过网络发送给服务器程序。

服务器程序

本课中的 Send.javaRemoteServer.java 类比其它课中的简单得多。它们有一个返回 DataOrder 实例的 getXXX 方法和一个接收 DataOrder 实例的 setXXX 方法。

Send.java

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Send extends Remote {
  public void sendOrder(DataOrder order) 
    throws RemoteException;
  public DataOrder getOrder() throws RemoteException;
}
RemoteServer.java

RemoteServer.sendOrder 方法把 DataOrder 实 例当作输入接受并把每一个订单保存在一个以编号命名的单独文件中。即第一个订 单保存在以 1 命名的文件中,第二个订单保存在以 2 命名的 文件中,以此类推。

为了跟踪文件名,每次调用 sendOrder 方法时 value 变量的值都加 1,然后转化为 String 型并 在串行化进程中用作文件名。

通过创建一个串行化输出流并把对象写入到输出流的方式,使对象串行化。在 程序代码中,try 程序块的第一行创建一个FileOutputStream, 输入参数如文件名,此文件将用于写入串行化的对象。

其后的程序行从文件输出流创建一个 ObjectOutputFileStream。 这是用于在 try 程序块最后一行中向其写入 order 对象的已串行化输出流。

RemoteServer.java

public void sendOrder(DataOrder order){

  value += 1;
  num = new Integer(value);
  orders = num.toString();
  try{
    FileOutputStream fos = 
      new FileOutputStream(orders);
    ObjectOutputStream oos = 
      new ObjectOutputStream(fos);
    oos.writeObject(order);
  }catch (java.io.FileNotFoundException e){
    System.out.println(e.toString());
  }catch (java.io.IOException e){
    System.out.println(e.toString());
  }
}
RemoteServer.getOrder 方法所完成的操作与 sendOrder 方法所完成的操作相反,它利用 get 变量来跟踪那些已经查看过的 订单。

但是,这个方法首先要检查 value 变量。如果该变量的值等于 0,则表示未从某个文件或视图中得到任何订单;如果其值大于 get 变量中的值,则表示从某个文件或视图中得到了至少一个订单。只要查看到一个订 单,get 变量的值就会加 1。

  public DataOrder getOrder(){

    DataOrder order = null;

    if(value == 0){
      System.out.println("No Orders To Process");
    }

    if(value > get){
      get += 1;
      num = new Integer(get);
      orders = num.toString();
      try{
        FileInputStream fis = 
          new FileInputStream(orders);
        ObjectInputStream ois = 
          new ObjectInputStream(fis);
        order = (DataOrder)ois.readObject();
      }catch (java.io.FileNotFoundException e){
        System.out.println(e.toString());
      }catch (java.io.IOException e){
        System.out.println(e.toString());
      }catch (java.lang.ClassNotFoundException e){
        System.out.println(e.toString());
      }
    }else{
      System.out.println("No Orders To Process");
    }
   return order;
  }

接收数据

RMIClient2.actionPerformed 方法获取一个 order 对象并参照其域将数据显示在用户界面上。

if(source == view){
  try{
    order  = send.getOrder();
    creditNo.setText(order.cardnum);
    customerNo.setText(order.custID);
    applesNo.setText(order.apples);
    peachesNo.setText(order.peaches);
    pearsNo.setText(order.pears);

    cost = order.icost;
    price = new Double(cost);
    unit = price.toString();
    icost.setText(unit);

    items = order.itotal;
    itms = new Integer(items);
    i = itms.toString();
    itotal.setText(i);
  } catch (Exception e) {
    System.out.println("Cannot send data to server");
  }
}

更多信息

有关串行化的详细说明,请参阅Java TM 教程 中的 读出和写入(非算术) 一课。

[TOP]

 

常见问答
下载中心
产品简介
 
 
Solaris论坛
 
   
 
null