ざっくりJava JSP/サーブレット

# 書いてる人
プログラミング学習サービスやら、ペットサロン予約サービス、風俗検索サービスなど色々とやっている「かずきち」です。
■運営サービス一部
http://crazy-wp.com/
http://webukatu.com/
新宿のホストから不動産・保険の営業を経て、HTMLって何？という状態から３ヶ月独学でプログラミングやデザインを学び、IT業界で１年間実務経験を積んで年収は１本超え。現在は起業家としてサービス運営やら不動産運営をしています。
Qiita内にそれ系の記事も書いてます。
<a href="http://qiita.com/kazukichi/items/7379b75fba2f90d3cf45" target="_blank">エンジニアで稼ぐために大切な１３のコト</a>
<a href="http://qiita.com/kazukichi/items/aeba286c2a750081e5c0" target="_blank">WEBサービスで起業したい人に読んで欲しい１８のコト</a>

#JSPってなに？
JSP(Java Server Pages)と言って、PHPなどと同じようにタグを使ってhtml内にそのまま記述出来るもの。
同じくサーブレットというものがあるが、それをもっと使いやすくした感じ。
Javaのお手軽版的な。

#サーブレットって？
簡単に言うと、サーバーで動的なコンテンツを生成するプログラムを作るための技術。
Javaサーバーで動く小さなプログラムで、JSPの原型。
JSPはJavaサーバーがJSPのコードを読み込み、それをサーブレットのソースコードに変換。
HTMLのタグなど、すべてprintlnで書きだすように変換される。
そして、生成されたサーブレットのソースコードをコンパイルし、サーブレットを生成してそれを呼び出す。

```
JSPファイル　⇒　サーブレットファイル　⇒　クラスファイル　⇒　実行
```

※サーブレットはバージョンがあり、サーバーによって対応していなかったりするので注意


#サーブレット
##サーブレットとは？
サーブレットは、Javaを使ってサーバサイドプログラムを作るための技術。
WEBサービスなどをJavaで作る場合には、必須のもの。
サーブレットや同じ感じのJSPという技術を使うには、JavaSEではなくJavaEEの技術が必要。
（JavaEEをPCにインストールする必要がある）
サーブレットはブラウザからリクエストがあるとアプリケーション・サーバーがサーブレットクラスのインスタンスを生成する。
毎回リクエストの度にインスタンスを生成するのはサーバーに負荷がかかるため、一回目作ったインスタンスをリクエスト応答後も破棄せずに次のリクエストでも再利用する。
（サーバーが終了するなどの時にインスタンスがサーバーによって破棄される）

##サーブレットの書き方

```java:Sample.java
//①お決まりのインポート文（Eclipseでサーブレットクラスを作成すると自動で書いてくれる）
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//②サーブレットクラスを作るにはサーブレットクラスの元になるHttpServletクラスを継承する必要がある。
public class Sample extends HttpServlet{
	//③サーブレットクラスがGETで呼ばれた場合のdoGetメソッドをオーバーライドする。書き方は基本このお決まりの書き方になる。
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException{
			//処理を書く

	}
	//④サーブレットクラスがPOSTで呼ばれた場合のdoPostメソッドをオーバーライドする。書き方は基本このお決まりの書き方になる。
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException{
			//処理を書く

	}
}
```
ブラウザからリクエストを受けるとアプリケーションサーバーがサーブレットクラスのdoGet()を呼び出す。
その時に引数として、ブラウザから届いたリクエスト情報の入った「HttpServletRequest」とサーバーから送るレスポンスに関係する情報や機能をもつ「HttpServletResponse」を渡している。
HttpServletRequestインスタンスに格納された情報を元に処理を行い、HttpServletResponseインスタンスを使ってブラウザへ結果を返している。

##サーブレットからHTMLを出力する

```java:Sample.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		response.setContentType("text/html; charset=UTF-8"); //①ブラウザへ渡す情報の文字コードを指定

		//②htmlを出力
		PrintWriter out = response.getWriter(); 
		out.println("<html>");
		out.println("<head>");
		out.println("</head>");
		out.println("<body>");
		out.println("<p>Hellooooo!</p>");
		out.println("</body>");
		out.println("</html>");
	}
```

##サーブレットクラスのコンパイル
サーブレットクラスのソースファイル　→　コンパイル　→　サーブレットクラスのクラスファイルが生成される　→　ブラウザがリクエスト　→　サーブレットクラスのクラスファイルが実行される　→　サーブレットクラスのクラスファイルからインスタンス化　→　サーブレットクラスのインスタンスが実行される

##サーブレットクラスとURL

サーブレットを呼び出す際のURLは以下の仕組みになっている。

```txt:
http://サーバー名/アプリケーション名/URLパターン
```

URLパターンというのはサーブレットクラスでつける「アダ名」のようなもの。
サーブレットクラスでURLパターンを設定しておくことで、それをURLとして呼び出すことができる。
このURLをhtmlのaタグのhref属性やformのaction属性に設定すれば、サーブレットへ飛ばせる。

###URLパターンの設定
URLパターンをサーブレットクラスで設定するには、「@WebServletアノテーション」を使う。

```servlet:サーブレットファイル：sample.java
import javax.servlet.annotation.WebServlet; //①アノテーションを使うために読み込んどく
・・・省略
@WebServlet("/sample") //②URLパターンを「sample」として設定
public class Sample extends ・・・省略
```

URLパターンをスラッシュで区切って階層を増やすことも出来る。
※URLパターンの設定方法には、アノテーションの他に`web.xml`という設定ファイルを使用する方法がある
※Eclipseでは、サーブレットクラスを作ると自動的にアノテーションに「/クラス名」と設定される。


##サーブレットの注意
サーブレットクラスのコードを修正しても、すぐには反映されない。
Eclipseでは、修正後にしばらく（数秒から数十秒ほど）待つとコンソールビューに「再ロードが完了しました」と出る。そうすれｂ反映されてる。
もしくは、サーバーを再起動させる。


#JSP

##JSPファイルから作成されるサーブレットクラスの場所
Eclipseを使っている場合、ワークスペースで指定した場所内の以下の場所にある

```
〜ワークスペース/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/プロジェクト名/org/apache/jsp
```

jspを作成して実行した場合、上記の場所にjavaファイルとclassファイルが作成される。
たまにjspファイルを修正されても反映されない場合は、このディレクトリにあるjavaファイルやclassファイルが古いままの場合があるので、削除して実行しなおす。

##JSPファイルのURL
jspファイルはhtmlファイルと同じ扱いで、WebContentフォルダの中に配置し、jspファイル名がURLになる。
実際のURLは下記の通り。

```
http://サーバ名/アプリケーション名/WebContentからのパス
```

##JSPの注意
Eclipseでjspを書く場合、文法エラーがある場合はコードの左側に☓印とコード内に波線が出て表示してくれるが、
エラーがない場合でもこれが出てしまう場合がある。
なので、そういう場合にはエラーが出たら一回切り取りして貼り付けし、上書き保存をすると直る。
直らなければ本当にエラーがあるってこと。


#JSP＆サーブレットを使う

##JSPからサーブレットへの値の受け渡し方法
ブラウザからGETやPOSTで送られたリクエストパラメータはHttpServletRequestインスタンスに格納され、送信先のJSPやサーブレットへ送られる。

```jsp:doPostやdoGetメソッド内で書く
//リクエストパラメータの文字コードを指定
request.setCharacterEncoding("UTF-8");

//リクエストパラメータの取得
String name = request.getParameter("name"); //getParameter("属性名");
String gender = request.getParameter("gender");
```

##リクエストパラメータをJSPファイルで受け取る

```jsp:jspファイル内で書く
<%
//リクエストパラメータの文字コードを指定
request.setCharacterEncoding("UTF-8");

//リクエストパラメータの取得
String name = request.getParameter("name"); //getParameter("属性名");
String gender = request.getParameter("gender");
%>
```

