広告

■□■□■□■□■□■□■□■□■□■□■□■□■□■□■
                      2011年12月19日

   Java総合講座 - 初心者から達人へのパスポート
                 2009年11月開講コース 051号

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:vol.xxx(xxxは番号)が振られています。
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:xxx号(xxxは番号)が振られています。
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


========================================================
◆ 01.データベースを使用するアプリケーションの開発(続き)
========================================================

今回は、HumanResourceEntryPaneに「削除」の機能を組み込み
ます。

これまでの記事で、データベースを使用するアプリケーションの
作り方のパターンはだいたい理解できたことと思いますので、
今回は説明をごく簡単に済ませることにします。


では、まず最初に例によって、EmployeeDbManagerクラスにデータ
の削除のメソッドを追加しましょう

EclipseでEmployeeDbManagerのエディターを開き、以下の編集を
行ってください。

まず、下記のPreparedStatement型の変数

--------------------------------------------------------
private String deleteSql = "DELETE FROM EMPLOYEE WHERE EMP_NUM = ?";
--------------------------------------------------------

を追加しましょう。

次に、下記のメソッドを追加しましょう。

--------------------------------------------------------
public boolean deleteData(Employee anEmployee) {
   try {
      connect();
      PreparedStatement selectPs = conn.prepareStatement(selectSql);
      selectPs.setInt(1, anEmployee.getEmployeeNumber());
      ResultSet rs = selectPs.executeQuery();
      if (!rs.next()) return false;
      selectPs.close();
      conn.setAutoCommit(false);
      PreparedStatement deletePs = conn.prepareStatement(deleteSql);
      deletePs.setInt(1, anEmployee.getEmployeeNumber());
      deletePs.executeUpdate();
      deletePs.close();
      conn.commit();
      disconnect();
   }
   catch (SQLException exception) {
      exception.printStackTrace();
   }
   return true;
}
--------------------------------------------------------

このソース・コードでは、例によって、該当する社員番号がデータ
ベース上に存在することを確認した上で、その社員のデータを削除
しています。
これもソース・コードの説明はもう必要ないですね

では、続いてHumanResourceEntryPane側の編集を行いましょう。

これまでは、「新規登録」のページ、「検索」のページ、「更新」の
ページというように各機能ごとに専用のページを用意していましたが、
今回は作業を簡単に済ませるために「更新」のページに「削除」の
ボタンを付け足し、「更新」のページに表示されている社員番号に対し
て「削除」を実行するようにします。


HumanResourceEntryPaneのエディター(WindowBuilder Editor)を開い
て、Designビューで「更新」のページを表示してください。

Palette(パレット)のComponents配下からJButtonを選択し、
「更新」ボタンの右側に貼り付けましょう。
変数名(Properties欄のVariable)は「jButtonDelete」にしましょう。
また、textプロパティーの値は「削除」にしましょう。

次に、この「削除」ボタンを右クリックし、「Add event handler」→
「アクション」→「actionPerformed」を選択します。

そうすると、getJButtonDelete()メソッドの中に下記のソース・コード
が自動生成されますね。

--------------------------------------------------------
jButtonDelete.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
   }
});
--------------------------------------------------------

これを下記のように編集しましょう。

--------------------------------------------------------
jButtonDelete.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
      Employee anEmployee = new Employee();
      int empNumber;
      try {
         empNumber = Integer.parseInt(getJTextFieldEmpNum().getText());
      }
      catch (NumberFormatException e1) {
         getMessageDialog().getTextPane().setText("エラー:社員番号の入力値が数字になっていません。");
         getMessageDialog().setVisible(true);
         return;
      }
      anEmployee.setEmployeeNumber(empNumber);
      EmployeeDbManager empDbManager = new EmployeeDbManager();
      if (empDbManager.deleteData(anEmployee)) {
         getMessageDialog().getTextPane().setText("削除が完了しました。");
         getMessageDialog().setVisible(true);
      }
      else {
         getMessageDialog().getTextPane().setText("指定された社員番号が存在しないため、削除はできませんでした。");
         getMessageDialog().setVisible(true);
      }
   }
});
--------------------------------------------------------

このソース・コードも、もう説明不要ですね。



ところで、このHumanResourceEntryPaneのソース・コードの中には、やたらに

--------------------------------------------------------
getMessageDialog().getTextPane().setText("○○○");
getMessageDialog().setVisible(true);
--------------------------------------------------------

の組み合わせが何度も出てきますね。

