戯言

つらつらと気づいたことを書いていきます。人狼とか。

RESTを利用したアクセスで、IEでは最新の情報を取得できない


IEでは、RESTを利用したアクセスで、サーバ側の最新の情報を取得できなかった。ブラウザ側にキャッシュされているらしく、サーバ側から渡すデータが変更になっているのに、サーバに再アクセスしても変更前のデータが表示されてしまう。Chromeでは問題ないのに…。
Webサーバへのアクセス状況などを調べていたら、やはりIEではキャッシュした情報を表示していて、サーバと通信していなかった。

この事象を回避するためには、サーバ側からブラウザに、キャッシュしないように指示するレスポンスを返しておく必要があります。

キャッシュ関係はブラウザ側やサーバ側でヘッダやブラウザ固有の事象など、いろいろと絡んできて厄介なんですが、とりあえずこれくらいのヘッダーを付与しておけば、いろんなブラウザでも大丈夫になるらしい。

"Cache-Control"に、"no-cahce"
"Pragma"に、 "no-cahce"
"Expires"に、 "-1"

さっそく、JerseyでHTMLレスポンスのヘッダに、これらを付与しようとしていたら、
javax.ws.rs.core.Response.ResponseBuilder.cacheControl(CacheControl arg0)
javax.ws.rs.core.Response.ResponseBuilder.expires(Date arg0)

などという、Jerseyの便利そうな名前のメソッドを発見したので、使ってみました。

CacheControl cc = new CacheControl();
cc.setNoCache(true);
return response.cacheControl(cc).expires(new Date(0))

こうすれば、上記3つのヘッダを上手いこと送ってくれます。
new Date(0) など指定しているので、valueは変わります。

もちろん、このメソッドは使わずに、javax.ws.rs.core.Response.ResponseBuilder.header(String arg0, Object arg1)を利用して、一つひとつヘッダを付与する方法でも可能です。

これで、IEでもキャッシュを使用せずに、サーバにアクセスしてくれるようになりました。




Apache Commons DbUtilsの勧め


Apache Commons DbUtilsを使うと、DB接続時に使用する処理をある程度カプセル化でき、 接続・切断コーディング(特に例外処理など)を簡素化したり、 select結果の固有のBeanに格納したりすることもできます。

Apache Commons DbUtilsを使っていない場合と、使った場合でのコード例は次のようになります。
なお、両者とも接続部はコンストラクタを使用することにしています。

一目瞭然ではないでしょうか。dbutilsを使わない場合は、直接の動作とは無関係の例外処理のコードが多くなりますが、dbutilsを使うと、その辺りは全て記述しなくてよくなります。


使わない場合
private Connection conn;
public XXXDB() throws ClassNotFoundException, SQLException {
	try{
		InitialContext ic = new InitialContext();
		DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/saldb");
		conn = ds.getConnection();
	}
	catch (NamingException ex){
		ex.printStackTrace();
	}
}

public void getXXXXXXXX(){
	Statement state = null;
	ResultSet rs = null;
	String query = "select ・・・・・・・・・・";
	try {
		state = conn.createStatement();
		rs = state.executeQuery(query);
		while (rs.next()){
			//
			// データ取得後の処理
			//
		}
	} catch (Exception ex) {
		ex.printStackTrace();
	} finally {
		try {
			if (rs != null) rs.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		try {
			if (state != null) state.close();
		} catch (SQLException ex) {
			ex.printStackTrace();
		}
	}
}

使う場合
private QueryRunner qr;
public XXXDB(){
	try{
		InitialContext ic = new InitialContext();
		DataSource ds = (DataSource)ic.lookup("java:comp/env/jdbc/xxxdb");
		qr = new QueryRunner(ds);
	}
	catch (NamingException e){
		e.printStackTrace();
	}
}

public void getXXXXXXXX(){
	String query = "SELECT ・・・・・・・・・・・・・・・";
	ResultSetHandler<?> rsh = new MapListHandler();
	try{
		List<Map<String, Object>> list = (List<Map<String, Object>>)qr.query(query, rsh);
		//
		// データ取得後の処理
		//
	}catch(SQLException e){
		e.printStackTrace();
	}
}

また、結果をMap(keyにカラム名、valueに値)として返したり、複数行であればこのMapのListを返すこともできます(上記の例のように)。さらには、Beanクラスを定義しておけば、Beanクラスで返すこともできるので、ResultSetから一つひとつ値を取り出してごちゃごちゃする処理から、おさらばできます。