requestなどは暗黙オブジェクトのため、宣言せずに使える。


##MVCモデル

```
コントローラ　・・・　ブラウザからのリクエストを受け取る役割（サーブレット）
ビュー　・・・　レスポンスとして返すファイル（JSPファイル）
モデル　・・・　実際の処理を行う役割（普通のjava）
```

##フォワードとリダイレクト
###フォワード
サーバー側で他のファイルの処理へ移すことができる。
ブラウザ側のURLが変わらずに画面など変えられる。

####サーブレットからJSPファイルへフォワードさせる
`javax.servlet.RequestDispatcher`をインポートした上で下記のように書く

```
RequestDispatcher dispatcher = request.getRequestDispatcher("フォワード先のパス");
dispatcher.forward(request,response);
```

フォワード先のパスはJSPファイルなら`/WebContentからのパス`
サーブレットなら`/URLパターン`となる。

####JSPファイル配置とリクエスト
JSPファイルを以下に配置するとブラウザからは直接リクエストできないようになる。
JSPファイルは基本サーブレットが呼び出してブラウザへ返すものなので、以下に配置する。

```java:
/WebContent
 |___ /WEB-INF
         |___ /jsp
                |___この中にフォワードするjspを配置しとく
```

###リダイレクト
サーバー側で一旦「こっちのファイルを呼んで！」とレスポンスを返し、
受け取ったブラウザ側は再度そっちのファイルへリクエストを送るもの。

####リダイレクト方法

```
response.sendRedirect("リダイレクト先のURL");
```

リダイレクト先は同じサーバー内の場合以下のようにも指定できる

```
サーブレットの場合　→　/アプリケーション名/URLパターン
JSPファイルの場合　→　/アプリケーション名/WebContentからのパス
```


##スコープ（画面間でのデータの引き継ぎ方法）
Java内で値を持ち回すにはJavaBeansを使い、インスタンスを持ち回す。
インスタンスを保持できる範囲・期間によって、４種類のスコープがある。

```
・ページスコープ
・リクエストスコープ
・セッションスコープ
・アプリケーションスコープ
```

###ページスコープ
１画面内でしか使いまわすことはできない。
基本、意識する必要はないものなので省略。

###リクエストスコープ
クライアントからリクエストを投げて、サーバーがレスポンスを返すまでの間だけ保持される。
なので、リダイレクトすると消える。が、フォワードの場合は情報は消えない。

```java:サーブレット内でのリクエストスコープへのインスタンス保存と取り出し
protected void doGet(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException{

		//リクエストスコープへ保存するインスタンス生成
		Human human = new Human("かずきち", 29);
		
		//リクエストスコープにインスタンス保存
		request.setAttribute("human",human); //第一引数は「属性名」、第二引数はインスタンス
		
		//リクエストスコープからインスタンス取得
		human h = (Human) request.getAttribute("human"); //取得したインスタンスはObject型になっているので元の型へキャスト（型変換）する必要がある
}
```

```jsp:JSP内でのリクエストスコープからインスタンス取り出し
<%@ page import = "bean.Human" %> //取得したいインスタンスのクラスをインポートする
<%
//リクエストスコープからインスタンスを取得する
Human h = (Human) request.getAttribute("human");
%>
<%= h.getName() %>さんの年齢は<%= h.getAge() %>歳です。 //インスタンスのプロパティにアクセスし、値を取り出す

```

###セッションスコープ
いわゆる、「セッション」と呼ばれるもの。
セッションスコープに保存した値は、インスタンスを削除するかブラウザを閉じるまで利用できる。（なので、リダイレクト先でも値を引き継いで利用できる）
Cookieという仕組みを使って値を保存しておく。セッションはCookieに関しての説明は面倒なので省略します。
セッションス
コープを使うには、`javax.servlet.ttp.HttpSession`型のインスタンスを使う。

```java:サーブレットでセッションスコープを利用する例

Human human = new Human();
human.setName("かずきち");
human.setAge(29);

//HttpSessionインスタンスの取得（javax.servlet.ttp.HttpSessionをインポートしておく必要がある）
HttpSession session = request.getSession();

//セッションスコープにインスタンスを保存
session.setAttribute("human", human);

//セッションスコープからインスタンスを取得
Human h = (Human) session.getAttribute("human");

//セッションスコープからインスタンスを削除
session.removeAttribute("human");

//セッションスコープ自体を削除したい場合
session.invalidate(); //スコープ自体が削除され、保存していたすべてのインスタンスが破棄される。ショッピングサイトなどで、ユーザーがログアウトを行った時などに利用する
```

###アプリケーションスコープ
WEBアプリケーションが終了するまでずっと値が保持される。
なので、サーバーを再起動するまでずっと保持しておけるってこと。
データベースに保存するまでもない情報などはアプリケーションスコープで保存しておくといい。

```java:サーブレットでアプリケーションを利用する例
Human human = new Human("かずきち",29);

//ServletContextインスタンスの取得
ServletContext app = this.getServletContext(); //javax.servlet.http.ServletContextをインポートする必要がある

//アプリケーションスコープにインスタンスを保存
app.setAttriute("human", human);

//アプリケーションスコープからインスタンスを取得
Human　h = (Human) app.getAttribute("human");

//アプリケーションスコープからインスタンスを削除
app.removeAttribute("human");

```

```jsp:jspファイルでアプリケーションスコープを利用する
<%@ page import = "bean.Human" %>
<%
//アプリケーションスコープからインスタンスを取得
Human h = (Human) app.getAttribute("human");
%>
<%= h.getName() %>さんの年齢は<%= getAge() %>際です
```

##フィルタ（同じ処理はまとめて実行！）
サーブレット内などで毎回書く`request.setCharacterEncoding("UTF-8");`やログインしていないと見れないページなどで毎回ログインしているかをチェックする処理を書く際など、フィルタという仕組みを使うことで毎回書く必要がなくなる。

```java:フィルタのサンプル

@WebFilter("/*") //①
public class FilterSample implements Filter {
	public void init(FilterConfig fConfig) throws ServletException{ } //フィルタがインスタンス化された直後に行いたい処理を書く場所
	
	//設定したサーブレットクラスが呼ばれた（リクエストされた）時に行いたい処理を書く場所
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
		throws IOException, ServletException{
			request.setCharacterEncoding("UTF-8");
			chain.doFilter(request, response);
	}

	public void destroy(){ } //フィルタのインスタンスが破棄される直前に行いたい処理を書く場所
}
```

①　フィルタには＠WebFilterアノテーションをつける。アノテーションをつけることで、フィルタをどこまでの範囲に適用するかを指定する。

```java:@WebFilterの書き方
@WebFilter("/フィルタを設定するサーブレットクラスのURLパターン")
※javax.servlet.annotation.WebFilterをインポートする必要がある
```


```java:@WebFilterの例
@WebFilter("/Sample") //Sampleのサーブレットクラスに設定
@WebFilter("/Sample/*") //Sample以下のサーブレットクラスに設定
@WebFilter("/*") //全てのサーブレットクラスに設定
```


##jspファイルを分割してインクルードする
jspファイルでもヘッダーやフッターなど共通な部分がある。
そういった時に毎回jspファイルにヘッダーフッターを記述するのは面倒だし、ヘッダー部分に修正があった場合、全てのjspファイルに対して修正をしないといけないので面倒。
なので、ヘッダーやフッターなどを共通化してそれぞれjspファイルにし、そのjspファイルを読み込むようにする。

```jsp:jspファイル内で他のjspを読み込む（サーブレット内でも使える）
<%
RequestDispatcher dpc = request.getRequestDispatcher("インクルード先");
dpc.include(request, response);
%>
```

もしくは、jspなら下記のようにアクションタグを使って読み込むこともできる

```jsp:
<jsp:include page="インクルード先" />
```

インクルード先の指定方法はフォワードの時と同じ。
アクションタグには最初から用意されているものがある。それを「標準アクションタグ」という。

