e-learning、オラクル研修、LMS(学習管理システム)のiStudy

e-learning、オラクル研修、LMS(学習管理システム)のiStudy

第122回「実用WEBアプリ 文書管理システム(3)文書登録」

2015.03.26

こんにちは。インストラクターの蓑島です。

もうすぐ4月ですね。新しい環境で期待に胸を膨らませる若い方々も多いと思います。
そんな皆さんのスキルアップの一助となれば、本メルマガも幸いです。

前回は、ディレクトリを登録するプロシージャを作成しました。今回はそのディレクトリの下に文書を作成(登録)するプロシージャ作成です。

そのプロシージャの名前は以下のようにします。前回のディレクトリ登録のプロシージャと同じような名前ですが、プロシージャ名の「DIR」というキーワードを「DOC」に変えただけです。

1
2
文書登録フォーム  DOC_DOC_MAKE
文書登録処理      DOC_DOC_MAKE_EXE

以下は文書やディレクトリを格納するDOCS表です。

SQL> SHOW USER
ユーザーは"SCOTT"です。

1
2
3
4
5
6
7
8
9
10
11
SQL> DESC DOCS
  名前           NULL ?    型
  -------------- -------- ----------------------------
  ID             NOT NULL NUMBER           --番号(主キー)
  TITLE          NOT NULL VARCHAR2(300)    --タイトル
  KBN            NOT NULL NUMBER           --区分1:文書 2:ディレクトリ
  HONBUN                  CLOB             --本文(文書のときのみセット)
  OYA_DIR                 NUMBER           --親ディレクトリ
  SEQ                     NUMBER           --ディレクトリ内の順序
  INSERT_DATE    NOT NULL DATE             --登録日
  UPDATE_DATE    NOT NULL DATE             --更新日

文書登録フォーム「DOC_DOC_MAKE」プロシージャですが、以下のような内容で作成しました。 (注意)以下のソースコードはブラウザ表示のために、山括弧(「<」と「>」)を全角にしています。 コピーして実行する方は、必ず、すべての山括弧(「<」と「>」)を半角に変換してください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
CREATE OR REPLACE PROCEDURE DOC_DOC_MAKE
IS
  V_ERRMSG  VARCHAR2(500);
BEGIN
/*****************************************/
/*         文書登録のためのフォーム画面  */
/*****************************************/
   HTP.P( '<HTML>' );
   HTP.P( '<HEAD><TITLE>文書登録</TITLE></HEAD>' );
   HTP.P( '<BODY>' );
   HTP.P( '<H1>文書登録</H1>' );
   HTP.P( '<HR>' );    -- 横線
   HTP.P( '<FORM ACTION="doc_doc_make_exe" METHOD="POST">' );
   HTP.P( '<TABLE BORDER>' );
   HTP.P( '<TR><TD BGCOLOR="LIGHTYELLOW">親ディレクトリのID</TD><TD>' ||
   '<INPUT TYPE="TEXT" NAME="P_OYA_ID" SIZE="8"> (必須)</TD></TR>' );
   HTP.P( '<TR><TD BGCOLOR="LIGHTYELLOW">表示順番</TD><TD>' ||
   '<INPUT TYPE="TEXT" NAME="P_SEQ" SIZE="8"> (同じディレクトリ内の表示順)</TD></TR>' );
   HTP.P( '<TR><TD BGCOLOR="LIGHTYELLOW">タイトル</TD><TD>' ||
        '<INPUT TYPE="TEXT" NAME="P_TITLE" SIZE="60"></TD></TR>' );
   HTP.P( '<TR><TD BGCOLOR="LIGHTYELLOW" COLSPAN="2"><CENTER>本文</CENTER></TD></TR>' );
   HTP.P( '<TR><TD COLSPAN="2">' ||
        '<TEXTAREA NAME="P_HONBUN" rows="15" cols="100"></TEXTAREA></TD><TR>' );
   HTP.P( '</TABLE>' );
   HTP.P( '<INPUT TYPE="SUBMIT" VALUE="送信">' );
   HTP.P( '</FORM>' );
   HTP.P( '</BODY>' );
   HTP.P( '</HTML>' );
