設定ファイル
もうアノテーションで全部指定できるから、個人的な開発ではほぼ不要かな。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>tomcatTest20150719</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>com.example.ListenerSample</listener-class>
</listener>
<context-param>
<param-name>hoge</param-name>
<param-value>HOGE</param-value>
</context-param>
<!-- フィルター -->
<filter>
<filter-name>FilterSample</filter-name>
<filter-class>com.example.FilterSample</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterSample</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
webリスナー。起動時、終了時
tomcatが起動した時とかwarファイルを更新した時とかにcontextInitializedが一度だけ、終了時にはcontextDestroyedが一度だけ。
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@javax.servlet.annotation.WebListener
public class WebListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent paramServletContextEvent) {}
@Override
public void contextInitialized(ServletContextEvent paramServletContextEvent) {
paramServletContextEvent.getServletContext().setAttribute("hoge", "ok");
}
}
コンテキストに共通のインスタンスを作成する方法
コンテキスト全体で共通のインスタンスを持たせたい時がある。例えばアプリ全体で共通のカウンターが欲しい時、共通のIntegerオブジェクトが必要になる。staticでシングルトンを使うとjvm共通になって別のwebアプリと被ってしまうから出来ない。
そんな時はServletContext.setAttribute(String,Object);を使う。これならwebアプリでそれぞれインスタンスを持てる。
もちろん、webアプリを再起動させた時はクリアされるから、ServletContextListenerクラスのcontextDestroyedメソッドの中でonSaveとかの処理をする。contextDestroyedメソッドの中で時間のかかる処理をしていると、webアプリの再起動がその分遅くなるから注意。必要ならServletContextListenerクラスのcontextInitializedメソッドで初期化を行っても良い。
以下のクラスを作る。特に何かを継承したりしなくてもよい。
import java.io.File;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.servlet.ServletContext;
public class CustomWebListenerManager {
private static final String getTag(ServletContext sc) {
String tag = String.format(Locale.US, "%s-%x", CustomWebListenerManager.class.getName(), System.identityHashCode(sc));
return tag;
}
public static CustomWebListenerManager getInstance(ServletContext sc) {
String tag = getTag(sc);
Object attribute = sc.getAttribute(tag);
if (attribute != null) {
return (CustomWebListenerManager) attribute;
}
CustomWebListenerManager instance = new CustomWebListenerManager(sc);
sc.setAttribute(tag, instance);
return instance;
}
public final String storagePath;
private CustomWebListenerManager(ServletContext sc) {
//好きな処理を書く
}
}
そして実際にインスタンスを取得する時はこうする
import java.io.IOException;
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({ "/hogeGet" })
public class FriendServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
String path = CustomWebListenerManager.getInstance(request.getServletContext()).storagePath;
System.err.println(path);
}
}
フィルター
↓リクエスト内容を弄くるフィルター
import javax.servlet.Filter;
public class FilterSample implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
}
}
サーブレット
@WebServlet({ "/url1","/url/sub2"})
public class AnyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("tweets", any object);
//サーブレットで色々なデータをsetAttributeして、jspで表示する
request.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(request, response);
//サーブレットを用意するのが面倒な時はこれでよい
responce.getWriter().write("hoge");
}
}
上記コード内の様にjspを指定した場合、そのjspを配置する場所は以下のとおり
jspファイル
プログラムの中でprintln("<html>");
ってやるのがめんどいのでphpっぽく書く方法。基本的にはサーブレットの中でsetAttributeした物をgetAttributeして色々使う。getAttributeの結果はObjectなのでキャストしないといけない。
<%@ page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<% String title=(String)request.getAttribute("title");
//複数行書ける
%>
<%!
// メソッドはここに書く
String getHoge(){
return "hoge";
}
%>
<!DOCTYPE html>
<meta charset="utf-8">
<title><%=title%></title>
つまり、<%なんとか%>
で囲った部分でjavaの処理が書けるという事。ループとか条件分岐もこれで囲う。クラスに対してgetterがしっかり実装されている時は${hoge.kage}
というより短い書き方が出来る。
jspファイルをincludeする
jspファイルをinclude出来る。注意点として、paramで指定できるvalueは文字列型のみ。オブジェクト駄目。パラメーターが色々あるjspファイルをincludeする時はparamタグの量が凄いことになる。jspの中でも<%request.setAttribute("key", object);%>
って出来るけど、グローバル変数的な感じでinclude先限定じゃなくなるから扱いが大変。attributeのキーが被ってもeclipse警告してくれないし。child.jsp側ではrequest.getParameter("")
で文字列を受け取る。俺の環境のEclipseでは自動補完のままjsp:paramタグを作ると、name valueでなくvalue nameの順番で属性値が入力されてしまい、それに気が付かずにnameに変数を入れて怒られる。
valueの項目に、例えば文字結合とかでダブルクオーテーションを使う時は、二重にエスケープする必要がある。複雑な値は<%String val=xxxx;%>
で別途変数に入れてからvalue属性として指定したほうがいいね
<jsp:include page="include/child.jsp" >
<jsp:param name="userId" value="<%=userId%>"/>
<jsp:param name="userId2" value="<%=userId2%>"/>
<jsp:param name="userId3" value="<%=(\"./\"+user.getUserId()) %>"/>
</jsp:include>
jspファイルの中で使える変数
jspファイルの中ではrequest変数とかが宣言ナシで使えるけど、宣言ナシで使える変数の一覧。使いみちがあるのはrequest、responce、session、application、config、out くらいかな
javax.servlet.http.HttpServletRequest request;
javax.servlet.http.HttpServletResponse response;
javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = pageContext.getSession();
javax.servlet.ServletContext application=pageContext.getServletContext();
javax.servlet.ServletConfig config=pageContext.getServletConfig();
javax.servlet.jsp.JspWriter out = pageContext.getOut();
java.lang.Object page = this;