##標準アクションタグ
主に以下のようなものがある

```
<jsp:useBean>　・・・　スコープからJavaBeansインスタンスを取得。取得できない場合は、インスタンスを新規作成してスコープに保存する。
<jsp:setProperty>　・・・　JavaBeanのプロパティの値を設定
<jsp:getProperty>　・・・　JavaBeanのプロパティの値を取得
<jsp:include>　・・・　インクルードできる
<jsp:forward>　・・・　フォワードできる
```

htmlのタグのように書けるが、大文字小文字は区別されるので注意。

##動的インクルードと静的インクルード
インクルードには２種類ある。
動的インクルードは、ファイルを実行中にインクルードで他のjspファイルなど呼び出し、そのファイルの処理を実行し、結果を元のファイルに戻すというもの。
静的インクルードは、ファイルを実行中にインクルードで他のjspファイルなどの処理をそのまま自身のファイルへ取り込み、自身のファイルとして実行するもの。
動的インクルードだと別のファイルとして実行しているため、別ファイルで定義した変数や生成したインスタンス、インポートしたクラスやタグライブラリなどなどは自身のファイルで使えない。
静的インクルードは、一つのファイルとして実行されるので、別ファイルで定義した変数や生成したインスタンス、インポートしたクラスやタグライブラリなどは自身のファイル内で使える。（が、変数名などバッティングしないように気をつける必要がある）

###静的インクルードの方法
includeディレクティブを使う

```jsp:jspファイル内で
<%@ include file="インクルード先" @>
```

※インクルード先は/WebContentからのパスを指定
※サーブレットクラスはインクルードできないので注意
※インクルード先のファイルを更新したら、インクルード元のファイルも更新しないと実行結果に反映されないので注意


#EL式
EL式を使うとスコープに保存された値を取得するのが楽になる。
インポートとスコープからの取得が不要に。


```jsp:普通に取得する場合
<%@ page import="model.Sample" @>
<@ Sample sp = *Smaple) session.getATtribute("sample"); @>
<@= sp.getName() @>
```

```jsp:EL式を使った場合
${ sp.name }
${ sp[2].name } //リストから取得もできる
```

##EL式の書き方

```jsp:
//スコープに保存されているインスタンスを取得する
${属性名}
//スコープに保存されているインスタンスのプロパティを取得する
${属性名.プロパティ}
//※指定したプロパティのgetterが自動で実行される。
```

※EL式は指定した属性名のインスタンスを下記の順序で探す

```
ページスコープ　→　リクエストスコープ　→　セッションスコープ　→　アプリケーションスコープ
```

※何も見つからなくても例外はスローされず、ただそこには表示されないだけ。

もし、セッションスコープに保存されているインスタンスを利用したいなどスコープを指定する場合は下記の通り

```jsp:セッションスコープから取得したい場合
${ sessionScope.msg }
```

EL式は後述のスクリプトレットやスクリプト式内で使うことが出来ない。なので、if文やfor文の中に使いたい場合は後述のJSTLを使う必要がある。

#JSTL
カスタムタグと言われるもので、開発者が独自に開発したアクションタグのことをいう。
jspでは`<jsp:forward>`のように標準で用意されているアクションタグのほか、独自で作成もできる。
独自作成したアクションタグは`タグライブラリ`にまとめて、他の人に配布できる。（タグのプラグイン的な）
JSTLは５つのタグライブラリで構成されている。
DB操作や条件分岐、繰り返しなど色々なタグがある。

##JSTLの利用方法
JSTLを使うにはネットからJSTLのJARファイルをダウンロードし、`WEB-INF/lib`に配置する。
JSPでタグライブラリを使うには、下記のようにtaglibディレクティブで使用するタグライブラリを指定する。

```jsp:JSP内でのタグライブラリ指定方法
<%@ tablib prefix="接頭辞" url="使用するタグライブラリのURI" %>
```

##Coreタグライブラリ
条件分岐などできるライブラリ。使い方は以下の通り。

```jsp:例
<c:out value="変数名"> //変数の値を出力。エスケープ処理も行ってくれる。
<c:out value="${sample.name}"> //EL式も使える

//分岐１
<c:if test="条件式">
	trueの場合の処理
</c:if>

//分岐１（EL式使った場合）
<c:if test="${sample.age == 20}">
	//trueの場合の処理
</c:if>

//分岐２（if-elseにしたい場合にはこっちを使う）
<c:choose>
	<c:when test="条件式">
		//trueの場合の処理
	</c:when>
	<c:otherwise>
		//falseの場合の処理
	</c:otherwise>
</c:choose>

//繰り返し
<c:forEach var="i" bigin="0" end="9" step="1" >
	//繰り返したい処理
</c:forEach>

//繰り返し（拡張for文）
<c:forEach var="変数名" items="配列など">
	//繰り返したい処理。varに指定した変数名を使って色々できる。
</c:forEach>

```


#JSPのタグの種類
主なタグは５種類

```
アクションタグ　・・・　<jsp: 内容 />
``` 

```
1.アクションタグ　・・・　定型的な処理をタグ形式で記述
2.ディレクティブタグ　・・・　ページ単位での処理方法を指定する。htmlでいうmetaタグ的な。
3.宣言部　・・・　変数やメソッドの定義のみ書くもの
4.スクリプトレット　・・・　ページの処理方法を記述。Javaコードなんでも書いてOK
5.式　・・・System.out.println(変数)と同じ機能。println書くならこっち使った方が楽。
``` 

##ディレクティブ

```text:基本構文
<%@ ディレクティブ名 属性名="属性値1" 属性名2="属性値2" …　 %>
```

 ※属性値は必ずダブルクウォートで囲む


```text:主なディレクティブ
@page　・・・　基本的な処理方法を決める
@include　・・・　外部ファイルをインクルードする
@taglib　・・・　ページ内で使用するタグライブラリを宣言
```

```text:@pageディレクティブの主な属性
contentType　・・・　ページの出力コンテンツタイプ（文字コードなど）を設定。基本は「text/html」でいい。
　　　　　　　　　　　　画像や動画を出力する場合は「image/jpeg」「video/mpeg」などを値に指定。
pageEncoding　・・・　jspファイルの文字コード
import　・・・　インポートするパッケージやクラスを指定。「java.util.Date」などと値を指定。
errorPage　・・・　例外発生時に表示するエラーページのパス
```

##スクリプトレット

```text:基本構文
<% 内容 %>
```

```jsp:例
<%
for(int i= 0; i<5; i++){
 out.prinln("テストです。");
}
%>
```
※暗黙オブジェクト（インスタンス化とかしないでいきなり使えるやつ）も使える
※ここで宣言した変数はページ処理終わるたびに破棄される。

```jsp:例
<% for(int i= 0; i<5; i++){ %>
 テストです。<br>
<% } %>
```
※phpと同じように挟んでも書ける

##宣言部

```text:基本構文
<%! 内容 %> 
```

```jsp:例
<%!
public String repeat(String msg, int n){
  String rst = null;
  for(int i=0; i<n; i++){ rst+= msg; }
  return rst;
}
%> 
```
※スクリプトレットのような処理の記述はできない。メソッド定義や変数定義のみ。
※暗黙オブジェクトはこの中では使えない
※ここで宣言した変数はApacheなどのWebサーバーが起動してる間ずっと残る。
※ブラウザがリロードしても、ほかのPCから見ても、変数の中身は共有。
（なので、読み取り専用の変数だけを定義した方がいい）

##式

```text:基本構文
<%=変数 %>
```

```jsp:例
<%=result %>
```
※変数を複数記述したり、計算式をそのまま記述はできない。メソッドはok。

#実際の使い方の流れ
##1．ファイルを作成する

JSPを使うにはファイル名の拡張子をjspにする。

```
ファイル名.jsp
```
※「httpd」「htdocs」的なフォルダ内に置くこと

