Tomcatで以下のエラーが出た時の対処法
アクセスが拒否されました。
Unable to open the service 'Tomcat6'
http://www.javadrive.jp/servlet/install/index8.html
Javaのクラスパスについて
クラスパスに半角が入っている( ...\Program Files\...) ため、
サーブレットのプログラムがコンパイルエラーになってしまった。
対処法としては、8.3形式のファイル名を使う方法があるらしい。
8.3形式の名前は、cmdから "dir /x"で調べることができる。
http://www.atmarkit.co.jp/fwin2k/win2ktips/606dirx/dirx.html
※ただし、NTFSのチューニングで8.3ファイル名が無効になっていたりする
環境もあるので注意
#無効にしたほうがパフォーマンスが良いので
システムにCLASSPATHを設定しても、eclipseには設定されない?
ウィンドウ(W)→設定(P)→Java→ビルドパス→クラスパス変数
から設定するか、
プロジェクト名を右クリックして、ビルドパスを追加する(外部Jarの追加)
Tomcatのeclipseへの登録方法
http://www.javadrive.jp/eclipse3/tomcat/
eclipseのビューで、[サーバー]を表示しておくと、
ビューの右上にある再生ボタンからTomcatの起動ができる。
※画面中央上の再生ボタン(プログラム実行ボタン)ではないので注意
Tomcatはシステムで使用していると使えないので、
PC起動時にTomcatを起動するようにしている場合は、
[管理ツール]⇒[サービス]のApache Tomcatから[停止]し、
また[手動]で起動するようにしておくとよい。
また、eclipseのビューの[サーバー]から、
サーバー・ロケーションを設定することができる。
[Tomcatインストールを使用]にチェックを入れておくと、
[サービス]からApache Tomcatを開始したときと同じ状況を再現できる
サーブレット動作時に必要なxmlファイル
(1)web.xml
web.xmlは、設定しなくても静的なウェブページは見ることが可能だが、
動的なページ(サーブレット)を動かすためには、web.xmlの設定が必要。
(2)xxx.xml
これとは、別にコンテキストファイルというのが必要で、
<Context path="/hello" docBase="d:/servlet-sample/helloworld"/>
とすると、docBaseで示したフォルダに、http://localhost:8080/hello
でアクセス可能になる(エイリアス?のようなもの)
ファイル名は、pathの値と同じhello.xmlとする。
配置は、web.xmlはサーブレットプログラムのWEB-INFの中で、
コンテキストファイルは、
[Tomcatインストールフォルダ]-[conf]-[Catalina]-[localhost]
の中に配置する。
web.xmlの書き方
作ったプログラムがHelloWorld.classのとき
<servlet>
<servlet-name>helloworld</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
のようにすると、プログラムに名前をつけられる。
この名前は下記のURLマッピングに使う。
<servlet-mapping>
<servlet-name>helloworld</servlet-name>
<url-pattern>/hogehoge</url-pattern>
</servlet-mapping>
先ほど、付けた名前のサーブレットを、
/hogehogeというURLで呼び出せるようにできる。
Tomcat開発で遭遇したミス
1.index.htmlのパスを変えたのに内容が変わらない。
→ブラウザのキャッシュのせい。F5を押下
2.localhostのxmlを編集しても反映されない
→Windows7が悪さしている?
xmlファイルはCtrl+ドラッグでコピーしないで、
新しくメモ帳を作ってカット&ペーストしたほうがよい。
サーブレットを呼び出したときに呼ばれるメソッド
Javaサーブレットのパスを指定して呼び出したときは、
サーブレットプログラム内のdoGetメソッドが呼ばれる。
サーブレットのライフサイクル
サーブレットは最初に呼ばれたときにインスタンスが生成される。
それ以降のリクエストは、すべてマルチスレッドで動作する。
したがって、インスタンス変数は、それぞれのリクエストで共有される。
→訪問数などを表示するときに使える
対して、メソッド内に記述したローカル変数はスレッド毎に独立しており、
別のスレッドはアクセスすることができない。
上記の理由により、
インスタンス変数の初期化はメソッド内で行ってはいけない。
スレッドが新しく作られるたびに、初期化されてしまう。
Tomcatを落としたりすると、インスタンスが破棄される
logを使う
サーブレット中で
log("カウント開始します");
のようにすると、ログにコメントを書き出すことができる。
logは、「(Tomcatをインストールしたディレクトリ)\Tomcat 6.0\logs」
の中のテキストファイルである。(localhost.日付.log)
サーブレット中で文字コードを指定しなければ、
latin1として認識されて、日本語は文字化けしてしまう。
フォームなどから送られてくるリクエストパラメータは、
すべてString型として受信する。必要に応じて変換する。
String vals[] = request.getParameterValues("name");
のようにすると、名前に対応したすべての値を取得することが可能。
フォームから得た日本語文字列は、そのままでは文字化けしてしまう。
※サーブレット側がデフォルトでは、latin1として解釈しようとするため
※クライアント側が
<meta http-equiv="Content-Type" Content="text/html;charset=Shift_JIS">
のようにしてShift-JISを指定していても、
サーブレット側に指定していないと文字化けする
文字化け対策
対策として以下の方法がある。
1)事前に文字コードを指定する方法
2)一度誤って処理された文字列をバイト列に戻してから改めて
正しい文字コードで文字列に戻す方法
(1)は「setCharacterEncoding」メソッドを使う
request.setCharacterEncoding("Shift_JIS");
requestはdoGetの第一引数
簡易的な方法だが、リクエストボディに含まれる
データの文字コードしか設定できない
→POSTなら問題ないが、GETはURIにリクエストが含まれているため、
文字コードの設定はできない。
(2)は
String val = request.getParameter("name");
byte[] byteData = val.getBytes("ISO_8859_1");
のようにして、バイト列に戻す。ISO_8859_1は、latin1のこと。
val = new String(byteData, "Shift_JIS");
のようにすれば、Shift_JISに直して、文字列になる。
※JISAutoDetectという自動判定もあるが、あまりアテにならない。
※クライアント側のHTMLページの文字コードを決めておき、
サーブレット側でも特定の文字コードを指定したほうが無難
パラメータ名の取得
request.getParameterNames();
で、パラメータ名を取得することが可能。
あまり必要性はないが、デバッグなどに有効
リクエストしたURIの取得
getRequestURLやgetRequestURIでリクエストURIの取得
リクエスト方法の取得(プロトコルやGET/POSTなど)
getScheme, getProtocol, getMethodでリクエスト方法の取得。
HTTPやHTTPSなどが取得できるので、SSL通信が行われているかの判別に使用可能。
ヘッダーの名前や値も取得可能(クライアントによって値は異なる)
invoker
Tomcat5より前のバージョンではweb.xmlを指定しなくても
サーブレットを呼び出すことができたという仕組みのこと。
しかし、クラスファイル名やディレクトリ構成が分かってしまうという
セキュリティの問題上もあり、Tomcat5ではデフォルトで使えなくなっている。
http://www.javadrive.jp/servlet/webxml/index3.html
Tomcatフォルダのconf\web.xmlを編集することでinvokerを有効化する手順
(ただし、テスト中などに限定して使用したほうが良い)
個々のweb.xmlを編集して、個々にinvokerの有効無効を設定することも可能。
使用はテスト時などに限ったほうが良い
web.xmlの<servlet-mapping>には、拡張子を含めたURIを指定してもよい。
したがって、/index.htmlと見せかけてサーブレットを呼び出すことも可能。
URLパターンは、/hello*
のように指定することが可能。
/hello/index.html
/hello/HelloWorld
/hello/foofoo/hogehoge/hogehoge.jpg
など、どのように指定しても同じサーブレットが呼ばれる。
*.gifのようにして呼び出すことも可能
'/'と"/*"という指定は異なる。
前者をデフォルトマッピング、後者をパスマッピングといい、
前者は優先順位が低いので、マッチしなかった場合に呼び出すサーブレットを
指定するのに適している
<servlet>には、子要素として、<init-param>を与えることが可能
<init-param>
<param-name>
パラメータ名
</param-name>
<param-value>
パラメータ値
</param-value>
</init-param>
で指定が可能
String ini = getInitParameter("パラメータ名");
で取得が可能
プログラムで初期値を指定する場合と違い、再コンパイルが必要ない。