この組み合わせはメソッド化してしまって、メッセージの部分(上記の"○○○"
の部分)のような可変部分はメソッドの引数で受け渡しする形にすれば、それぞれ
の2行の部分が1行のメソッド呼び出しに置き換えることができ、ソース・コード
の行数が減ってすっきりするし、間違いも減る(たとえばsetVisible(true)の呼び
出しは書き忘れやすいが、それを忘れる心配がなくなる)と感じた人もいることで
しょう。
(ここではgetMessageDialog()によってMessageDialogのインスタンスを呼び出して
そのメソッドを使っているわけですが、MessageDialogのような汎用性のあるクラスは、
後で他のアプリケーションでも再利用される可能性が高いですが、その場合に上記の
2行のような余計なコードをいちいち書かされるのでは不便です。やはり一つのメソッド
にしてしまったほうがよいでしょう。)


というわけで、上記の2行をメソッド化する作業をやってみましょう。

ちなみに、これも一種のリファクタリングですが、(プロであれば2〜3分でできる)
簡単な作業なので、今回は最初から手作業で行います。


まず、(jp.co.flsi.lecture.uiパッケージの)MessageDialog.javaのソース・コード
をエディターで開きましょう。

(1) このクラスに下記のようなメソッドを追加しましょう。

--------------------------------------------------------
   public void setMessageAndShow(String message) {
      getTextPane().setText(message);
      setVisible(true);
   }
--------------------------------------------------------

(2) 上記のメソッドを使えば、getTextPane()メソッドを公開する必要はなく
なるので、getTextPane()メソッドはprivateに変更します。つまり、
getTextPane()メソッドを定義しているコードを下記のように書き換えます。
(コードの場所を見つけにくい場合は、以前お話したようにgetTextPaneの
文字列の中にカーソルを入れてF3キーを押せば、そのメソッドの定義の所
に飛んでくれます。)

--------------------------------------------------------
   private JTextPane getTextPane() {
      return textPane;
   }
--------------------------------------------------------
(変更するのはpublicをprivateに書き換えることだけです。)

(3) すると、HumanResourceEntryPaneのソース・コードの中で上のgetTextPane()
を呼び出していた所がことごとくエラー(赤いアンダーラインが付く)になり
ますね。(これで、書き換えるべき所が一目瞭然になります。)
そこをことごとく上のsetMessageAndShow()メソッドの呼び出しに
書き換えます。つまり、getButton()メソッド、getJButtonUpdate()メソッド、
getJButtonDelete()メソッドの定義のコードをそれぞれ下記のように書き換え
ます。これは「getTextPane().setText」の文字列を置換の機能(メニュー・バー
から「編集」→「検索/置換」を選択)で「setMessageAndShow」に一挙に変換
すれば簡単にできます。ただし、その後
getMessageDialog().setVisible(true);
の行をことごとく削除するのを忘れないように(これも置換の機能で一挙に
空白行に変換すれば簡単である)。

--------------------------------------------------------
   private JButton getButton() {
      if (button == null) {
         button = new JButton("\u767B\u9332");
         button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               Employee anEmployee = new Employee();
               int empNumber;
               try {
                  empNumber = Integer.parseInt(getJTextFieldEntryEmpNum().getText());
               }
               catch (NumberFormatException e1) {
                  String errorHtml = "<HTML>"
                        + "<HEAD><TITLE>エラー・メッセージ</TITLE></HEAD>"
                        + "<BODY>"
                        + "<FONT color=\"FF0000\" size=\"+1\">エラー:</FONT><BR>"
                        + "<FONT color=\"0000FF\">社員番号</FONT>の入力値が数字になっていません。"
                        + "</BODY>"
                        + "</HTML>";
                  getMessageDialog().setMessageAndShow(errorHtml);
                  return;
               }
               anEmployee.setEmployeeNumber(empNumber);

               anEmployee.setName(getJTextFieldEntryName().getText());
               CalendarConverter aCalConverter = new CalendarConverter();
               aCalConverter.setDay(Integer.parseInt(getTextField().getText()));
               aCalConverter.setMonth(Integer.parseInt(getTextField_1().getText()));
               aCalConverter.setJaNameOfEra(getComboBox().getSelectedIndex());
               switch (aCalConverter.getJaNameOfEra()) {
                case 0:
                case 1:
                case 2:
                case 3:
                  aCalConverter.setJaYear(Integer.parseInt(getJTextField2().getText()));
                  aCalConverter.convertJaCal2GreCal();
                  break;
                default:
                  aCalConverter.setGreYear(Integer.parseInt(getJTextField2().getText()));
                  break;
               }
               anEmployee.setDateOfBirth(aCalConverter.getGreYear(), aCalConverter.getMonth(), aCalConverter.getDay());
               ComboBoxModelOfDepartment aBoxModelOfDepartment = (ComboBoxModelOfDepartment) getComboBox_1().getModel();
               Department aDepartment = (Department)aBoxModelOfDepartment.getDepartmentList().get(getComboBox_1().getSelectedIndex());
               anEmployee.setDepartmentNumber(aDepartment.getDepartmentNumber());
               EmployeeDbManager empDbManager = new EmployeeDbManager();
               if (empDbManager.insertData(anEmployee)) {
                  getMessageDialog().setMessageAndShow("新規登録が完了しました。");
               }
               else {
                  getMessageDialog().setMessageAndShow("指定された社員番号がすでに存在するため、新規登録はできませんでした。");
               }
            }
         });
      }
      return button;
   }