##2．文字コードを設定する（基本utf8で）

```jsp:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
```
※jspファイルの中でさらにincludeして他のjspファイル（子ファイル）を読み込む場合、子ファイルにはcharset属性はなしにする。

##3．パッケージを取り込む

```jsp:
<%@ page import="クラスの指定" %>
```

##4．メソッドや変数を宣言する
`<%!` と `%>` の間に、メソッドの定義や変数の宣言を記述すると他の`<% %>`内でも使いまわせる。 

```
<%! 変数宣言やメソッド定義 %>
```

```jsp:例
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>テストタイトル</title>
</head>
<body>
<%
for(int i = 0; i<10 ; i++) out.println("テストテキスト");
%>
</body>
</html>
```


#ページ間で値を受け渡しする

##aタグやGET経由で渡す
クエリ情報には「？」「＆」「％」や空白、マルチバイト文字（日本語）はそのままだと渡せない。
だから、渡す前にURLエンコードして渡せる様にする必要がある。
（フォーム経由の場合は自動でエンコードされるので不要）
※クエリ情報での受け渡しはIEの場合は2083文字まで。

###送る側処理
```html:
<a href=”link2.jsp?keyword=<%=URLEncoder.encode(“クエリ情報（&&%）”,”UTF-8”)%>情報を送る</a>
```
※「?キー値=値」で送る
※import=”java.net.*”をしておく
※受け取る側がgetParameterした時に自動的にデコードされる

日本語が文字化けするなら、`%CATALINA_HOME%/conf`フォルダ内`server.xml`の72行目あたりを以下のように編集する
```
<Connector port="8080" protocol="HTTP/1.1"
  connectionTimeout="20000"
  redirectPort="8443" useBodyEncodingForURI="true" />

```

###受け取る側処理
JSPではGET、POSTを気にすることなく扱える設計になっている。
GETで送られてきたものでも、POSTで送られてきたものでも、下記のように`getParameter("name属性名")` 受け取れる。

```jsp:
request.getParameter(“keyword”);
```
※キー値で取得できる。


##色々なフォームからPOSTで値を受け取る

```java:例
String inpt = request.getParameter("input"); //name属性がinput
String chk = request.getParameter("check"); //チェックボックス（name属性がcheckの場合）
String rd = request.getParameter("radio"); //ラジオボタン（name属性がradioの場合）

//複数選択可能なセレクトボックス（name属性がselectの場合）
String[] slt = request.getParameterValues("select");
String rst = null;
if (slt != null){
    for(String rst : slt){
      out.println(rst);
    }
}
```

※値を受け取るときには必ず文字エンコードすること

```java:
request.setCharacterEncoding("UTF-8"); //クライアントから送信されたリクエスト情報の文字コードを宣言
```
※getParameterする前に必ず上の１行を記述すること。
※「JISAutoDetect」という値にすると自動で文字コードを判別してくれるが、絶対正しい訳じゃないので使わない

#リダイレクトさせる

```jsp:
<% response.sendRedirect("http://www.google.com/"); %>
```

#エスケープ処理
フォームなどから受け取った値は何が入っているかわからない。<script>タグなどを入れられてるとブラウザで動いてしまって変な処理をされたりとセキュリティ的によくないので、そういう特殊な文字を変換（エスケープ）して影響のない文字にする。

JSPでは `getEscapedString` というメソッドが用意されているので、そのメソッドを定義して中にエスケープしたい文字を追加する。

```jsp
//エスケープ処理メソッド
<%!public String getEscapedString(String s){
    String str = s;
    str = str.replace("&","&amp;");
    str = str.replace("<","&lt;");
    str = str.replace(">","&gt;");
    str = str.replace("\"","&quot;");
    return str;
}%>
//実際にエスケープする際
<%
    String input = request.getParameter("input");
    String str = getEscapedString(input);
%>

//html内で以下のような記述をすればエスケープされた文字が表示される
<%=str %>
```


#リクエストパスを取得する

色々な種類がある。
getRequestURIで取得したリクエストパスを物理パスに変換してファイル読み書きしたりする。


#リダイレクトする

```jsp
response.sendRedirect(“http://www.yahoo.co.jp/”);
```

#Cookieを使う

##Cookieの流れ

```
（初回）ブラウザがサーバへアクセス　➡　サーバがCookie生成して返す　➡　（次回以降）ブラウザがサーバへアクセス時に持っているCookie送信　➡ サーバがもらったCookieを読み込み
```

##Cookieの使い方

```
//クッキーのインスタンス生成
Cookie 変数 = new Cookie( 名前 , 値 );

//有効期限設定
クッキーインスタンス名.setMaxAge( 秒数 );

//クッキー保存
response.addCookie( クッキーインスタンス名 );

//クッキー読み込み
Cookie[] 変数 = request.getCookies();
```
※JSPでは指定したクッキーだけを読み込むということができないので、サイトで保存されているすべてのクッキーをCookie配列として取り出す
※有効期限を設定しない場合、ブラウザ閉じた段階でクッキーが破棄される

```
//クッキーの名前を取得
String 変数 = クッキーインスタンス名.getName();

//クッキーの値（中身）を取得
String 変数 = クッキーインスタンス名.getValue();
```

##URLエンコード
Cookieには日本語は保存できないので、URLエンコードする必要がある。（java.net.*をimportして使う）

```
//テキストをURLエンコードする
String 変数 = URLEncoder.encode( 値 , エンコード名 );

//テキストをURLデコードする
String 変数 = URLDecoder.decode( 値 , エンコード名 );
```

##テキストエンコード方式を設定
日本語を表示する際など文字化けするので、文頭に追記しておく

```jsp
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
```


例）フォームに入力した内容を保持する

```jsp:test1.jsp
//■入力するページ
<% page contentType="text\html; charset=UTF-8" %>
<%
       //エンコード設定
         request.setCharacterEncoding("utf-8"); //フォームデータ送信時の文字コード

       //クッキーを取得
	String email="";
	Cookie[] cookie = request.getCookies();
	if(cookie != null){ //取得したクッキーに何か入っていた場合
		for(Cookie c : cookie){ //インスタンス変数cookieをインスタンス変数cへ移し
			if(c.getName().equals("email")){ //インスタンス変数cの中の名前がemalと等しいか1個ずつ確認
                                    //デコードする
				email = URLDecoder.decode(c.getValue();,"UTF-8");
			}
		}
	}
%>
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>クッキーテスト</title></head>
<body>
<form method="POST" action="cookie.jsp"> <!--cookie.jspへ遷移-->
<input type="text" size="10" name="email" value="<%= email %>"/>
<inpu type="submit" value="送信" />
</form>
</body>
</html>
```

```jsp:cookie.jsp

//■Cookieを生成してブラウザへ渡す（保存）ページ
<% page contentType="text\html; charset=UTF-8" %>
<html>
<head>
<meta charset="UTF-8" />
<title>クッキー保存処理</title>
</head>
<body>
<%
 request.setCharacterEncoding("UTF-8"); //文字コードを設定
 String value = URLEncoder.encode(request.getParameter("email"),"UTF-8"); //フォームの値を取得
 Cookie cookie = new Cookie("email",value); //クッキー生成し、セット。引数はクッキー名、値の順。
 cookie.setMaxAge(60*60*24*7); //クッキーの有効期限を設定（今回は１週間）（引数を0にするとクッキー削除）
 response.addCookie(cookie); //クッキーを発行
%>
<p>クッキーを保存しました</p>
</body>
</html>
```

#Sessionを使う
セッションID、キー値、値の３つで管理される。

##流れ

```
フォーム送信　➡　セッション保存。ID発行。　➡　セッションID送信　➡　セッションID読み込む
```

セッションはオブジェクトも保存できる。日本語は文字化けする。
新規のアクセスならセッションIDを発行する。
Cookieがオフになってると、セッションは使えない。（その代わり、URLでセッションIDを発行するURLリライティングを使う）