EXCEPTION
   WHEN  OTHERS  THEN
      V_ERRMSG := SQLERRM;
      HTP.P(V_ERRMSG);
END  DOC_DOC_MAKE;
/
 
プロシージャが作成されました。

このフォーム画面をブラウザに表示してみましょう。

バックナンバー 第103回「WEBアプリ作成(1) (Oracle DBとPL/SQLだけで、即、WEBアプリ)」と同等の設定ができている方は以下のURLで表示できます。

http://localhost:8080/dad/doc_doc_make

ログインを求められたら、SCOTTユーザでログインしてください。

ご覧のようにこの文書登録のフォーム画面は、前回(第121回)のディレクトリ登録のフォーム画面とよく似ていますね。というのは、さらにその前回(第120回)でこのシステムの基本的な考え方として「ディレクトリとは本文のない特殊な文書である」とみなしているからです。
その考え方の通り、文書登録のフォーム画面とディレクトリ登録のフォーム画面の実質的な違いは、「本文」があるかないかだけです。

この文書登録画面の「本文」のパラメータ名は、「P_HONBUN」です(ソースコード23行目)。この本文の記述は23行目にある通り、TEXTAREAタグですから、改行を含む大量の文字データを入力できます。その他の項目は前回のディレクトリ登録のフォーム画面と同じですから、結局このフォーム画面は以下の4つのリクエストパラメータを持ちます。

1
2
3
4
親ディレクトリのID  P_OYA_ID
表示順番       P_SEQ 
タイトル       P_TITLE
本文         P_HONBUN

そしてこれらのパラメータの送信先が、FORMタグのACTION属性である「doc_doc_make_exe」プロシージャです(13行目)。
このプロシージャが受信したパラメータを使って文書登録処理を行うわけです。しかし、現時点ではこのプロシージャはまだ作成していませんので、送信ボタンを押してもエラーとなります。

その文書登録処理プロシージャ「DOC_DOC_MAKE_EXE」を以下のように作成しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
CREATE OR REPLACE PROCEDURE DOC_DOC_MAKE_EXE
(  P_OYA_ID  IN VARCHAR2,
    P_SEQ     IN VARCHAR2,
    P_TITLE   IN VARCHAR2,
    P_HONBUN  IN VARCHAR2)
IS
  V_ID        NUMBER;
  V_OYA_ID    NUMBER;
  V_SEQ       NUMBER;
  V_ERRMSG  VARCHAR2(500);  --エラーメッセージ用変数
  ERROR01     EXCEPTION;
BEGIN
/*****************************************/
/* 文書登録の実行処理            */
/*****************************************/
--
/***********************************/
/*親ディレクトリ(親ID)のチェック   */
/***********************************/
   V_OYA_ID := TO_NUMBER(P_OYA_ID);   -- 親IDが数字かどうかのチェック
   IF V_OYA_ID IS NULL  THEN
      V_ERRMSG  := '親ディレクトリのIDは必須です' ;
      RAISE  ERROR01;    -- エラー処理へ
   ELSE  -- 親IDがセットされている場合はそれが存在し、ディレクトリ(KBN=2)であること
     DECLARE  -- ネストブロック
        V_KBN  NUMBER;
     BEGIN
        SELECT  KBN INTO V_KBN FROM DOCS WHERE ID = V_OYA_ID;
        IF V_KBN = 2 THEN
           NULL ;     -- ディレクトリであればOK
        ELSE         -- ディレクトリではない(つまり文書:KBN=1)のときはエラー
           V_ERRMSG := '親ディレクトリのIDは、ディレクトリでなく文書です' ;
           RAISE  ERROR01;  -- エラー処理へ
        END IF;
     EXCEPTION
        WHEN NO_DATA_FOUND THEN   -- 存在しない場合もエラー
           V_ERRMSG := '指定された親ディレクトリのIDは存在しません' ;
           RAISE  ERROR01;   -- エラー処理へ
     END ;
   END IF;