--------------------------------------------------------

--------------------------------------------------------
   private JButton getJButtonUpdate() {
      if (jButtonUpdate == null) {
         jButtonUpdate = new JButton("\u66F4\u65B0");
         jButtonUpdate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               Employee anEmployee = new Employee();
               int empNumber;
               try {
                  empNumber = Integer.parseInt(getJTextFieldEmpNum().getText());
               }
               catch (NumberFormatException e1) {
                  getMessageDialog().setMessageAndShow("エラー:社員番号の入力値が数字になっていません。");
                  return;
               }
               anEmployee.setEmployeeNumber(empNumber);
               anEmployee.setName(getJTextFieldName().getText());
               CalendarConverter aCalConverter = new CalendarConverter();
               aCalConverter.setDay(Integer.parseInt(getJTextFieldDay().getText()));
               aCalConverter.setMonth(Integer.parseInt(getJTextFieldMonth().getText()));
               aCalConverter.setJaNameOfEra(getJComboBoxEra().getSelectedIndex());
               switch (aCalConverter.getJaNameOfEra()) {
               case 0:
               case 1:
               case 2:
               case 3:
                  aCalConverter.setJaYear(Integer.parseInt(getJTextFieldYear().getText()));
                  aCalConverter.convertJaCal2GreCal();
                  break;
               default:
                  aCalConverter.setGreYear(Integer.parseInt(getJTextFieldYear().getText()));
                  break;
               }
               anEmployee.setDateOfBirth(aCalConverter.getGreYear(), aCalConverter.getMonth(), aCalConverter.getDay());
               ComboBoxModelOfDepartment aBoxModelOfDepartment = (ComboBoxModelOfDepartment) getJComboBoxDepart().getModel();
               Department aDepartment = (Department)aBoxModelOfDepartment.getDepartmentList().get(getJComboBoxDepart().getSelectedIndex());
               anEmployee.setDepartmentNumber(aDepartment.getDepartmentNumber());
               EmployeeDbManager empDbManager = new EmployeeDbManager();
               if (empDbManager.updateData(anEmployee)) {
                  getMessageDialog().setMessageAndShow("更新が完了しました。");
               }
               else {
                  getMessageDialog().setMessageAndShow("指定された社員番号が存在しないため、更新はできませんでした。");
               }
            }
         });
      }
      return jButtonUpdate;
   }
--------------------------------------------------------

--------------------------------------------------------
   private JButton getJButtonDelete() {
      if (jButtonDelete == null) {
         jButtonDelete = new JButton("\u524A\u9664");
         jButtonDelete.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
               Employee anEmployee = new Employee();
               int empNumber;
               try {
                  empNumber = Integer.parseInt(getJTextFieldEmpNum().getText());
               }
               catch (NumberFormatException e1) {
                  getMessageDialog().setMessageAndShow("エラー:社員番号の入力値が数字になっていません。");
                  return;
               }
               anEmployee.setEmployeeNumber(empNumber);
               EmployeeDbManager empDbManager = new EmployeeDbManager();
               if (empDbManager.deleteData(anEmployee)) {
                  getMessageDialog().setMessageAndShow("削除が完了しました。");
               }
               else {
                  getMessageDialog().setMessageAndShow("指定された社員番号が存在しないため、削除はできませんでした。");
               }
            }
         });
      }
      return jButtonDelete;
   }
--------------------------------------------------------



編集が終わったらテスト(HumanResourceJFrameの実行)をしてみ
ましょう。

これで「人事情報を管理するためのアプリケーション」の基本的な
機能は完成しました。


しかし、このままだと、このアプリケーションは誰でも使えてしまい
ますね。
これでは、まずいですから、決められた人(人事管理者)だけしか使
えないようにパスワードで保護することにしましょう。
これは次回やります。


では、今回はここまで。


(続く)



========================================================
◆ 02.文法解説 [break文]
========================================================

[break文]

ループを途中で抜け出したいとき、つまり、ループの実行を途中で
やめたいときに使うのが、break文

break;

です。

ループが入れ子になって階層構造になっているときは、直近のループ
から抜け出すことになります。
たとえば、