##使い方
sessionはインスタンス生成する必要はない。

```jsp

//値を保管する
session.setAttribute( 名前 , 値 );

//値を取得する
Object 変数 = session.getAttribute( 名前 );

//セッションを開始した時刻を得る
long 変数 = session.getCreationTime();

//最終アクセス時間を得る
long 変数 = session.getLastAccessedTime();

//セッションを無効にする
session.invalidate();
```
※セッションを無効にした場合、それ以降のsessionメソッドは使えない


##例

```jsp
■入力するページ
<%　//セッション読み込み、オブジェクト型なのでString型へキャスト
	String email = (String)session.getAttribute("email");
%>  //emailがnullだったら、空の文字を返す
<input type="text" size="10" name="email" value="<%= (email == null) ?"": email %>"/>

■sessionを保存するページ
<% //
 session.setMaxInactiveInterval(60*60*24*7);  //サーバー側のセッション有効期限を決める(秒単位)（デフォルトは３０分）
 session.setAttribute("email",request.getParameter("email"));
%>
```

セッションは確実に破棄しておかないと、どんどん溜まって行って負荷が増える。（ブラウザ側のセッションIDは閉じたら破棄される）
破棄の方法は３通り。
①	session.invalidate();で現在のセッションとその関連のオブジェクトを破棄。
②	セッションの有効期限を決める
③	セッションの有効期限を設定ファイル（web.xml）で設定する。

```xml
//WEB-INFフォルダ内のweb.xml
<session-config>
 <session-timeout>10</session-timeout> <!--分単位で指定する-->
</session-config>

```

##セッションの主なメソッド

```
removeAttribute(key)　・・・　指定セッションを削除
getCreationTime()　　　・・・　セッション生成時刻を取得（タイムスタンプで）
getLastAccessedTime()　・・・　セッションの最終アクセス時間を取得（タイムスタンプで）
getId()　　　　　　　　・・・　セッションIDを取得
isNew()　　　　　　　　・・・　新規に生成されたセッションかを調べる
```

#MySQLデータベースへ保存、読み込みする。
DBへのやり取りには、JDBCを使う。
本来、DBごとにやり取りが違うものをJDBCを挟むことで同じ方法でやり取りが出来る。
実際にはDB種類ごとのJDBCドライバをインストールし、そのドライバが間を繋いでくれてる。
ユーザーごとに毎回毎回DBに接続して～とやるのは、負荷がかかるので「コネクションプーリング」を使い
接続をいくつか保持して、DBを使いたいユーザーへ都度貸し出す様な仕組みをとる。

##コネクションプーリングとデータソース
コネクションプーリングを管理しているのはデータソース（javax.sql.DataSource）
データソースの設定はMETA-INFフォルダ内の`context.xml`で行う
※「DB接続時のユーザID・PW」「プールする最大接続数」や「待機時に最低維持する接続数」などが設定できる

```jsp:接続例
<%@ page contentType="text/html; charset=UTF-8" import="java.sql.*,javax.naming.*,javax.sql.*" %>
<!DOCTYPE html>
<head><meta charset="UTF-8" /><title>DB接続テスト</title></head>
<body>
<%
Connection db = null;
PreparedStatement pstm = null;
try{
  Context context = new InitialContext();
  //データソース（DB接続のための基本情報）を取得。返り値はオブジェクト型なのでキャストする
  DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/データソース名(DB名)"); 
  Connection db = ds.getConnection();

  db.setAutoCommit(false); //トランザクション処理をする場合は記述。自動コミットをoffにする

  //プリペアードステートメントで値をセット
  pstm = db.preparedStatement("INSERT INTO user(id,name) VALUE(?,?)");
  pstm.setInt(1,request.getParameter("id"));
  pstm.setString(2,request.getParameter("name")); //他にもsetDateやsetTimestamp、setBooleanなどがある
  pstm.executeUpdate(); //SQL実行。挿入、更新、削除時には返り値に成功した件数が返る
  
  db.commit(); //トランザクション処理の場合には最後にコミットする
}catch(Exception e){
  throw new ServletException(e);
}finally{
  try{
    if(db != null){ 
      db.close(); //プールへ接続を戻す。必ず記述しないと一定時間保持し続けたままになってしまう。
     }
    if(pstm != null){ pstm.close(); }
    db.rollback(); //トランザクション処理の場合に記述。エラー時はコミット前にDBを戻す。
   }catch(Exception e){}
}
response.sendRedirect("success.jsp"); //登録後に任意のページへリダイレクト
%>
データベース処理成功。
</body>
</html>
```

```jsp:検索系のDB処理の場合
ResultSet rs = null;
try{
   //接続らへんは同じ
   rs = pstm.executeQuery(); //検索系のクエリーを実行
  while(rs.next()){ //一つずつ取得していく
%>
 <p><%=rs.getString("name") %></p>
<% } %>

<% //その他は同じくclose処理を記述 %>
```
	
##ログイン処理

```java
<%@page contentType="text/html" pageEncoding="UTF-8" %>
<%@page import="java.sql.* " %>

<%
		//-------------------------
		//フォームから送られてきた内容を取得
		//-------------------------
   		String name = request.getParameter("name");
   		String psss = request.getParameter("pass");
   		
   		//-------------------------
   		//DBに接続して検索する
   		//-------------------------
   		//nameもパスもちゃんと入っていたら処理開始
   		if(name != null && pass != null){
   			Class.forName("com.mysql.jdbc.Driver").newInstance();
   			String url = "jdbc:mysql://localhost/mydb?characterEncoding=UTF-8";
   			Connection conn = DriverManager.getConnection(url, "test", "pass");
   			//nameとsha1で暗号化したパスがDBのと一致するか
   			PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM user WHERE name = ? AND pass = SHA1(?)");
   			//さっきのクエリーの?部分に値を入れる
   			pstmt.setString(1,name);
   			pstmt.setString(2,pass);
   			ResultSet rs = pstmt.executeQuery();
   			
   			//ログイン成功なら
   			if(rs.next()){
	   			//セッションを一度破棄
	   			session.invalidate();
	   			//セッション再生成
	   			session = request.getSession();
	   			//セッションへ保存
	   			session.setAttribute("name",name);
	   			//画面遷移
	   			response.sendRedirect("secretform.jsp");
   			}
   			//DBを明示的に切断
   			pstmt.close();
   			conn.close();
   		
   		}

%>
以下、htmlのログインフォーム
```

##認証が必要なページでのログインチェック
ログインしてないと見れないページでのログイン認証

```java
<%@page contentType="text/html" pageEncoding="UTF-8" %>
<%@page import="java.sql.* " %>

<%
		//-------------------------
		//セッションからnameを取り出す。なかったら、ログイン画面へリダイレクト
		//-------------------------
		String name = (String)session.getAttribute("name");
		if(name == null){
			response.sendRedirect("login.jsp");
		}
   		//-------------------------
   		//送信データがあるなら、データベースに接続して登録
   		//-------------------------
   		//文字コードセット
   		request.setCharacterEncoding("UTF-8");
   		//フォームよりテキストを取得
   		String message = request.getParameter("message");
   		
   		if(message != null){
   			//DB接続
   			Class.forName("com.mysql.jdbc.Driver").newInstance();
   			String url = "jdbc:mysql://localhost/mydb?characterEncoding=UTF-8";
   			Connection conn = DriverManager.getConnection(url, "test", "pass");
   			
   			//クエリー作成（フォームのテキストをmessageテーブルへ保存する）
   			PreparedStatement pstmt = conn.PreparedStatement("INSERT INTO message (name,body) VALUES (?,?)");
   			//?に値セット
   			pstmt.setString(1,name);
   			pstmt.setString(2,name);
   			//実行
   			pstmt.executeUpdate();
   			
   			//DB明示的に切断
   			pstmt.close();
   			conn.close();
   		
   		}

%>
以下、テキストフォームなど

```

