6 請求日誌
請求日誌就是將請求的記錄儲存下來,通常以記錄檔(Log File)的形式永久儲存在電腦中。很多系統都提供了記錄檔,例如Windows記錄檔、Oracle記錄檔等,記錄檔可以記錄使用者對系統的一些操作(例如對資料的更改)。請求記錄檔可以實現很多功能,常用功能如下:
(1) “天有不測風雲”,一旦系統發生故障,記錄檔可以為系統提供一種恢複機制,在請求記錄檔中可以記錄使用者對系統的每一步操作,從而讓系統能夠順利恢複到某一個特定的狀態;
(2) 請求日誌也可以用於實現批處理,在一個請求記錄檔中可以儲存一系列命令對象,例如一個命令隊列;
(3) 可以將命令隊列中的所有命令對象都儲存在一個記錄檔中,每執行一個命令則從記錄檔中刪除一個對應的命令對象,防止因為斷電或者系統重啟等原因造成請求丟失,而且可以避免重新發送全部請求時造成某些命令的重複執行,只需讀取請求記錄檔,再繼續執行檔案中剩餘的命令即可。
在實現請求日誌時,我們可以將命令對象通過序列化寫到記錄檔中,此時命令類必須實現java.io.Serializable介面。下面我們通過一個簡單一實例來說明記錄檔的用途以及如何?請求日誌:
|
Sunny軟體公司開發了一個網站設定檔管理工具,可以通過一個可視化介面對網站設定檔進行增刪改等操作,該工具使用命令模式進行設計,結構如圖6所示:
圖6 網站設定檔管理工具結構圖
現在Sunny軟體公司開發人員希望將對設定檔的操作請求記錄在記錄檔中,如果網站重新部署,只需要執行儲存在記錄檔中的命令對象即可修改設定檔。 |
本執行個體完整代碼如下所示: [java] view plain copy import java.io.*; import java.util.*; //抽象命令類,由於需要將命令對象寫入檔案,因此它實現了Serializable介面 abstract class Command implements Serializable { protected String name; //命令名稱 protected String args; //命令參數 protected ConfigOperator configOperator; //維持對接收者對象的引用 public Command(String name) { this.name = name; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public void setConfigOperator(ConfigOperator configOperator) { this.configOperator = configOperator; } //聲明兩個抽象的執行方法execute() public abstract void execute(String args); public abstract void execute(); } //增加命令類:具體命令 class InsertCommand extends Command { public InsertCommand(String name) { super(name); } public void execute(String args) { this.args = args; configOperator.insert(args); } public void execute() { configOperator.insert(this.args); } } //修改命令類:具體命令 class ModifyCommand extends Command { public ModifyCommand(String name) { super(name); } public void execute(String args) { this.args = args; configOperator.modify(args); } public void execute() { configOperator.modify(this.args); } } //省略了刪除命令類DeleteCommand //設定檔操作類:請求接收者。由於ConfigOperator類的對象是Command的成員對象,它也將隨Command對象一起寫入檔案,因此ConfigOperator也需要實現Serializable介面 class ConfigOperator implements Serializable { public void insert(String args) { System.out.println("增加新節點:" + args); } public void modify(String args) { System.out.println("修改節點:" + args); } public void delete(String args) { System.out.println("刪除節點:" + args); } } //設定檔設定視窗類別:請求寄件者 class ConfigSettingWindow { //定義一個集合來儲存每一次操作時的命令對象 private ArrayList<Command> commands = new ArrayList<Command>(); private Command command; //注入具體命令對象 public void setCommand(Command command) { this.command = command; } //執行設定檔修改命令,同時將命令對象添加到命令集合中 public void call(String args) { command.execute(args); commands.add(command); } //記錄請求日誌,組建記錄檔檔案,將命令集合寫入記錄檔 public void save() { FileUtil.writeCommands(commands); } //從記錄檔中提取命令集合,並迴圈調用每一個命令對象的execute()方法來實現設定檔的重新設定 public void recover() { ArrayList list; list = FileUtil.readCommands(); for (Object obj : list) { ((Command)obj).execute(); } } } //工具類:檔案操作類 class FileUtil { //將命令集合寫入記錄檔 public static void writeCommands(ArrayList commands) { try { FileOutputStream file = new FileOutputStream("config.log"); //建立對象輸出資料流用於將對象寫入到檔案中 ObjectOutputStream objout = new ObjectOutputStream(new BufferedOutputStream(file)); //將對象寫入檔案 objout.writeObject(commands); objout.close(); } catch(Exception e) { System.out.println("命令儲存失敗。"); e.printStackTrace(); } } //從記錄檔中提取命令集合 public static ArrayList readCommands() { try { FileInputStream file = new FileInputStream("config.log"); //建立對象輸入資料流用於從檔案中讀取對象 ObjectInputStream objin = new ObjectInputStream(new BufferedInputStream(file)); //將檔案中的對象讀出並轉換為ArrayList類型 ArrayList commands = (ArrayList)objin.readObject(); objin.close(); return commands; } catch(Exception e) { System.out.println("命令讀取失敗。"); e.printStackTrace(); return null; } } }
編寫如下用戶端測試代碼: [java] view plain copy class Client { public static void main(String args[]) { ConfigSettingWindow csw = new ConfigSettingWindow(); //定義請求寄件者 Command command; //定義命令對象 ConfigOperator co = new ConfigOperator(); //定義請求接收者 //四次對設定檔的更改 command = new InsertCommand("增加"); command.setConfigOperator(co); csw.setCommand(command); csw.call("網站首頁"); command = new InsertCommand("增加"); command.setConfigOperator(co); csw.setCommand(command); csw.call("連接埠號碼"); command = new ModifyCommand("修改"); command.setConfigOperator(co); csw.setCommand(command); csw.call("網站首頁"); command = new ModifyCommand("修改"); command.setConfigOperator(co); csw.setCommand(command); csw.call("連接埠號碼"); System.out.println("----------------------------"); System.out.println("儲存配置"); csw.save(); System.out.println("----------------------------"); System.out.println("恢複配置"); System.out.println("----------------------------"); csw.recover(); } }
編譯並運行程式,輸出結果如下:
增加新節點:網站首頁
增加新節點:連接埠號碼
修改節點:網站首頁
修改節點:連接埠號碼
----------------------------
儲存配置
----------------------------
恢複配置
----------------------------
增加新節點:網站首頁
增加新節點:連接埠號碼
修改節點:網站首頁
修改節點:連接埠號碼