--------------------------------------------------------
int i;
do {
   i = (int) (Math.random() * 100);
   System.out.println("ここ掘れワンワン。掘ったら小判が" + i + "枚。");
   for (int j = 1; j < 10; j++) {
      i -= 10 * j;
      if (i < 10) {
         break;
      }
      System.out.println(10 * j + "枚使って、残りは" + i + "枚。");
   }
   System.out.println("(forループ終わり)");
} while (i != 5);
System.out.println("(doループ終わり)");
--------------------------------------------------------

とすると、このbreak文では、forループを抜け出して、その下の

System.out.println("(forループ終わり)");

の行に飛ぶことになります。


┌補足─────────────────────────┐
上のソース・コードの中のMathクラスは、数学関連のメソッドを
持つクラスです。
そのうちのrandom()メソッドは、乱数を返すメソッドで、0以上1未満
のdouble型の数値を返します。
なお、random()メソッドはstaticメソッドなので、Math.random()と
いう形式で呼び出すことができます。
上のソース・コードの中の

i = (int) (Math.random() * 100);

では、random()メソッドによって取り出した乱数を100倍した後、
int型にキャストしていますから、0から99までの数がiに代入される
ことになります。(乱数ですから無作為な値が出てきます。)
└───────────────────────────┘


複数のループが入れ子になっているとき、すなわち複数のループに
よって階層構造になっているときに、どの階層を抜け出したいのか
を明示したい場合は、

break  ラベル名;

という形式で指定します。

このラベル名というのは、

--------------------------------------------------------
ラベル名: {

}
--------------------------------------------------------

という形式でブロック({と}で囲まれた部分)に名前をつけておいた
ものです。
「break  ラベル名;」によって、このブロックの外に抜け出ることが
できます。

たとえば、

--------------------------------------------------------
int i = 0;
outerLoop: {
   do {
      i = (int) (Math.random() * 100);
      System.out.println("ここ掘れワンワン。掘ったら小判が" + i + "枚。");
      innerLoop: {
         for (int j = 1; j < 10; j++) {
            i -= 10 * j;
            if (i < 10) {
               if (i == 5) {
                  System.out.println("(forループ終わり)");
                  break outerLoop;
               }
               else {
                  break innerLoop;
               }
            }
            System.out.println(10 * j + "枚使って、残りは" + i + "枚。");
         }
      }
      System.out.println("(forループ終わり)");
   } while (true);
//   System.out.println("(ここは実行されない)");
}
System.out.println("(doループ終わり)");
--------------------------------------------------------

とすると、
break outerLoop;
では、outerLoopのブロックを抜け出しますので、doループの外に
出ます。

また、
break innerLoop;
では、innerLoopのブロックを抜け出しますので、forループの外に
出ます。


なお、上のソース・コードのようにwhile (true)を指定した場合には、
いつまでもループの処理を繰り返す、いわゆる「無限ループ」になり
ます。

無限ループはどこかの時点で終わらせなければなりませんから、
上のソース・コードのようにbreak文を使って終わらせたりします。
(return文を使ってメソッドごと終わらせる場合もあります。)


(続く)



================================================
◆ 03.演習問題
================================================

上記のbreak文の振る舞いを確認するために、下記のようなプロ
グラムを作って実行してみてください。
そして、自分で理解している通りの結果が出ることを確認して
ください。

--------------------------------------------------------
public class BreakTest {

   public static void main(String[] args) {
      System.out.println("[Example 1]");
      int i;
      do {
         i = (int) (Math.random() * 100);
         System.out.println("ここ掘れワンワン。掘ったら小判が" + i + "枚。");
         for (int j = 1; j < 10; j++) {
            i -= 10 * j;
            if (i < 10) {
               break;
            }
            System.out.println(10 * j + "枚使って、残りは" + i + "枚。");
         }
         System.out.println("(forループ終わり)");
      } while (i != 5);
      System.out.println("(doループ終わり)");

      System.out.println("\n[Example 2]");
      outerLoop: {
         do {
            i = (int) (Math.random() * 100);
            System.out.println("ここ掘れワンワン。掘ったら小判が" + i + "枚。");
            innerLoop: {
               for (int j = 1; j < 10; j++) {
                  i -= 10 * j;
                  if (i < 10) {
                     if (i == 5) {
                        System.out.println("(forループ終わり)");
                        break outerLoop;
                     }
                     else {
                        break innerLoop;
                     }
                  }
                  System.out.println(10 * j + "枚使って、残りは" + i + "枚。");
               }
            }
            System.out.println("(forループ終わり)");
         } while (true);
//         System.out.println("(ここは実行されない)");
      }
      System.out.println("(doループ終わり)");
   }
}
--------------------------------------------------------

なお、
//         System.out.println("(ここは実行されない)");
の行のコメントをはずす(//のマークを取り除くこと)とどうな
るかも確認してみてください。



(次回に続く。)



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2011 Future Lifestyle Inc. 不許無断複製