##ログアウト

```java
session.invalidate();
response.sendRedirect("login.jsp");
```

##フォームの内容を記憶する

```java
<%@page contentType="text/html" pageEncoding="UTF-8" %>
<%@page import="org.apache.commons.lang.*" %>
<%
	//-------------------------
	//テキストボックスに入力された値を復元
	//-------------------------
	//フォーム送信された値を取得
	String paramq = request.getParameter("q");
	//取得した値がnullじゃない（送信されてる）なら
	if(paramq != null){
                //サニタイズして格納（htmlへ出力するので）
		paramq = StringEscapeUtils.escapeXml(paramq);
	}else{
		paramq = "";
	}
%>
<html>
<head>
<title>郵便番号から住所を検索するフォーム</title>
</head>
<body>
	<form action="" method="get">
		<imput type="text" name="q" value='<%= paramq %>' />
		<input type="submit" value="search" />
	</form>
<!-- 	郵便番号から住所を検索する処理ページを読み込み -->
	<jsp:include page="zips.jsp" />
</body>
</html>

<%
```

#サーブレット
##動作手順
1．.javaファイルをコンパイルする
2．出来た.classファイルを`/WEB-INF/classes`フォルダ内にパッケージ構造に則した形で置く
※パッケージが`jp.co.test.sample01`だったら、`/WEB-INF/classes/jp/co/test/sample01`フォルダ内に置く

##基本の書き方
doGetメソッドとdoPostメソッドを定義する。
doGetはGETでアクセスされた時の処理。
doPostはPOSTでアクセスされた時の処理。

```java:基本構文
package jp.co.test.sample01;

import java.io.IOException; //以下６つのパッケージはインポート必須（jspでは自動でインポートされてた）
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;  

//ブラウザでサーブレットを呼び出すためのパスを宣言。アプリケーションルートからの絶対パスで。
//以下の場合、http://localhost:8080/アプリケーション名/Test　で呼び出せる
@WebServlet("/Test") 
public class TestServlet extends HttpServlet { //HttpServletクラスの機能を引き継いで使う
   @Override //オーバーライドしていることを明示し、メソッド名や引数など誤りをコンパイラが通知

   //doGetメソッドをオーバーライド。
   //引数にはクライアントから送信された入力情報を管理するHttpServletRequestオブジェクトと
   //クライアントへ送信する出力情報を管理するHttpServletResponseオブジェクトを指定する
   protected void doGet(HttpServletRequest request,HttpServletResponse response)
    throws ServletException, IOException {
       response.setContentType("text/html;charset=UTF-8"); //ブラウザへ渡すコンテンツのタイプを指定
        request.setCharacterEncoding("UTF-8"); //ブラウザから受け取ったデータの文字コード指定
        response.setCharacterEncoding("UTF-8"); //ブラウザへ送るデータの文字コード指定
        PrintWriter out = response.getWriter(); //クライアントへ表示するためのインスタンス生成
        //htmlをゴリゴリ記述
        out.println("<html><head></head><body><h1>こんにちは！</h1><p>このページはサンプルです。</p></body></html>"); 
   }

   public void doPost(HttpServletRequest request,HttpServletResponse response)
     throws ServletException, IOException {

                 //POSTでアクセスされた時の処理を記述  
  
             }
}
```
※サーブレット2.5（Tomcat6.0）以前のものは@WebServletは使えないので`/WEB-INF`フォルダ内のweb.xmlにサーブレットを登録する。
※サーブレットクラスはリクエストのたびにインスタンス化されるのではなく、１回インスタンス化されたものを複数のユーザーで共有している。



##フォームの値を受け取る
JSPと同じような記述で受け取れる。

name属性「email」のフォームからpostで送られたものを受け取る場合

```html:フォーム画面（post.jsp）
<form method="POST" action="TestServlet">
 //普通にフォームを記述
</form>
```

```java:受け取るサーブレット（TestServlet.java）
package jp.co.test.sample01;

import java.io.IOException; 
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;  

@WebServlet("/Test") 
public class TestServlet extends HttpServlet { 

   @Override 
   protected void doPost(HttpServletRequest request,HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8"); 
        request.setCharacterEncoding("UTF-8"); 
        response.setCharacterEncoding("UTF-8"); 
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE html><html><head><meta charset='UTF-8'>");
        out.println("</head><body>");
        String email = request.getParameter("email");
        if(email.equals("") out.println("空です");
        out.println("</body></html>");
   } 

}
```

```text:フォルダ構成
/Test（アプリケーション名）
  |_post.jsp（フォーム画面）
  |_/WEB-INF
      |_classes
           |_/jp
              |_/co
                 |_/test
                    |_/sample01
                          |_TestServlet.java（コンパイル用javaファイル）
                               |_TestServlet.class（コンパイル済みのもの）
```


##フォワードを使って、JSPに表示を切り替える
フォワードは同じURL（「sample.jsp」など）のままでサーブレットなど違う処理ファイルへ移動し、そのままのURLで結果を取得できるもの。
ただし、リロードした際にはdoGetの内容が表示されてしまう。

1. ServletContextを取得する

```java
ServletContext app = this.getServletContext();
```

ServletContextは、現在動いているWebアプリケーションを管理するためのもの。
このインスタンス内に、Webアプリケーションに関する重要な機能がまとめられている。

2. RequestDispatcherを取得する

```java
RequestDispatcher dispatcher = app.getRequestDispatcher("/helo.jsp");
```

ServletContextから「RequestDispatcher」というインスタンスを取得。
これは、リクエストをディスパッチ（別のものに掛け替える）するためのもの。
フォワードがメソッドとしてあると思えばいい。

3. forwardメソッドでフォワードする

```java
try {
    dispatcher.forward(request, response);
} catch (ServletException e) {
    out.println(e);
}
```

##ファイルをアップロードする

```jsp:upload.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>ファイルアップ</title></head>
<body>
<form method="POST" enctype="multipart/form-data" action="UploadServlet">
<input type="file" name="file" size="80"><br>
<input type="submit" value="アップロード">
</form>
</body></html>
```

```java:UploadServlet.java
package jp.co.test.sample01;

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

@MultipartConfig(location="C:/tmp/") //①アップロードの設定をする（今回は一時保存先を指定）
@WebServlet("/UploadServlet") 
public class TestServlet extends HttpServlet { 

   @Override 
   protected void doPost(HttpServletRequest request,HttpServletResponse response)
    throws ServletException, IOException {
        Part part = request.getPart("file"); //②getPartでファイルを取得（戻り値はPartオブジェクト）
        String name = this.getFileName(part); //③アップされたファイル名を取り出す
        if(this.isValidFile(name)){ 
         part.write{ //④part.writeメソッドで指定のパスへファイルを保存
           getServletContext().getRealPath("/WEB-INF/data")+"/"+name); //仮想パスを絶対パスへ変換
           response.sendRedirect("Upload.jsp");
         }else{ response.getWriter().println("アップロードエラー"); }
       }
   }

   private String getFileName(Part part){　//ファイル名を取得
     String result = null;
     for(String disp : part.getHeader("Content-Disposition").split(";")){
       disp = disp.trim();
       if(disp.startsWith("filename")){
         result = disp.substring(disp.indexOf("=")+1).trim();
         result = result.replace("¥","").replace("¥¥","/");
         int pos = result.lastIndexOf("/");
         if(pos >= 0){
           result = result.substring(post+1);
         }
         break;
       }
      }
      return result;
     }

     private boolean isValidFile(String name){ //拡張子チェック
       if(name != null){
         String[] perms = { "fig","jpg","jpeg","png"};
         String[] names = name.split("¥¥.");
         for(String perm: perms){
           if(perm.equals(names[names.length-1])){ return true; }
         }
       }
       return false;
     }
}

```

##文字コードなどを一括で設定する
毎回毎回、文字コードやパスを設定するのは面倒＆変更した時の修正が面倒なので、設定ファイル`web.xml`に定義して、それを読み込むようにする。