/**********************************/
/* 表示順(P_SEQ)のチェック        */
/**********************************/
    V_SEQ  := TO_NUMBER(P_SEQ);   --P_SEQが数字であることのチェック
    IF V_SEQ IS NULL THEN
       NULL ;                      -- 表示順はNULLでもOK
    END IF;
/**********************************/
/* タイトル(P_TITLE)のチェック    */
/**********************************/
    IF P_TITLE IS NULL THEN
       V_ERRMSG := 'タイトルがセットされていません' ;
       RAISE ERROR01;    -- エラー処理へ
    END IF;
/**********************************/
/*  本文(P_HONBUN)のチェック      */
/**********************************/
    IF P_HONBUN IS NULL THEN
       V_ERRMSG := '本文がセットされていません' ;
       RAISE  ERROR01;    -- エラー処理へ
    END IF;
/*********************************************************************/
/* もろもろのチェックがOKであれば次にデータ登録処理                  */
/*********************************************************************/
-- 主キーを生成する (簡単ですが、非推奨の方法です。(前回(No.121)参照)
    SELECT NVL( MAX (ID),0) + 1 INTO V_ID FROM DOCS;
-- DOCS表にINSERTする
    INSERT INTO DOCS(ID, TITLE, KBN, OYA_DIR, SEQ, HONBUN,
      INSERT_DATE, UPDATE_DATE)
    VALUES (V_ID, P_TITLE, 1, V_OYA_ID, V_SEQ, P_HONBUN, SYSDATE, SYSDATE);
-- 1行操作されたことの確認
    IF SQL%ROWCOUNT = 1 THEN
       COMMIT ;
       HTP.P( '文書が登録されました ID = ' || TO_CHAR(V_ID));
    ELSE
       ROLLBACK ;
       HTP.P( '文書登録処理は異常です。処理を取り消しました' );
    END IF;
EXCEPTION
   WHEN  VALUE_ERROR THEN
         HTP.P( '親ディレクトリ、表示順番に数値でない値がセットされています' );
   WHEN  ERROR01 THEN
       HTP.P(V_ERRMSG);
   WHEN  OTHERS  THEN
      V_ERRMSG := SQLERRM;
      HTP.P(V_ERRMSG);
END  DOC_DOC_MAKE_EXE;
/
 
プロシージャが作成されました。

これも前回(第121回)、掲載したディレクトリ登録処理プロシージャ DOC_DIR_MAKE_EXEと似ていますね。
ではディレクトリ登録処理と違う点を解説します。

まず21~23行目ですが、親ディレクトリのIDは必須としています。前回のディレクトリ登録処理では、最上位ディレクトリであればその親ディレクトリは存在しないので、NULLを許可していました。しかし、文書の場合は必ず親ディレクトリを持つ必要があると、ルールを決めてあります。ですから、親ディレクトリのIDがNULLであればエラーとしているわけです。

次に本文がNULLだとエラーにしています(58~61行目)。これも文書である限りは本文を持つとルールを決めたので、その通りのチェックを行っているわけです。

そして、DOCS表へのINSERT文(68~70行目)に、当然、本文(HONBUN列)が含まれているということと(68行目)、そしてKBNの値が「1」であること(70行目)が前回との違いです。本文は「KBN=1」であると決めたので、その通りに登録しています。

これでプロシージャがそろったので、早速、文書を登録してみましょう。
前回、私自身はディレクトリとして、ID=1とID=2のふたつを作成していますので、親ディレクトリのIDで入力可能なのは、私の場合、「1」か「2」です。では今回はそれを想定して、親ディレクトリのIDを「1」とします。
先ほどのフォーム画面に以下のように入力して送信ボタンをクリックします。

私の場合、ID=3 で文書が登録されました。

続いて、ID=3で文書が登録されたことを問い合わせで確認してみましょう。

確かに、指定した内容で文書として登録されたことがわかります。

今回はここまでにいたします。次回はこの文書をブラウザに表示するプロシージャを作成します。これにより最低限は使える(登録→表示)状態となります。

それでは次回、ご期待ください。

先頭へ戻る