サーブレット・JSP・Linuxメモ



2001年6月1日 0:32:13

変更は一行

さんざんエスケープシーケンスを取ってきて、その後ろの文字をなんて言っていたが、そんなことしなくて前のままのロジックでまったく問題なかった。
ただ一行「\」を「\\」に変換するという行を加えるだけだった。前回のソースに変更を加えた(UserEnteryBean.javaもクラスの名前を変えたので少し変更)

ログインユーザーのセッション管理

ちょい前にUserInfoクラスを拡張したが、これをトップのJSPページでscope=sessionで呼び出している。セッション管理するならばセッション変数にオブジェクトを入れて(?)行うのだが、これではやり方が違う。
明日は正統派の(?)セッション管理の手法にロジックを切り替えて行ってみる。


文字変換の改善

今日はGT3をついついやってしまい、Javaはほぼノータッチ(#^.^#)

文字変換の流れとしてやはり、\マークの検出を行い、その後の文字をチェックする。それぞれ変換すべき文字に変換して、それ以外の場合はもう一つ\を追加する(文字の中に\という文字を入れていた場合に\\と重ねる処理)

\マークの検索はvalue.indexOf(target, newpos)で見つかった場所を返してもらう。
次の文字を取得する(何かメソッドがあるはず)
しかたないけど、エスケープシーケンスごとにifを書きまくり(いい方法ないかな?)。そして、replacer変更版(座標指定で置き換え対象を選ぶようにする?)を実行して文字を置き換える。
どれにも当てはまらなければ\\とする。

だいたいの流れはこんな感じで明日作ってみる


2001年5月27日 14:35:24

文字置換

特殊文字の関係でDBに書き込むときだけ文字変換をしなくてはいけなくなった。
以下を参考に作ってみようと思う。

http://www11.u-page.so-net.ne.jp/ga2/no-ji/reseach/20000128.htm

ふう、かなり時間がかかった。余計お手本に惑わされてしまった感じだ。元のプログラムが悪いというのではなくて、目的とする動作が違うのに、真似して作ろうとして時間がかかってしまった。でも、基本の部分は参考にさせてもらいました。
なんとか、特殊文字(エスケープシーケンス)がDBに入るようになった。ソースは5/25の流れの中にリンク張りました。
セキュリティーに問題があると言っていたのは、ソースを見ると察しがつくと思うが、フォームの中に「'」なんかを入れるとDBにSQL文を送るときの文字列が途中で切られてしまうのだな。その後につづけて、SQL文を流してみると・・・、もしかしたら何か実行できるかもしれん。ただ、「'」と打っただけでなんらかのエラーは出る。それで、修正を加えて問題は解決しました(?)

エスケープシーケンス

今回、特定のエスケープシーケンスにだけ対応をおこなったが、よくよく考えれば、Javaのエスケープシーケンスは他にもいっぱいあるので、根本的にやり方を変えないといけない。今でも文字の中に\が入るとおかしな動作になると思う・・・と試しにやってみたら\を入れたら後に文字が受け付けられてない。やっぱり直さないといけないみたいだ。
\を見つけたら、その後の記号を調べて、適正な文字列に変更という感じで処理していかないといけない。
今のInputChkはまた別の用途で使えそうなので、取っておいて別にクラスを作ってみよう。

Cookieが日本語未対応

また、?????と表示されてしまいました。DBには日本語入ってるんだけどね。
とおもったら、?すら表示されなくなってしまった。cookieを見ると化け化け(T.T)
まず、フォームからデータを取り込むときに変数に入れる前にEUC->Unicode変換
それから、
クッキー書き込み時に・・

何もしない Tomcatに「8859_1,not support : あ」みたいな感じで一文字ずつエラー出力された
8859_1はUnicodeのことみたい。
Unicode->EUC 文字化け化け状態
Unicode->SJIS 文字化け化け状態
EUC->Unicode ??????のパレード
SJIS->Unicode ??????のパレード

という結果になる。この文字化けや?????はクッキーのファイルを直接開いて確認した結果。
本によるとCookieの値は基本的にASCIIになっているそうなので、名前はDBに管理させて、ただのIDと考えた方がよいのかなー。
本にはデフォルトエンコードさえ合っていればJava言語的には問題ないらしい。ためしに
-encoding EUC_JPをつけてコンパイルしてみる。

何もしない Tomcatに「8859_1,not support : あ」みたいな感じで一文字ずつエラー出力された
Unicode->EUC 文字化け化け状態
Unicode->SJIS
EUC->Unicode ??????のパレード
SJIS->Unicode

結果は一緒だった。だいたい、このエンコーディング指定はソース内の日本語に対する物だったと思う。
ログイン名と名前は別に持つことにしよう。本にも文字化けしてもおかしくないみたいなことを書いてあったし。
それにログインするときに日本語の長い名前は入力する方も面倒に違いない。

Cookie破棄方法

http://java-house.etl.go.jp/ml/archive/j-h-b/033379.html#body

ここにあるみたい。

Unicodeエスケープという方法

JavaにはUnicodeをASCIIコードだけで表記する方法がある。&uxxxxという感じになる。日本語が通らなくても、Unicodeエスケープに変換して、取り出すときも元に戻せばよい。時間があったら調べておきたい。
http://www.netpassport.or.jp/~wkimsan/ここにも詳しい説明有り。

UserInfoクラスの拡張・変更

uidとpassしか保持していなかったが、メールやホームページなども覚えさせて、各所ですぐに取り出せるようにした。まだデータはセットしてないけど・・・

データベース仕様変更

データベースにuidを追加。今までのユーザー名と同じで、今までのnameは掲示板などで使えるようにする予定の本当の名前(ニックネーム)にした。キーのidは名前が似て紛らわしいので、noに改めた。


2001年5月26日 16:11:36

トップページレイアウト変更

トップページは今、フレーム構成になっているがこれをやめるつもりだ。
なぜなら、別のフレームでユーザーのログイン状況などを管理させると、それが読み込まれる前にメインの画面でクリックされるとおかしなことになりそうだからだ。
最初にサーブレットを読む必要があるので、ダミーのindex.htmlからJava Scriptでリダイレクトしてサーブレットを読み、実際のインデックスに飛ぶようにするつもり。

リンクの変更が面倒だった・・・

リダイレクトさせたら案の定、URLがサーブレット実行のURLになっていて、あまり見栄えがよろしくない。ただし、index.jspとかだとエラーが出るのでとりあえずそのままにしておく。合わせて他もリンクを変更して、トップページに戻るときはindex.htmlを読み込みクッキーチェックから再度行うようにした。

パッケージ名の変更

これも下にパッケージの図を作ったりなんかしたのだが、変えてしまった。
構成はそのままだが、頭にnet.dynodns.atakをつけた。
自分のドメインを逆さまにして名前を付けると世界で唯一の名前になるのでそうした方がよいそう。みんなやってないみたいだけどね。
最初はnet.dynodns.a-takとしていたが、パッケージ名に「-」は使えないらしい。エラーが出て駄目だった。
全部コンパイルし直したので、面倒だった。やたらと名前長くなって打つのがちょい大変だし。

特殊文字の変更

Javaで特殊文字は\'とか\"で表現されているはずなのだが、なんか意図した動きをしていない。
フォームに「B\'z」と入れると、データベースでは「B'z」になっていて、クッキーではそのまま「B\'z」になっている。
文字列に展開したときに「\'」は「'」になっているのか?ちょっとややこしいな・・・。
もしかして、String変数の実体を渡しているのか参照として渡しているのかなんかが絡むのか?


2001年5月25日 21:15:46

AccessからPostgresqlのDBを扱う

DBのメンテナンスにもAccessは使えるというのは聞いていたが、PostgresqlにもODBCドライバがあるというのを同じ人から聞いた。googleで検索したらドライバがあった。
以下のサイトからダウンロードできる。

http://www.interwiz.koganei.tokyo.jp/software/PsqlODBC/

ドライバを解凍して、readme.txtに沿ってレジストリ登録して、コントロールパネルのODBCデータソース(OSによって名前まちまち)で追加でPostgresqlを選択。
接続するデータベース名とユーザー名とパスワードとホスト名はIPを入れておく。

そして、サーバーの/usr/local/pgsql/data/pg_hba.conf(環境によって違うかも)の中の最後に
host all 192.168.1.1 trust
というように接続を許したいクライアントのIPを設定する。
これでOK。デーモンの再起動もしなくて良いみたい。

Accessではテーブルのリンクを使ってテーブルを読み込む。実際、使ってみたが非常に楽。

cookieからの取得OK

構成を変えたら一発でOKだった

旧index.htmlのデザイン

top.jsp<--旧CookieChkをinclude
index.jsp

新index.htmlのデザイン

/servlet/login.CookieChk-->top.jspにforward
index.jsp

これで、Cookieに記録が残っていれば、ユーザー名とパスワードが自動的に入ってくるようになる。

ユーザー登録の流れ

  1. entering.htmで入力されたデータをEnteryサーブレットが受け取る
  2. EnteryサーブレットはUserEnterBean(ビーンの条件満たしてないけど・・・)を生成し、フォームデータを渡す
  3. UserEnterBeanはDbAccessのインスタンスを生成し、ユーザーが登録されているか検索し、無かったら登録する。
    ※登録する前にStringReplaceクラスで都合の悪い値をチェックすることにした(2001/5/27)
  4. Enterサーブレットは新規登録出来た場合は、CookieSendのインスタンスを生成しクッキーも同時に送信する。
  5. ユーザー登録の可否に対応するjspを表示する

トップページ表示時のクッキーチェック

  1. index.htmlCookieChkサーブレットを呼び出す。
  2. CookieChkはCookieServのインスタンスを生成し、クッキーの取得を行う
  3. UserInfoというユーザー名とパスワードを保持するオブジェクトを作成して、そこにデータをセットする。
  4. UserInfoビーンを属性にセットして、Top.jspを開く
  5. Top.jspは属性にセットされたUserInfoビーンを呼出し、フォームの初期値にする

パッケージ構成

パッケージ名 クラス名
web CookieSend
CookieServ
login CookieChk
Entery
UserEnterBean
UserInfo
db DbAccess

オブジェクト指向的作りになっていないような気がするが、MVCモデルを目指して(?)やってみた。Model、View、Controlの分担は出来た・・・・かな?
プログラム自体がまだまだなんで、こんなもんか。

今回、セキュリティー上問題がありそうな箇所があるので、ソースを公開してない部分があります(まあ、たいしたデータは無いのだけど)
次は、やっと実際にログインできる仕組みを作る。セッション管理も行っていく。
※とりあえず、問題解決したのでソースをリンクしました(2001/5/27)
 ただし、この後構成が変わったので整合性がとれてないかもしれません。


2001年5月24日 1:12:25

流れ変更

WebLogicのページを良く見たら、cookie作成の時や読み込みの時に使うRequestやResponseはservice()メソッドの物を使うと書いてある。読み込みの方はtop.jspからインクルードしているのだが、もしかしてこれではだめなのではないだろうか?
現にテストバージョンの方はサーブレットを直接起動してうまくいくのを確認している。

そんなわけで流れの変更。最初トップページ表示時にサーブレットを呼出し、クッキーを取得しJSPに渡すようにする。ビルダーで編集しづらくなるけどしょうがない。


2001年5月22日 23:20:58

その3 部品ごとに分けてテスト

しらみつぶしにやっても、問題点が絞れないので、方法を変えてみた。
問題と思われる部分のロジックのみを切り出して、個別にテストしてみる。
まず、Cookieの取得自体がうまくいっていない可能性があるので、そこから調べてみた。
結果はNG。
クッキーの中にnameという欄があるかチェックしており、見つかればその値を、見つからなければNotFoundを返すようにしたところNotFoundの表示。

いきなり原因発見。アホなことにクッキーの名前と値を逆に書いていた。
Cookie cookies = new Cookie(name, value);
のように名前、値と書くところを(普通そうだって)
Cookie cookies = new Cookie(value, name);
と逆に書いていたのだ。そりゃみつからん。
ブラウザのキャッシュファイルの表示でCookieファイルの中身を覗いてみて値が上に来ているのに気づいてわかりました。はぁ。

Cookieを探せない

テストプログラムではうまくクッキーの中を参照して値を出力できたが、今のプログラムではなぜかうまくいかない。ただ、少し前進してクッキーが見つからないときにGuestと表示する処理が行われていて、ユーザー名にGuestと表示されている。
ということは、クッキーがなぜか見つからないと言うことだ。
同じロジックのテストプログラムではうまく行くので、それ以外の部分に問題がありそう。
サーブレットからリクエスト情報をサーブレットに渡して、クッキーを取得するあたりに何か問題がありそう。
これは明日テストプログラムで試してみる。


2001年5月21日 23:24:41

サーブレット->Bean->JSPその2

なかなかうまくいかない。
今回、情報受け渡し用のUserInfoというクラスを作ったのだが、JSPから呼び出すと、
JasperException: R( + /top.jsp + null) Cannot find any information on property 'Name' in a bean of type 'login.UserInfo'
とエラーが返ってきている。

ちなみに呼び出すところは
<jsp:useBean id="cookie" scope="request" class="login.UserInfo" />
として、
<jsp:getProperty name="cookie" property="Name" />
で呼び出している。
Nameというプロパティーが無いと言っているようだ。

呼出し側のproperty="Name"を"getName"とかに変えても同じ結果なので、何かの原因でプロパティーが見えていないのかもしれない。

どこでうまくいっていないのか、なんらかの状態を段階段階で出力してデバッグしないといけないようだ。


2001年5月20日 20:01:19

肉じゃがの作り方(おいっ!!)

肉じゃが発祥の地・舞鶴のページより

http://www.city.maizuru.kyoto.jp/yokogao/nikujaga/niku.html

材料 生牛肉、蒟蒻、馬鈴薯、玉葱、胡麻油、砂糖、醤油 

所要時間
 1.油入れ送気
 2.3分後生牛肉入れ
 3.7分後砂糖入れ
 4.10分後醤油入れ
 5.14分後蒟蒻、馬鈴薯入れ
 6.31分後玉葱入れ
 7.34分後終了

サーブレット->Bean->JSPうまく行かず

Cookieの登録はうまくいったが、それを読み込む部分がうまくいかない。
読み込みはTop.jspでCookieChkクラスをインクルードし、このクラスはCookieServクラスを呼び出し、クッキーの値を取得させる。そして、CookieChkはCookieServクラスをJSPにそのまま渡しているつもりなのだが、どうもそのような動きになっていない様子。
CookieServがクッキーを読み込めていないのか、CookieChkで動かしたCookieServのインスタンスがうまく渡せていないようだ。
なぜかというと、CookieChkにJSPに渡す予定のクラス変数を定義しているが、コンストラクタにその変数に値を入れてあげると、JSPに表示されるのだ。
だから、元々データを読み込めていないのか、JSPでビーンを呼び出したときはまた新たなインスタンスを作ってしまっていて、CookieChkで作成したインスタンスは無くなっているかもしれないのだ。
だいたい、サーブレットをビーンのようにJSPに渡せるのか?このあたりも何か大きな勘違いしているのかも。
本のとおりにJSPとサーブレットの中間にどちらからも参照するクラスを作成するのがいいかもしれない。


2001年5月19日 22:01:06

FMV II S167のBIOSの表示させ方

起動時にctrl + alt + ESCを押す。
わかりづらい・・・。

サーブレットでCookieを使う方法

http://www.beasys.co.jp/weblogic/docs/classdocs/API_servlet.html#129071
ここにかなり詳しく説明してあります。

現在のカウンタの弱点またも発見

セッションはcookieかURLの二つのどちらかを使って実現するらしい。試しにクッキーをオフにしてトップページを何回も行き来していると、数字がどんどん増えていく。JSPからsessionで呼び出した場合はどうやらクッキーでセッション管理しているようだ。
それなら、ということで他のサイトも同じようにして見てみたが、なぜかどんどんカウントが増えていくことはない。URLに変な記述があるわけでもないので、URLでの管理ではないはずだが・・・。

Cookieはオンで・・・

Cookieオンの状態じゃないと、既に作ったセッションを見て処理をやっているプログラムはうまく動かないことが判明。基本的にCookieオンで、ログイン情報だけ記録するかどうか選択してもらうようにする予定。

本にいろいろ載ってたりして・・・

わからないことがあったらインターネットで調べていたが、既に購入済みの「サーブレット&JSPではじめる JAVAサーバーサイドプログラミング(技術評論社・原田洋子著)」にいろいろ書いてあった。JSPタグもインターネットで調べたが、よく見ていくとこの本に書いてある。
だって、この本難しいんだよね。すごく根底の動きまで詳しく書いてあるのから、深く知るにはいいのだけど、まだ自分がついて行ってない。

サーブレットのインクルードやimplementsやら多重継承が駄目なわけとか

上に書いた本にJSP<-->サーブレットのやりとりのことが書いてあった。その中にimplementsというのがあるのだが、これがいまいちわからない。他の本を読んだりするが、いまいちといったところだ。多重継承の代わりに用意されているものらしい。
JAVAは単一継承しかできない。あるクラスが複数のスーパークラスを継承(extends)することはできない。なぜなら、まったく関連性の無いクラスからいろいろ引っ張ってくると、複雑になるし、もし元のクラスを変えたりしたときはわけのわからないことになり得るからだ。
implementsはメソッドの中身は定義していないものらしい。名前はあるけど、中身は勝手に定義してねというもののようだが、いまいちピンと来ない感じ。
もう少し調べてみるかな。


2001年5月19日 1:18:49

dyndns.orgにIPを自動登録するには(PPxPの利用)

ddclientのダウンロード。http://www.dyndns.orgからクライアントのページへ飛べる。そこのリンク先にある。
それをtar vzxfで解凍。
その中のddclientを/etc/ppxp/rcにコピー。
sample-ddclient.confを/etc/ddclient.confとしてコピー

ddclient.confの編集
最初の方に
#login=your-login
#password=test
があるので、dyndns.orgのログイン名とパスワードを入れる。
あと、その下に
## dyndns.org dynamic addressとあり、
#your-dynamic-host.dyndns.orgという行があるので、ここも自分が取得したドメイン名に変える。

ppxpの設定
ダイヤルアップの設定ファイル(/etc/ppxp/conf)に以下の行を追加
set IP.START autocon

/etc/ppxp/ip/autoconの作成
/etc/ppxp/rc/dyndns.rc &
と一行書いて終わり。

/etc/ppxp/rc/dyndns.rcの作成
#!/bin/sh
IPADDR="`/sbin/ifconfig eth1|grep inet|sed 's/.*addr:\([^ ]*\).*/\1/'`";
/usr/local/bin/ddclient -ip $IPADDR -mx $IPADDR -refresh -retry -quiet
と書いてこれで終わり。

以上で、ダイヤルアップ時に自動的にIP登録を行ってくれるようになるはず?!

TCP Wrapperのログの取り方

etc/syslog.confに
local0.info /var/log/tcpwrappers(ログを記録する場所)
と付け加えた後、
/etc/rc.d/init.d/syslog restart
とするとTCP Wrapperでもログが取られるらしい・・・


2001年5月17日 23:35:49

クライアント側(Windows)での公開鍵の作成

http://kussharo.complex.eng.hokudai.ac.jp/ssh/ssh-howto-for-win.html

ここが詳しい。

しかし、断念。なんかうまくいかない。いくらパスを指定してもパーミッションがないとかいうし(Windowsなのに)

[DB]DBのフィールドの追加

http://www.dolphy.gr.jp/webap/env/backup.htm

ここが詳しい

pg_dump -D webdb > webdb.dump
と打ってまずバックアップをとる。postgresユーザーで行う。dumpの保存先もpostgresユーザーが操作できるディレクトリでないと失敗するぞ。
あとはダンプをviで加工。
次にDBを一度削除して(dropdb DB名)、同じ名前でcreatedb。
psql -e webdb < webdb.dump
これで復元して終了


2001年5月17日 2:14:45

OpenSSHとTCP Wrapperの設定

VineならばVineのページでFTPサイトからVine Plusのフォルダを見つけてopensshを探して、rpm -ivh openssh~もしくはrpm -Uvh openssh~と言う感じでインストールする。設定方法は日経Linux2001.5にも載っていた。
genkeyコマンドで公開キーと秘密キーを作成しておくのを忘れずに。あと、公開キーの登録も忘れずに。たぶん、サーバーすら立ち上がらないはず。
tcpwrapperでのアクセス制限はプロトコルはsshdを指定する。sshとか入れてもまったく利かないので注意。/etc/hosts.denyでsshd : ALLとして、hosts.allowの方で sshd : 許可するIPなど というようにsshでアクセスできる場所は限定しておく。
そういえば、inetd.confには記述がない。いいのだろうか?

ユーザー登録のIDについて

Accessにもオートナンバーみたいなのがあるので、あるとは思っていたがあった。
あの後、技術評論社の「Postgresql 完全攻略ガイド」を読んでいると、serial型という物があり、これはレコードを追加すると勝手に重複しない番号を振ってくれる型らしい。これで、ユーザーのIDの件は解決。今日は遅いので明日やってみる。


2001年5月16日 2:16:07

【登録部分完成!!】

ユーザー登録の部分が完成した。ただし、登録しても表示や削除もないしどこでも使っていないので、まだ意味はない。ただし、こちらでPostgresqlで確認するとDBにちゃんと登録されている。

引っかかっていた部分(INSERT文の書き方)

昨日の「,」の近くでエラーが出ているのは、INSERTする数値を「'」で囲んでいなかったため。囲むのは文字だけと思っていたので、引っかかっていた

引っかかった部分(getRequestDispatcher)

また、これでうまく飛ばなかったので、リンク先があるか確認したり、いろいろやっていたが、原因は
rd = ctx.getRequestDispatcher("/already_use.jsp");
RequestDispatcher
という部分ののctxがnullだったのが原因。
ctxにはServletConfig.getServletContext()から取り出せるコンテキスト(これについてはよくわかってない)を入れて置かないといけない。これはどうやら普通、サーブレットのinitメソッドに入れるようだ。
if(ctx == null) {
ctx = config.getServletContext();
}
initメソッドでこんな感じにしている。なぜNullを確認しているかはわからない。参考にしているサンプルがそうしてあったので、そのまま使っている。
あとは、上の実際にページを呼び出す前の段階で
RequestDispatcher rdでrdをRequestDispatcher型で定義しておけば良い。

問題発見

今、DBへのアクセス部分でロジックに問題を見つけてしまった。
ユーザー管理テーブルの主キーとなるIDがこのままでは重複した値を入れようとしてエラーが出る可能性がある。このIDは単純にテーブルのレコード数+1で新しいIDを作っていたが、レコードが削除されるとそれではまずいことになる。
何か他の方法でIDが重ならないように振れる方法を見つけなくてはいけない。


2001年5月15日 1:52:01

【ベースは完成】

ユーザー登録部分デバッグ

とりあえず作ってみたら、とてもひどく見にくいソースになってしまったので、作り直した。DBへのアクセス部分はクラスを分けて、別ファイルにした。多少オブジェクト指向らしい作りになった・・・・かも。
形は何となくできたが、まだ動かすとエラーが出る。sql文で「,」の近くでエラーが出ているとのことだが、おおざっぱなエラーしか出ないようにしているのでどこのことかよくわからない。sql文を画面で出力できればいいのだが。

throws節

今まで意味がわからなかったが、なかなか便利だ。
public void getvalue throws IOException {・・・
という感じで書いて、try{・・・}catch{・・・}でエラーとラップをかけるのは知っていたが、throwsを書いてtry・・・catchを書かないと、このクラスを呼び出した親メソッドでエラーが処理できるのだ。
親メソッドもthrows IOExceptionとして、try・・・catchを書くとエラー処理ができるが、親メソッドもさらにtry・・・catchを記述しないことで、さらにその親メソッドにエラー処理を任せることができる。
今回、サーブレットからビーンを動しているので、ビーンからは直接エラーはブラウザに出力できない(たぶん・・・・)。そんなときに、これを使うことで、ビーンを呼び出したサーブレットにエラー文をブラウザへ表示させることができる。

ただ、これを使うとどこでエラーが発生したかわかりづらくなるのが難点。今回もビーンのどこでエラーが起きたかわかりづらかった。

しかし、うまく使うことでエラー処理が簡略化できる。各クラスを部品化して使うということで考えると、親メソッドにエラー処理は任せた方がいいかもしれない。


2001年5月10日 2:05:43

【ログインシステム作成開始】

カウンター弱点もあり

完璧だと思っていたカウンターにも弱点がありました。というのも、アクセスカウンターのビーンはセッションごとにインスタンスができて、そのセッションが無くなるまで、サーバーで生き続けるので、同時にこのページを見ている人が10人いれば、10個のインスタンスが常駐することになってしまうのです。だから、更新ボタンを押してもカウントアップされないのですが。
他のカウンターはそれを防ぐために、おそらくセッション変数か何かにカウントアップしたかどうかを記録しているのではないかと思います。んー、でもセッション変数と言うぐらいだから、やっぱり更新押してもクリアされないような(カウントアップしない)気がする・・・。
まあ、そんなにアクセス数が多いわけではないので、とりあえず現状のままにしておきます。

ユーザー登録ページ作成

ユーザー登録ページのデザインはできました。必須入力の項目を入れてないとエラーが出るようにJava Scriptも使ってみました。フォームに入力したデータを受けとり、Beanに処理を流すサーブレットも一応大枠ができました。
あとは、ビジネスロジック部分のBeanを作ります。ビジネスロジックとしてはサーブレットから受け取ったフォームデータを元にPostgresqlにアクセスし、同じユーザーが登録されていないかのチェック。名前とメールでチェックをかける予定。そして、実際のDBへの登録をし、サーブレットに可否の戻り値を返す動きになる。今は、ただDBアクセスのソースを持ってきただけで、手をつけていない。明日、やってみる。


2001年5月8日 20:56:54

【カウンター改良】

その前にちょっとメモ。

セッションのタイムアウトの設定方法

web.xmlセッションのタイムアウト時間を設定することができます。web.xmlで設定するタイムアウト時間は分単位

<session-config>
  <session-timeout>60</session-timeout>
</session-config>

セッションが続く限り再度カウントしない

今のカウンターは一度他のページにリンクして、またカウンターのページに戻ってくるとまたカウントがひとつ増えてしまう。一般に見られるカウンターは一度の訪問で一度きりしかカウントアップしない。

Beanにそのロジックを入れてみる。思いついたのが、counterビーンはJSPからscope=sessionで呼ばれている。このBeanはセッションが続く限り生き続けるわけだ。ならば、こいつにカウントアップ既にしたかどうかの変数を持たせて、カウントアップするdoGetメソッドが呼ばれたときに、それをチェックするようにすればいい。セッションが切れればその変数もろともビーンは消滅するので、再度訪問したときはまたカウントアップするはずだ(もしかしたらみんなこんな風にしているのかもしれないけど・・・)

コーディングしてみた。意外にもほぼ一発で思惑通りの動きに。いや、予想以上の動き。というのも、普通ブラウザの更新ボタンを押したら、カウンターが増えていくがそれも無い。いいぞ。せっかくだからソース公開。

アクセスカウンター(Bean)

/**
==================================
アクセスカウンター written by A-tak 2001/5/6
http://a-tak.com  a-tak@geocities.co.jp
JSPに<jsp:useBean scope="request" id="count"  class="web.Counter" scope="session"/>で定義
<%=count.doGet() %> で呼び出す
カウンターを記録するテキストファイルを前もって作っておく。ファイルの場所はソース内のFileNameに指定。
==================================
*/
package web;

import java.io.*;
import java.util.*;
import java.net.*;

// counter
public class Counter {

    int counter = 0;                                            //カウンター用変数
    final String FileName = "/usr/local/tomcat/counter.txt"; //カウンター書き込みファイル名。
        String result;
        boolean up = false;

        //doGet
        public String doGet(){
                if (up == false) CountUp(); //まだこのセッションでカウントアップしていなければ、CoutUpへ

                return result;
        }
        
        //CountUp
        private void CountUp() {
                try {
                BufferedReader reader = null;

                reader = new BufferedReader( new FileReader( FileName ) );

                String line = reader.readLine();
                if (line != null){
                        counter = Integer.parseInt( line );
                }else{
                        counter = 1;  //行が空だった場合1を入れておく
                }
                
                //カウンタープラス
                counter++;

                //ファイル書き込み
                PrintWriter file_write = new PrintWriter(new FileOutputStream( FileName ));
                file_write.println( counter );
                file_write.close();
                result = Integer.toString( counter );   //resultはここでString result = ...としてはエラー処理のところでエラーが出る。
                } catch( IOException e ){
                result = e.toString();
                }
                up = true;
        }
}

アクセスカウンター(JSP)

<BODY>タグの前に以下の行を追加

<jsp:useBean id="count" class="web.Counter" scope="session"/>

classは便宜自分の環境に合わせること。scopeはsessionにしておかないと正しく動作しません。
あとは、カウンターを入れたい所に以下のように書き込めばCounterのBeanを呼び出して表示します。

<P>あなたは <%=count.doGet() %>人目の訪問者です</P>

こんな感じです。前もって、所定の場所にカウンターを記録するテキストファイルを作っておく必要があります。
そうしないとたぶんエラーが出ます。ファイルの作成までは今回やらなかった(#^.^#)。
カウンターがテキストで寂しい場合は、数字をgifで用意してグラフィカルなカウンターを作るのも良いでしょう。数字がアニメーションでカウントアップするやつとか。A-takはとりあえず、やりません(笑)。綺麗なロジックの書き方の練習にはいいかもしれないけどな。
次はログインシステムを作ってみるぞ。


2001年5月7日 23:29:42

【カウンター一応完成】

JSPとサーブレットとビーンのうまい使い分け

カウンターは作成終わり。
どうも、サーブレットとビーンの使い方を混同していたようです。ここにうまい使い分けが書いてありました。リンクコーナーにも置いてあったけど、今になってやっと意味がわかった感じ。

JSPは表示を担当して、Servletはデータを受け取って、それをJSPやBeanに渡す役目、Beanはとにかく計算などの処理を行うという分け方をする。今回はJSPから直接Beanを呼び出してデータをテキストでそのままもらっているので、サーブレットはない。これから作る予定のログインの仕組みはJSP(HTML)からサーブレットにデータが渡り、ビーンで処理をして、JSPに結果を渡す。または、Beanオブジェクト自体をサーブレットがJSPに渡したりする(セッションごと、ようするに見に来た人ごとにオブジェクトを管理できる)。
こういう構造なので、サーブレットはHttpServletクラスを継承してリクエストやレスポンスが返せるようになっているし、Beanにはそれがないのだ。


2001年5月7日 1:08:30

【引き続きアクセスカウンター】

とりあえず、できたのだが問題あり。一つはTomcatを再起動するとカウンターがリセットされてしまうこと。保存ルーチンを昨日見つけたサンプルから持ってきているが、働いていない様子。
昨日のサンプルは、
public class Counter extends HttpServlet {
というように、HttpServletクラスを継承している。実は今回のBeanはこれを継承していない。なぜかというと他のもっと簡単なサンプルは継承していなかったからだ。試しに継承させると今度はコンパイル時にエラーが発生する。もうちょっと調べる必要有り。

おそらく、HttpServletを継承していないので、初期化(init)や保存ルーチン(destroy)が動かないと思われる。これらはサーブレットが読み込まれたときと終了したとき(サーブレットコンテナの終了など)に実行される。

もう一つの問題はトップページを行ったり来たりするだけでカウントが増えていくこと。セッション管理を使うらしいが、どのようにすればいいのか?考えればいろいろ考えつくが、どれがベストなんだろう。


2001年5月5日 18:47:34

【カウンターをつくってみよー】

カウンターを作るためにインターネットからサンプルのソースを持ってきてみた。
どうやらこのカウンターはURLごとに記録をとり、サーブレットとして直接呼び出すことで使えるようなので、今回のようにJSPからBeanとして呼び出して、カウントアップさせていくような使い方には向いていない様子。
これを元に作り直すことにする。ちなみに、サンプルにいくつか気になる命令があったので、調べた結果を書いておく。

synchronizedとは?

よくわからないが、ロックを行うらしい。同時に複数のスレッドが同じ変数に値を書き込んだときなどsynchronized指定しておくことでロックされて正しく処理されるということらしい。

ここの同期の部分がわかりやすい(参照)
こっちは補足で読む(参照)
他の運用方法もあり(参照)

thisとは?

thisはインスタンスの変数を指定するときなどに使う。同じ名前でインスタンス変数とローカル変数(メソッド内の変数)が存在すると、ローカル変数が優先される。たとえば、引数でもらったhensuuというローカル変数の値を同じ名前のhennsuuというインスタンス変数に代入する場合は、this.hensuu = hensuuという書き方をする。
synchronized(this)というのはたぶん、インスタンス変数は同期させるという意味なのだろうか?


2001年5月5日 17:13:34

【前回の問題】(RequestDispacererの注意点)

GNUJSP + JServでうまく行かなかった部分だが、Tomcatでもうまくいかない。
ただ一つだけまずい所はみつかった。
RequestDispatcher rd = ctx.getRequestDispatcher("../jsp/Login2.jsp");
の行だが、getRequestDispatcherメソッドのパラメータは最初に"/"がこないといけないそうだ。(参照)
そして、sendRedirectというものもあり、これならば先ほどのようなURLを書いても良いらしい。
試しにred.sendRedirect("../jsp/hello.jsp")としてみたが、同じエラーが出た。使い方が間違っているのかも。

RequestDispatcher rd = ctx.getRequestDispatcher("/Hello.jsp");
試しにこんな風にしてみた。なんと、今まで変なエラーが出ていたのが、Not Foundのエラーが出るようになった。
さっきはありもしないファイルを指定してもこのようなエラーは出なかった。

・・・と思ったが、今度はさっき一度試してみた
RequestDispatcher rd = ctx.getRequestDispatcher("/jsp/Login2.jsp");
をやってみたら、先に進んだ!!なぜ?!

なんだかよくわからないが、先に進む。
今度はLogin2.jspでエラーが出ている。

いろいろいじったが原因がわからん。コードはサンプルのものそのままだし(#^.^#)

TomcatとWebサーバー再起動。無事動作。おい、そんなものなのか?
なんかTomcatもちょっと不安だな。それとも、オレのサーバーマシン(48MB)が危ないのか?

今回のポイント:
不思議なエラーが出たらTomcat + Apache を再起動!!


2001年5月5日 10:50:10

【サーブレットも起動】

どうやらURLの指定が間違っていた様子。
Tomcat--webapp--WEBアプリ名--WEB-INF--classes以下のサーブレットにアクセスする場合は、
http://ドメイン名/WEBアプリ名/servlet/サーブレット名とすると良い。

このあたりの設定はTomcaのmod_jk.confに
JkMount /servlet/* ajp12
となっているところが関係あるみたい。

自由にいろいろ設定したい場合は、これに加えて、
web.xml で
<servlet-mapping>
<servlet-name>test.ServletTest</servlet-name>
<url-pattern>/Foo/map</url-pattern>
</servlet-mapping>

と書いていくらしい。(参照)

自分はこの方法はとってない。
以下の用にserver.xmlを設定した。ついでにTomcatのwebサーバーの停止も。

server.xmlの内容(かなり略)

TOMCATのHTTPサーバーは使わないのでコメントアウト

      <!-- ==================== Connectors ==================== -->
        <!-- Normal HTTP -->
<!--
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler" 
                value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
            <Parameter name="port" 
                value="8080"/>
        </Connector>
-->

Context pathに"/"を指定することで、webデータのある所全部でjspが使える
htmlフォルダの直下にWEB-INFを置いてある。

        <!-- ==================== Special webapps ==================== -->
        <Context path="/"
                docBase="/home/httpd/html"
                debug="999999999"
                reloadable="true">
        </Context>      


    </ContextManager>
</Server>

mod_jk.confの内容

*/.jsp となっているので、ルートフォルダ以下すべてでjspファイルが使える。
サーブレットに関してはservletというパスがつくことになる。

LoadModule jk_module modules/mod_jk.dll

<IfModule mod_jk.c>

JkWorkersFile <fill-path-to>/workers.properties
JkLogFile  logs/jk.log
JkLogLevel warn
JkMount /*.jsp ajp12
JkMount /servlet/* ajp12

</IfModule>

web.xml

どうも、これは設定しなくても良いみたい。WEB-INFのclassesに入れてあれば、ここに登録しなくても使える様子。

<web-app>
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>hello</servlet-class>
  </servlet>
</web-app>

使用するjarなど

postgresqlにアクセスするためのpostgresql.jarはJServではwrapper.class.bin(?)かどっかにパスを書いたと思うが、TomcatはWEB-INF/libの中に入れておけば、勝手に参照してくれる。便利。

これで、やっとすべての環境が揃った!!やっとプログラムに移れるぞ。


2001年5月3日 10:34:13

もしかしたらApacheのディレクトリ設定がいるのかも。
それと、JSPをHTMLフォルダの下に入れて試してみる。


2001年4月30日 22:34:23

【本日二度目の挑戦】

なにげにWebで探して、ルートにindex.htmlを置いたりしてみようと思ったら、いつの間にかエラーは起きなくなりました。index.htmlは無くてもエラーが起きないので何が原因なのかさっぱりわかりません。絶対、後でつまづくな。GNUJSPの時のように。

ただ、登録しているhelloサーブレットがNotFoundになってしまう。

起動しているときに、昔設定したGNUJSPなどのパスが表示されるのが気になるが。

試しにbaseDocの場所に*.jspファイルをコピーしてみた。すんなり表示された。サーブレットだけの設定が存在するのか?


2001年4月30日 15:56:14

【Tomcat起動!!】

Tomcatの設定

前回の設定で間違いがあった。
mod_jk.soの保存先はmoduleではなく、指示通りapacheの下のlibexecの下に入れなくてはいけない。フォルダがなかったら、libexecを作ってその中に入れる。このパスはおそらく、後から出てくるTomcatが作成するmod_jk.conf-autoの中にパスが書いてあるようだ。このTomcatが作成するファイルも本ではmod_jk-autoになっていたので、環境やバージョンによって違うのかもしれない。
それと、パスが長すぎて面倒だったので、Tomcatのインストール先も変えた。/usr/local/tomcat以下に環境を置いた。

まず、Apacheにアドオンするための設定を書く。
httpd.cofnの一番最後の行にでも記入

include /usr/local/tomcat/conf/mod_jk.conf-auto

これがさっきのパス。中にはjspの拡張子のファイルへのリクエストが来たときのApacheの処理を書いてある。これはTomcatが勝手に作成してくれるファイル。

自分が使っている環境では実はもうこれだけ設定は終了。
あとは、まずTomcatを
/usr/locatl/tomcat/bin/tomcat.sh start
で起動させて、Apacheも
/etc/rc.d/init.d/httpd start
で起動すれば終わり。
Tomcatは最後まで終了しても、なぜかプロンプトまで戻らないようだが、Enterを押せばプロンプトが出る。ちゃんと動いているのかちょい心配だが、これでサンプルを動かすとちゃんと動くのでOKなのだろう。

本当はAPJ13というTomcat用の最新プロトコルを使いたいが、なぜか本の通りに設定してもエラーでまくり。なんでやねん。
とりあえず、突き詰めるとまた収集がつかなくなりそうなので、このぐらいにしてプログラムをやっていきたいと思う。
だいたい、このサイトのアクセス数なんてたかがしれているので、わざわざパフォーマンスの良いAPJ13は使わなくてもいいかもしれん。

とりあえず、今まで作ったサーブレット、JSPが動くようにする。
server.xmlに設定を書き込むと良いらしい。

【server.xml】
<Context path="/j-ap"
    docBase="/home/httpd/html"
    debug=0
    reloadable="true">
</Context>

としてみたが、Tomcatの起動時にJavaのコンパイルエラーのような物がずらずらと出てくる始末。
どういうこっちゃ。
docBaseをTomcatのサンプルがあるフォルダに変えて、WEB-INFの中にweb.xmlを入れたけどダメ。
web.xmlの中身は

【web.xml】
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
    <servlet>
        <servlet-name>
            hello
        </servlet-name>
        <servlet-class>
            hello
        </servlet-class>
    </servlet>
</web-app>

いろいろやってみた
Tomcatのwebappの下にonpcというフォルダを作り、web.xmlに上のContextの指定のみ入れた→ダメ
上の状態でweb.xmlをexamplesの中の物と入れ替えた→エラーは出なくなった。もちろんサーブレットは動かない。
上のフォルダの中身を/home/httpd/htmlに移して、server.xmlのdocBaseも書き換えた→エラー。
webappの中でまず動くようにする。その前に試しに、server.xmlはそのままで、webappにonpcフォルダを作って動かしてみる→エラー
もしかするとserver.xmlの設定が悪いのか?
server.xmlの設定をコメントアウト→エラーなし
web.xmlの一番材呉に追加で設定を書き込んでみる。もしかしたら、必要な物まで消していたかもしれない。→
「at Illigal character at end of document, &#x3c;.」こんなエラーが出た。
最後の改行を消したが同じ結果。もしかしたTABがまずいとか・・・・→消しても一緒
試しに追加した部分をコメントアウトしたら→動く
もしかして、追加した部分だけ文字コードが違うとか、最初の行に文字コードが指定してあるEUCの文字コードではない!
他の行をすべて消し、文字コード指定も削除すると→OK!!

server.xmlにonpcフォルダを登録したが→エラー
また文字コードかと思い、一行目の文字コードを削除し、秀丸でEUCで保存してみるがダメ(この方法ではダメかもしれないが)。ただ、さっきのようなエラーではなく、javaのエラーみたいなのがずらずら出ているので、原因は違うような気がする。

コンパイルに使うときのjarが違うからかもしれないので、tomcatのjarを使いコンパイルし直してみる→エラー

jaspet.logファイルを見ると、いつのまにか「Scratch Dir for JSP Engine is : /usr/local/tomcat/work/localhost~」というエラーが出ている。ここをのぞいてみるとサンプルのJSPファイルがコンパイルされている場所だ。なんでねここをなんか言っているんだ。もしかして、サーブレット名が重なっているとか?→×
server.xmlで他のサンプルをコメントアウトしたが一緒だった。
もしかすると、ここでコメントアウトするだけでは意味がないのかもしれない。
とりあえず、今日は終わり。


2001年4月28日 22:21:15

【JServ廃止!!】

突然だが、廃止だ。
理由の一つに、前回から続いている「バージョンの違いらしき問題でエラーが起きている」ってこと。どうもGNUJSPがサーブレットAPI2.1に正式に対応していないのではと思うわれる情報がネット上であった。だからといって、古いバージョンのAPIしか使えないのは、ちょっと・・・
しかも、これからはTomcatがJServの後継になっていくということで、つまりはJServはバージョンアップしないということ。
それに、GNUJSPはGNUJSPに付属されているサーブレットAPIを使わないといけない。たぶん、サーブレットのバージョンが上がったらGNUJSPを作った人たちがそれに手を加えて、新しいバージョンをつくっているのであろう。それはなんか気持ち悪い。

そんなわけで、Apache + JServ + GNUJSPの組み合わせはやめて、Apache + Tomcatでやっていくことにした。
Tomcatは以外と設定が簡単そうだし。
まず、今使っているJServを無効にする方法を試してみて、以下の方法でエラーが出ずに無効にすることができた。

JServを無効にする方法

httpd.confを編集する
#LoadModule Jserv_module module/mod_jserv.so

#AddModule mod_jserv.c
このように、上の二行を#でコメントアウトすれば良いようだ。
Apacheのバージョンによって違うかも。

Tomcatインストール

まずはTomcatのインストール。Apacheのインストールは省略。
以下のサイトからダウンロードする。
今回はTomcatの3.2.1バージョンを使用した。新しいバージョンはJakarta Projectのページから入手できる。

Jakarta Projectのページ
http://jakarta.apache.org/
Tomcat 3.2.1のダウンロード先
http://jakarta.apache.org/builds/jakarta-tomcat/release/v3.2.1/bin/

たぶん、jakarta-tomcat-3.2.1.tar.gzがTomcatのファイルなので、これをダウンロード。
jakarta-servletapi-3.2.tar.gzというのもあるので、よくわからないがダウンロードしてみた。
Linux/i386フォルダの中のmod_jk.soも必要なのでダウンロード。

インストール方法は、技術評論社の「Javaサーバーサイドプログラミング(原田洋子著)」を見ながら進めた。
The Ja-Jakarta Projectにインストール方法などのドキュメントがあるらしいが、今日はつながらなかった。サーバー障害かな?

Tomcatは
tar zxfv jakarta-tomcat-3.2.1.tar.gz -C /usr/local/jakarta
でうまくいった。後ろのパスはTomcatのインストール先。

ApacheにTomcatをアドオンするためのmod_jk.soはさっきダウンロードしてきたので、これを使えばいいはずだが、apacheをインストールした先のlibexecにコピーすれば良いそうだが、そんなディレクトリは無い。
本ではコンパイルしているので、mod_jk.soはコンパイルしてみるが、いつものごとくエラーが出てうまくいかないし、makeファイルを見ても特にconfファイルに何か手を加えている様子はないので、どこかにコピーすれば良いのだろうが。とりあえず、モジュールファイルが入っている/etc/httpd/modulesの中に入れてみる。

次はtomcatの設定ファイルを書いていくことにする


2001年4月25日 23:00:05

Jserv.confの
ApJServAction .jsp /html/jsp/gnujsp
の設定がよくわからんと思っていたら、たまたまこんなことが書いてあった。
「GNUJSP 自体が、 Java Servlet なので、 /serlet/gnujsp と設定するんです。 .jsp があるたびに、Servlet である GNUJSP を起動するんですね。」
なるほどね。

APIの仕様だがやっぱりちがうかもしれん。
http://www.atmarkit.co.jp/fjava/special/servlet01/jservlet03.html
servlet-2.0.jarとなっているので、ここに書いてあるバージョン2.0以前に当てはまるのでは?
ということは呼び出しかたが違うので、さっそくHttpServiceResponse.callPage("../jsp/login2.jsp");としてみたが、文法が違うのか同じエラー。

結局、ソースを変えるのではなくjarのバージョンを2.1にあげることにした。gnujspのlibにservlet-2.1.jarというのがあったので、これをWindows環境に持ってきてこれを使ってコンパイルするとノーエラー。
Linuxも同じように2.1を使うように指定して、例のページを見るがブラウザにエラーが出ている。
Jserv.logを見ると相変わらず29行目で「AbstractMethodError」というのが出てる。
今度は、これを調べてみる。


2001年4月24日 23:29:12

試しにjserv.propertiesのwrapper.classpathの指定を元々のservlet-2.0.jarに戻したところ、結局同じエラーが出た。ということは、jarの問題ではない。
もしかすると、単純な記述ミスかもしれないので、ソースを再チェック→特にへんなところはなさそう。たぶん(^_^;

APIドキュメントの見方でわかったことがあるので、メモ。

Method Summary
 java.lang.Object getAttribute(java.lang.String name)
          Returns the servlet engine attribute with the given name, or null if there is none.
 java.util.Enumeration getAttributeNames()
          Returns an Enumeration containing the attribute names available within this servlet context.
 ServletContext getContext(java.lang.String uripath)
          Returns a ServletContext object that corresponds to a specified URL on the server.
 int getMajorVersion()
          Returns the major version of the Java Servlet API that this Web server supports.
 java.lang.String getMimeType(java.lang.String file)
          Returns the MIME type of the specified file, or null if the MIME type is not known.
 int getMinorVersion()
          Returns the minor version of the Servlet API that this Web server supports.
 java.lang.String getRealPath(java.lang.String path)
          Returns a String containing the real path that corresponds to a virtual path.
 RequestDispatcher getRequestDispatcher(java.lang.String urlpath)
          Returns a RequestDispatcher object that acts as a wrapper for the resource located at the named path.

この場合、getReuestDispacherの型は左のRequestDispatcherになる。
あと、メソッドを探すときは、フレーム表示にして、まず左上からパッケージを選び、左下のメソッドを選べば良い。No Frameで見てるときは、必然的にそういう操作になるけどね。あと、上のINDEXとかTREEとかで探しやすい方法で探せるのも良い。

コンパイルを行ってるWindows環境と環境変数を比べてみた。Windowsの方には「D:\jswdk-1.0.1\lib\servlet.jar」という記述がある。この中にはwebserver.jarなどのファイルもある。Linuxで調べるとない。もしかしたら、GNUJSPの時も書いたかもしれないが、JSWDKを入れていないのかも。入れてみる、と思ったが、classpathで指定しているのはservlet.jar。これはlinuxではgnujspについてきている物を使っている。

servlet-2.0.jarのソースを確認してみた。HTTPServletContext.javaというファイルをのぞいてみる。
引数の数ごとにいくつか定義がある?中で、引数一つのもの(今回使っているもの、たぶん)はnullをReturnしている。他にも引数二つの物もあり、それはいろいろやってる様子だが、第二引数にJSPWriterとかかれている。調べてみるべきかも。

その前に、LinuxでつかっているjarをWindows環境に持ってきて参照した場合、コンパイル時にエラーが出るのではないか?jarはJAVAのプログラムなので、プラットフォームが違っても動く。同じ現象が出た場合はLinuxで使っていたjarが二つともダメと言うことになる。

login2.java:28: シンボルを解釈処理できません。
シンボル: クラス RequestDispatcher
位置 : web.Login2 の クラス
RequestDispatcher rd = ctx.getRequestDispatcher("../jsp/login2.jsp");
^
login2.java:28: シンボルを解釈処理できません。
シンボル: メソッド getRequestDispatcher (java.lang.String)
位置 : javax.servlet.ServletContext の インタフェース
RequestDispatcher rd = ctx.getRequestDispatcher("../jsp/login2.jsp");
^
注: login2.java は推奨されない API を使用またはオーバーライドしています。
注: 詳細については、-deprecation オプションを指定して再コンパイルしてください。
エラー 2 個

結果がこれ↑。
果たして、これは当然の結果なのか?やっぱり、jarが怪しいのか?。JAVAのプログラムはどの環境でも同じように動くはずなので、気になる。最後の注のところも気になる(推奨されないAPI?!)。-deprecation オプションをつけて見ろというのでつけてコンパイルしてみると・・・

login2.java:21: 警告: javax.servlet.ServletRequest の getParameter(java.lang.String) は推奨されません。
String userid = request.getParameter("userid"); //requestは上で定義している。リクエストを受け付ける
^
login2.java:22: 警告: javax.servlet.ServletRequest の getParameter(java.lang.String) は推奨されません。
String password = request.getParameter("password");
^

上のエラーに加えて二つの警告が出てきた。
文面から見ると、Stringというのが良くない様子。もしかしたら、俺が勝手に手を加えているかも。
明日は、元になっているサンプルのソースを確認してみる。APIの仕様変更の可能性もあるので、そっちも疑ってみる。


2001年4月22日 21:04:56

前回、調べると言うことで言ってたclasspathは関係なかった。おそらく、これはコンパイル時に影響してくるものだ。コンパイルはクライアントのWindowsマシンでやっているので関係ない。
次は、servlet-2.0-plus.jarではなく、普通のservlet-2.0.jarに切り替えて試しに動かしてみる。これでなれば、servlet-2.0-plus.jarにこのメソッドが含まれてないのだろう。うまくいけば、今度は他のメソッドを実行してみる。


2001年4月16日 23:30:43

今日は情報収集。googleで「サーブレットからJSP」というそのものズバリなキーワードで検索した
以下のサイトに大変有用な情報を見つけた。サンクス!!

http://cfusion.sirius.co.jp/jrun/faq/faq.htm#Servlet_JSP

サーブレットからのJSP呼び出しについて
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SampleSJ extends HttpServlet {
  ServletContext sc = null;
  public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException, ServletException{
     sc = getServletContext();
     sc.getRequestDispatcher("/XXX.jsp").forward(req, res);  
  }
}
XXX.jspには、呼び出したいJSPファイルを指定してください。
上記の場合、Webサーバで設定しているDOCUMENTROOTの直下にファイルがあると仮定しています。

やはり、getRequestDispatcherを使うようだ。後ろにforwardがついているので、今まで見たサンプルと違うが、試しにやってみよう。
→やっぱり、NoSuchMethodErrorだ。そのようなメソッドはないと言っているので、クラスパスが通っていないのか?

明日はLinux側のclasspathでも調べてみよう。


2001年4月15日 15:24:26

ログインJSP版

なぜか、
java.lang.servletNoSuchMethodError
at web.login2.service(login2.java :28)のエラーが出る。

getRequestDispatcherというメソッドが見つからないということか?

login_jsp.htm(html/java)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML><META name="GENERATOR" content="IBM WebSphere Homepage Builder V6.0.0 for Windows">
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE></TITLE>

<BODY>
<FORM action="/servlets/web.Login2" method="POST">
ユーザID:<INPUT type="input" name="userid"><BR>
パスワード:<INPUT type="password" name="password"><BR>
<INPUT type="submit" value="ログイン">
</FORM>
</BODY>
</HTML>

Login2.java(servlets/web)

1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
20
1
2
3
4
5
6
7
28
package web;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class Login2 extends HttpServlet
{
ServletContext ctx = null;
public void init(ServletConfig config) {
synchronized(this) {
if(ctx == null) {
ctx = config.getServletContext();
}}}

public void service(
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
// ブラウザからの情報の読み取り
String userid = request.getParameter("userid");
String password = request.getParameter("password");
// セッションオブジェクトに保管
HttpSession session = request.getSession(true);
UserinfoBean bean = new UserinfoBean(userid, password);
session.putValue("userinfo", bean);
// 画面を表示
RequestDispatcher rd = ctx.getRequestDispatcher("../jsp/login2.jsp");
rd.forward(request, response);
}
}

login2.jsp(html/jsp)

<html><META http-equiv="Content-Type" content="text/html; charset=EUC-JP">

<jsp:useBean id="userinfo" class="web.UserinfoBean" scope="session"/>
<body>
<H1><%=userinfo.getUserid() %>さん、ようこそ!</H1>
<A HREF='/servlets/web.Userinfo2'>ユーザ情報</A>
</body>
</html>

User.info2(html/jsp)

<HTML>
<jsp:useBean id="userinfo" class="web.UserinfoBean" scope="session"/>
<BODY>
<H1>パスワードの表示</H1><BR>
<TABLE>
<TR>
<TD>ユーザID</TD><TD><%=userinfo.getUserid()%></TD>
</TR>
<TR>
<TD>パスワード</TD><TD><%=userinfo.getPassword()%></TD>
</TR>
</TABLE>
</BODY>
</HTML>