```java:受け取るサーブレット（TestServlet.java）
import javax.servlet.annotation.WebInitParam; //initメソッドを使うため読み込み
 
@WebServlet("/Test") 
public class TestServlet extends HttpServlet { 
   private String path = null;

   @Override //initメソッドはサーブレットクラスが初めて呼び出された時だけ実行される
   public void init(ServletConfig config) throws ServletException{
     super.init(confg);
     //初期化パラメータの値をインスタンス変数pathにセットし、保存先パスなどに使う
     this.path = config.getInitParameter("path");
   }
   //・・・
}
```

```xml:web.xml
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  http://java.sun.com/sml/ns/javaee/we-app_3_0.xsd"
  version="3.0">
  //・・・
  <servlet>
   <servlet-name>TestServlet</sevlet-name>
   <servlet-class>jp.co.test.sample01.TestServlet</servlet-class>
   <init-param>
     <param-name>path</param-name> //変数定義
     <para-value>/WE-INF/img/</param-value> //変数内の値を定義
   </init-param>
  </servlet>
  //・・・

```
※<servlet>要素内で宣言された初期化パラメータは指定したサーブレットクラスでしか参照できないので、全サーブレットで参照できるようにするには<context-param>要素で宣言する。


#いくつかのURLから１つのサーブレットを呼び出す
いくつかのリクエストを１つのサーブレットで受け取るものを「フロントコントローラ」という。
例えば、URLが`~/FrontServlet/mypage1`や`~/FrontServlet/mypage2`でも、同じサーブレットを呼び出し、そのサーブレットの中で処理を切り分ける。

```
package jp.co.test.sample01;

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

@WebServlet("/FrontServlet/*") //アスタリスク以下のURLが何指定されてもこのサーブレットを呼び出す
public class FrontServlet extends HttpServlet{
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException{
     response.setContentType("text/html:charset=UTF-8");
     PrintWriter out = response.getWriter();
     out.println("<pre>");
     out.println("リクエストされたURLは"+request.getRequestURL());
     out.println("リクエストされたURIは"+request.getRequestURI());
     out.println("サーブレットパスは"+request.getServletPath());
     out.println("拡張パスは"+request.getPathInfo()); //クエリ情報に相当する部分
     out.println("<?pre>");
  }
}
```
※拡張パスとして入力された情報（「list/1023」などスラッシュで区切られたもの）をサーブレット側で解析し、処理の判断をする。
※クエリ情報で動的に変化させるページだと検索エンジンがクローリングしてくれない場合があるので、SEOとしても動的に切り分けるページの場合は拡張パスでやったほうがいい

#JSPとサーブレットの連携
入力画面jspからサーブレットへ値を送り、サーブレットから出力画面jspへ値を送る。
サーブレットからjspへ値を送るにはsetAttributeを使う。
setAttributeは「リクエスト属性」に指定の変数を登録するもの。
リクエスト属性とは、「クライアントがリクエスト要求してから、クライアントへ応答を返すまで」の間だけ保持される変数のこと。

```jsp:bmi.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>テスト連携</title>
</head>
<body>
<form method="POST" action="TestServlet">
<label name="height">身長：<input type="text" name="height">m</label>
<label name="weight">体重：<input type="text" name="weight">kg</label>
<input type="submit" value="計算する">
</form>
</body>
</html>
```

```java:TestServlet.java
package jp.co.test.sample01;

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

@WebServlet("/TestServlet") 
public class FrontServlet extends HttpServlet{
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException{
     double h = Double.parseDouble(request.getParameter("height"));
     double w = Double.parseDouble(request.getParameter("weight"));
     double bmi = w/(h*h);
     request.setAttribute("bmi",bmi); //setAttributeでjspへ渡す変数名と値を設定
     if(bmi < 18.5){
       request.setAttribute("rank","やせ");
     }elseif(bmi < 25){
       request.setAttribute("rank","標準");
     }else{
       request.setAttribute("rank","肥満");
     }
     //jspへ渡すため、RequestDspatcher.forwardメソッドを呼び出す。
     //RequestDispatcherオブジェクトを取得するにはServletContext.getRequestDispathcerメソッドを使う
     this.getSevletContext().getRequestDispatcher("/bmi_result.jsp").forward(request,response);
  }
}
```

```jsp:bmi_result.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>テスト連携</title>
</head>
<body>
<p>身長:${param['height']}</p> //フォワードを使うことで、フォームの値をそのまま使用できる
<p>体重:${param['weight']}</p>
<p>BMI:${requestScope['bmi']}</p>
<p>結果:${requestScope['rank']}</p>
</form>
</body>
</html>
```

```text:フォルダ構成
/Test（アプリケーション名）
  |_bmi.jsp（フォーム画面）
  |_bmi_result.jsp（結果画面）
  |_/WEB-INF
      |_classes
           |_/jp
              |_/co
                 |_/test
                    |_/sample01
                          |_TestServlet.java（コンパイル用javaファイル）
                               |_TestServlet.class（コンパイル済みのもの）
```

##リダイレクトとフォワードの違い
1．リダイレクトはサーバー側がクライアントへ強制的にページBをリクエストさせるので、内部的に２往復の通信をしている。

```tex
■リダイレクト
クライアントがページA要求　→　サーバーがリダイレクトを応答　→　クライアントがページB要求　→　サーバーがページBを応答
■フォワード
クライアントがページA要求　→　サーバー内でページAからBへ処理を転送　→　サーバーがページBを返す
```

2．リダイレクトだとクライアントがページBを要求した場合、そのリクエストは他のリクエストの最後尾になるので、トラフィックが多い場合、ページBが表示されるまで時間がかかる。

3．リダイレクトだと内部的に２往復しているので、ポストデータやクエリ情報、リクエスト属性は引き継げないが、フォワードであれば１つのリクエスト・レスポンス内なので、引き継げる。

4．フォワードは外部のサーバーへは使えない。（http://~などと指定しなければいけない場合）

#複数のユーザー間で値を共有したい場合
##JSPでやる場合

```jsp
<%
  application.setAttribute(属性名,値); //変数を共有したい場合
  application.getAttribute(属性名); //共有している変数を受け取る場合
%>
```

##サーブレットでやる場合

```java
ServletContext app = this.getServletContext(); //ServletContextオブジェクトを明示的に取得
```

#JavaBeansを使う
JavaBeansは部品化できるようにルールづけしたクラスのことをそう呼んでいるだけ。
今までは、JSPで画面を出力し、サーブレットで内部処理（ビジネスロジック）をしていたが、
サーブレット内には○○のname属性の値を取得して～○○の変数で出力して～と本来のデータ処理のほかに「データ受け取り・受け渡し」の部分などが含まれている。
そういった処理はどのページでも共通にも関わらず、name属性やレイアウトが変わっただけで使いまわせなくなってしまう。
なので、切り離して再利用性を高めた方がいい。こういう設計方法をMVCモデルという。
JavaBeansはMVCモデルでいうところの、モデル部分。
JavaBeansでモデルを記述し、JSPでViewを実装、サーブレットでコントローラーとして制御する。

##JavaBeansクラスのルール
###1．Serializableインターフェースを実装していること
オブジェクトはフィールドとメソッドを持つ構造だが、そのオブジェクトをそのままDBやファイルへ保存することはできないので、Serializableを実装することで「直列化（バイト列へ変換）」し保存することが出来る。
###2．引数のないコンストラクタがあること
###3．アクセサメソッド（ゲッター、セッター）を定義すること。いわゆるカプセル化。
アクセサメソッドを使うことで、変数に書き込みだけ出来るようにしたいなどの制約をさせたり、
メソッド内で処理が記述できるので、書き込む内容を制限（整数だけとか）したり出来る。


```java:TestServlet.java
package jp.co.test.sample01;

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

@WebServlet("/TestServlet") 
public class FrontServlet extends HttpServlet{
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException{
     Bmi bmi = new Bmi(); //Bmiクラスをインスタンス化
     
      bmi.setHeight(Double.parseDouble(request.getParameter("height")));
     bmi.setWeight(Double.parseDouble(request.getParameter("weight")));
     bmi.calculate();
     request.setAttribute("bmi",bmi); //bmiオブジェクトをリクエスト属性bmiにセット
     //jspへ渡すため、RequestDspatcher.forwardメソッドを呼び出す。
     //RequestDispatcherオブジェクトを取得するにはServletContext.getRequestDispathcerメソッドを使う
     this.getSevletContext().getRequestDispatcher("/bmi_result.jsp").forward(request,response);
  }
}
```

```java:Bmi.java
package jp.co.test.sample01;

import java.io.*;

public class Bmi implements Serializable{ //ルール１：Serializableを実装
　
  //ルール３：カプセル化のためにprivateで変数への外部からのアクセスを制限
  private double height = 0;
  private double weight = 0;
  private double bmi = 0;
  
  public Bmi(){} //ルール２：引数のないコンストラクタを定義する。中身が空なら定義しなくてもいい。
  
  //ルール３：アクササメソッドを定義
  public double getHeight(){ return this.height; }
  public double getWeight(){ return this.weight; }
  public double getValue(){ return this.bmi; } 
  public String getRank(){
    if(this.bmi < 18.5){
     return "やせ";
    }
  } 
  public void setHeight(double height){ 
    if(height > ){ this.height = height; }
  }
  public void setWeight(double weight){ 
    if(height > ){ this.weight = weight; }
  }

  public void calculate(){
    this.bmi = this.weight / (thiw.height * this.height);
  }

```

```jsp:bmi_result.jsp
<p>身長:${param['height']}</p> <!-- フォワードを使うことで、フォームの値をそのまま使用できる -->
<p>体重:${param['weight']}</p>
<p>BMI:${requestScope['bmi'].value}</p> <!-- getValueメソッドを呼び出してる -->
<p>結果:${requestScope['bmi'].rank}</p> <!-- getRankメソッドを呼び出してる -->
```
※`${requestScope['bmi'].rank}`は`${bmi.rank}`と書いてもいい

#デプロイメントディスクリプタ
JSP/サーブレットの標準設定ファイルのこと。
Webアプリケーションの配置情報を記述したXML形式のファイル。
使用しているコンテナによってファイル名が違ったりする。(Tomcatではweb.xml)

サーブレットの登録やセッション情報、初期化パラメータやウェルカムページ、エラーページ、認証の定義など設定（定義）できる。

##web.xmlの配置場所
レベルによって２種類ある。
全アプリケーションの設定・・・`%CATALINA_HOME%/conf/web.xml`
現在のアプリケーションのみの設定・・・'(アプリケーションルート)/WEB-INF/web.xml'
※基本/conf/web.xmlは触らないこと

##web.xmlの最低限の構成

```xml:
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">

  <!-- 要素を指定していく -->

</web-app>
```

##<web-app>要素内に記述できる主な設定要素

```text:
要素名　　　　　　　　　　　　　概要
<icon>　　　　　　　　　　　　　GUIツールに表示するアイコン画像
<display-name>　　　　　　　　GUIツールに表示するアプリケーション名
<description>　　　　　　　　　GUIツールに表示する備考情報
<content-param>※　　　　　　　初期化パラメータ
<filter>※　　　　　　　　　　　フィルタクラスを登録
<fileter-mapping>※　　　　　　フィルタの適用範囲
<listener>※　　　　　　　　　　リスなクラスを登録
<servlet>※　　　　　　　　　　サーブレットクラスを登録
<servlet-mapping>※　　　　　　サーブレット呼び出しのためのURI
<session-config>　　　　　　　セッション情報（有効期限）
<mime-mapping>※　　　　　　　MIMEタイプ
<welcome-file-list>　　　　　ウェルカムページ
<error-page>※　　　　　　　　エラーページ
<jsp-config>　　　　　　　　　JSPページの設定情報
<security-constraint>※　　　アクセス制限の適用範囲
<login-config>　　　　　　　　ログイン方法
<security-role>※　　　　　　　認証に使用するロール名を登録
```
※の要素は複数記述できる

#XML文書の書き方
1．「要素」と「属性」で構成されている

```text:
<要素名 属性名="属性値" ・・・>　データ　</要素名>
```
※要素名は大文字小文字が区別される
※属性値はダブルクウォートもしくはシングルクウォートで囲む

2．XML文書だということを宣言する

```xml:
<?xml version="1.0" encoding="UTF-8" ?>
```

##xml内要素を定義する

```xml:web.xml
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">

  <!--全サーブレット共通のパラメータを定義-->
  <context-param>
    <param-name>sample.title</param-name>
    <param-value>テストタイトル</param-value>
  </context-param>

  <!--エラーページを定義。今回の場合、java.lang.Exception例外に対して/ErrorServletを表示する-->
  <error-page>
    <exception-tpe>java.lang.Exception</exception-type>
    <location>/ErrorServlet</location>
  </error-page>
  <!--エラーページを定義。エラーコードごとにも定義できる-->
  <error-page>
    <error-code>404</error-code>
    <location>/404error.jsp</location>
  </error-page>
</web-app>
```

```jsp:jspでパラメータを受け取る場合
${initParam['sample.title']}
```

```java:サーブレットでパラメータを受け取る場合
ServletContext application = this.getServletContext();
application.getInitParameter("sample.title");
```

```ErrorServlet.java
package jp.co.test.sample01

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

@WebServlet("/ErrorServlet")
public class ErrorServlet extends HttpServlet{
  @override
  protected void doGet(HttpServletRequest request.HttpservletResponse response)
    throws ServletException, IOException{
     ServletContext app = this.getServletContext();
     StringBuffer sb = new StringBuffer();
     sb.append(new java.util.Date()); //エラー発生日時を記録
      sb.append(System.getProperty("line.separator")); //改行
      sb.append(request.getAttribute("javax.servlet.error.status_code")); //HTTP応答ステータスコード
      sb.append(System.getProperty("line.separator")); //改行
      sb.append(request.getAttribute("javax.servlet.error.request_uri")); //エラー場所
      sb.append(System.getProperty("line.separator")); //改行
      sb.append(request.getAttribute("javax.servlet.error.message")); //エラーメッセージ
      app.log(sb.toString()); //エラー情報をデフォルトのログファイルに記録
      response.sendRedirect(request.getContextPath()+"/error.jsp");
  }
}
```
※ログは外部から見えない様に/WEB-INFフォルダ内か`%CATALINA_HOME%/webapps`フォルダの外に配置する

```text:error.jsp
時間を空けて再度アクセスしてください。的な内容を表示する。
```

#JARファイルの配置場所
`%CATALINA_HOME%/webapps/<アプリケーション名>/WEB-INF/lib`

#WEBプログラミングから起業までを一貫して学べるオンライン動画総合学習サービス『ウェブカツ！！』
様々なプログラミング学習サイトやサービスでは正直な所、自分でWEBサービスを作れるようにはならないため、「自分でWEBサービスを作れるようになる！」をゴールとしたオンライン動画総合学習サービス『ウェブカツ！！』を立ち上げました。興味ある方は登録よろしくお願いいたします。

#Javaアプリケーションのファイル構成

```
プロジェクトフォルダ
	｜_ Javaリソース
			|_ src
				|_servlet　←パッケージ
					|_サーブレットファイルが入っている
				|_model ←パッケージ
					|_普通のjavaファイル（クラス）を置く場所
	|_WebContent
		|_静的なHTMLファイルや動的なJSPファイルを置く場所
		|_WEB-INF
			|_ブラウザからリクエストできないが、フォワードで使いたいJSPファイルを置く場所
			|_lib
				|_JARファイルを置く場所
```