csWindows31J

HTTPレスポンスヘッダのcontentType

JSPの先頭には次のような1行を書くのが通例だ。

<%@ page contentType="text/html; charset=Windows-31J" pageEncoding="Windows-31J" %>

このcontentTypeの部分が最終的にはHTTPレスポンスヘッダに展開される。
機種依存文字が文字化けするからShift_JISではなくWindows-31Jを使いましょう、と。だからAjaxプログラミングをしようと思った場合もサーバー側のプログラムは当然こんな風に作るだろう。

  response.setContentType("text/html; charset=Windows-31J");
  PrintWriter writer = response.getPrintWriter();
  writer.println("{age:27}");
  writer.close();

ちなみにクライアント側のサンプルも載せておきます。jQueryを使用したajax呼び出し。

  $.getJSON('http://localhost:5555/sample/getajaxdata', {}, function(result){ alert(result.age); });

これで画面には「27」と表示される。
・・・と思いきやこのプログラムはIEでは動作しない。こういうのはまるわー。結論を先に言うとサーバー側プログラムのcharsetをWindows-31JではなくcsWindows31Jとすればよいのだ。http://d.hatena.ne.jp/kusakari/20070720/1184928455#tbに詳しくあります。本当に助かりました。

csWindows31Jって?

ところで初めて聞いたけどこのcsWindows31Jって何よって話。名前から考えるとWindows-31Jの別名だと想像できる。事実、http://d.hatena.ne.jp/Kazzz/20050614/p1を読んでみると

これはIANAでは"Windows-31J"のエイリアスとして登録されている名前なので

とあり、やはりWindows-31Jの別名のようだ。しかしその後に不可解なことが書いてある。

このエンコーディング名"csWindows31J"ですがWindowsXPのレジストリ上では"Shift_JIS"のエイリアスとして登録されているのです。

え!?
ということは、AjaxのところでWindows-31Jの代わりにcsWindows31Jを使用すればOKということになっていた訳だけど、実はWindows-31JではなくShift_JISという扱いになってしまうってことか。機種依存文字とかが文字化けするやん(汗)
・・・と思ってやってみたけど特に文字化けしなかった。あれ、Shift_JISって文字化けしなかったっけ?ちょっと不安になったのでcharsetの部分をShift_JISにして再度実験してみると予想通り機種依存文字が文字化けした。ほっ。
でもおかしいな・・・うーむ・・・
この実験結果から分かる事といえば、OS上では「csWindows31J=Shift_JIS」だけどIE上では本来の「csWindows31J=Windows-31J」ってことなんだろうな。あってるよね!?ややこしや〜。

追記 2008/12/24

さらに調査を続けて分かったことがあったのでメモ。
Ajaxリクエストの時だけcharsetをcsWindows31Jにして通常リクエストの時はcharsetをWindows-31Jにするってのは面倒なので常にcsWindows31Jにした方が統一されてていいんじゃないかとjspヘッダ部をこのようにしてみました。

<%@ page contentType="text/html; charset=csWindows31J" pageEncoding="Windows-31J" %>

このやり方で問題ないかどうかを確認するための実験をしてみます。
まずHTMLのHEAD部に次のようなメタタグを付与してみます。

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

ブラウザの文字エンコーディングの解釈は、次の順で行われると理解しています。

  1. HTTPレスポンスヘッダのcontentType
  2. METAタグのContent-Type

csWindows31Jがうまく認識されていれば正しく表示されるし、認識できていなければUTF-8と解釈して全ての全角文字で文字化けが起こるはずです。
実験結果としては、以下のようになりました。

IE firefox
×

事実、firefoxの文字エンコーディングを確認してみるとUnicode(UTF-8)が選択されていました。
当然ですが、ajax版もfirefoxでは文字化けが起こりました。
IEだけしか動作保障していないような場合はcsWindows31Jで統一してもよさそうですが、firefoxなど他のブラウザも対象になっている場合はひと工夫が必要のようです。

疑問

csWindows31Jをfirefoxが認識していないからMETAタグを参考にUTF-8だと判定したとみて間違いないと思うんですが、試しにjspヘッダ部のcharsetを

<%@ page contentType="text/html; charset=xxxx" pageEncoding="Windows-31J" %>

に変えてみたところ、200OKは返ってきてるもののfirefox上では全く何も表示されなくなりました。
同じくMETAタグが優先されると思ってたんだけどな。。
ということはcsWindows31Jを全く認識していないというわけではないのか!?うーん、分からん・・・

jQueryのeachメソッドの逆

$('#sel').children(':selected').each(function(){ 処理 });

ってやると、複数のオブジェクトが取得できている場合、取得順にぐるぐる回るわけですがこれを逆向きに回したい。
普通のfor文なら

for(var i=ary.length-1; i>=0; i--) {
}

こんな感じで逆から回していけばいいけどjQueryオブジェクトの場合どうやるんだろうっていうのが疑問だった。
jQueryでは、複数の値が取得できたとしてもオブジェクトとしては1つなので、そういうメソッドがあるんだろうとeachの逆に該当するメソッドを探すも見つからず。
とあるところで教えてもらいました。

$($('#sel').children(':selected').get().reverse()).each(function(){ 処理 });

getメソッドでいったん通常の配列にし、それを配列のreverseメソッドで逆にしておいてからもう一回jQueryオブジェクトにして、eachでまわす、と。
スッキリ~♪
本当はeachの逆メソッドがあると便利なんだけどな〜。って自分で拡張すればいいんだけど。

jQueryでselectで選択したものだけ消す

<select name="hoge" id="sel" multiple="multiple">
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
</select>

っていうSELECTタグから、選択したものだけ消すってのをjQueryでやってみる。

$('#sel option:selected').remove();

$('#sel').children(':selected').remove();

は同じ

jQueryの$(this)

$(this)の使い方としてよくあるサンプルは、

$(":text").each(function(){ alert($(this).val()); });

こんなやつ。eachでぐるぐる回しているときのそれぞれのターゲットを参照する時に使う。
それが、

<input type="text" name="hoge" value="hoge!" onclick="alert($(this).val());">

ここでも使えたよ、というだけです。ある時「あっ」と思ってやってみたら予想通り使えたもんで嬉しくなり書いてみました。

Struts×JSON.simple×jQueryでJSONオブジェクトをajaxでやり取り

今更感ありありですが、これらの組み合わせでやったのは初めてだったのでメモしておきます。
やり取りするのはこんなJSONデータ。

[{"name":"太朗", "age":27}, {"name":"花子", "age":25}]

想定としては検索ボタンをクリックすると、上記データがサーバーから送られてきて以下のようにSELECTに展開するというものをやってみます。

<SELECT name="users" id="users">
  <OPTION value="0">太朗(27)</OPTION>
  <OPTION value="1">花子(25)</OPTION>
</SELECT>

クライアントサイド

まず用意しておくhtmlはこんな感じ。

<INPUT type="button" name="search_button" id="search_button" value="検索">
<SELECT name="users" id="users"></SELECT>

つづいてjavascriptはこんな感じ。

$(function(){
  $("#search_button").click(function(){
    $.getJSON(
      "http://localhost:8080/sample/user_search.do",
      function(result){
        for(var i=0; i<result.length; i++){
          $("<OPTION></OPTION>").val(i).text(resut[i].name + "(" + result[i].age + ")").appendTo("#users");
        }
      }
    );
  });
});

JSONオブジェクトをやり取りするのであれば、Ajax.getJSON関数が便利。いちいちevalしてオブジェクト化しなくても即使えます♪

サーバーサイド

JSON形式の文字列を返す際、自分で組み立ててもいいんですが既にライブラリがあるのでこれを利用します。
http://www.json.org/java/simple.txt
では、StrutsのActionクラスです。

public ActionForward execute(ActionMapping mapping,
                             ActionForm form, 
                             HttpServletRequest request, 
                             HttpServletResponse response) {
  JSONObject obj1 = new JSONObject();
  obj.put("name","太朗");
  obj.put("age",27);
  JSONObject obj2 = new JSONObject();
  obj.put("name","花子");
  obj.put("age",25);

  JSONArray json = new JSONArray();
  json.add(obj1);
  json.add(obj2);

  PrintWriter writer = response.getWriter();
  writer.print(json.toString());
  writer.close();

  return null;
}

最後をreturn null;とするところがポイントかな。

javascriptの縮小化

ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール

ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール


フロントエンドでの高速化を実現する14のルールが紹介された本。大分前に買っていていたんですがやっと読み終わりました。とは言ってもただ読んで無かっただけ。。150Pくらいなので非常に薄く読みやすいです。14のルールのうち「ルール8:JavaScriptCSSは外部ファイル化する」「ルール10:JavaScriptを縮小化する」をAntを使って手順の自動化を実現してみました。手順をまとめると次のようになります。

  1. インライン化されているJavaScriptを外部ファイルにまとめる
  2. JavaScriptファイル群を1つにまとめる
  3. 最後に圧縮する

とはいえ、1の手順は自動化できないので手動でまとめます。自動化するのは2番と3番の手順。
2番目の手順にはgroovyを使って1つのファイルにマージします。本当はAntタスクで実現できればよかったんですが、いいのが見つかりませんでした。「js」という名前のディレクトリに「a.js」「b.js」「c.js」といったような複数のjsファイルが存在している場合にこれらをまとめて1つのファイル「merge.js」を作成します。
3番目の手順にはYUI Compressorを使用します。YUI Compressorはjavaで作られているのでAntと相性がいいんです。libフォルダにyuicompressor-2.3.6.jarを配置しておきましょう。ちなみにYUI Compressorの使い方はこのようにします。

$java -jar yuicompressor-x.y.z.jar myfile.js -o myfile-min.js

では最後にbuild.xmlです。

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

<project name="antsample">
	<property name="js.dir" value="js" />
	<property name="js.file" value="${js.dir}/merge.js" />
	<property name="js.min.file" value="${js.dir}/merge-min.js" />
	
	<path id="build.classpath">
		<fileset dir="lib" includes="*.jar" />
	</path>

	<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.classpath" />

	<target name="compress">
		<delete file="${js.file}" />
		
		<groovy>
			targetFile = new File(properties['js.file'])

			new File(properties['js.dir']).eachFile{
				targetFile.append(it.text)
			}
		</groovy>

		<java jar="lib/yuicompressor-2.3.6.jar" fork="true">
			<arg line="${js.file} -o ${js.min.file}" />
		</java>
	</target>

</project>

YUI 3.x Preview Release 1

http://developer.yahoo.com/yui/3/
YUI!3がまだ正式ではないけどリリースされたので触ってみた。とりあえずサンプルとして2つのことをしてみた。

  • リストに対して動的にスタイルシートを適用する
  • 「morning」「hello」「evening」がリスト表示されていて、それぞれをクリックするとクリックした文字を表示する
<html>
<head>
<style type="text/css">
.demostyle {
  list-style-type: none;
  width: 100px;
  border: 1px solid red;
  background-color: pink;
  margin: 2px;
  padding: 3px;
}
</style>
<script type="text/javascript" src="build/yui/yui.js"></script> 
<script type="text/javascript" src="build/oop/oop.js"></script> 
<script type="text/javascript" src="build/event/event.js"></script> 
<script type="text/javascript" src="build/dom/dom.js"></script> 
<script type="text/javascript" src="build/node/node.js"></script> 
</head>
<body>
<ul id="demo">
  <li>morning</li>
  <li>hello</li>
  <li>evening</li>
</ul>

<script type="text/javascript">
YUI().use('*', function(Y) { 
    Y.get('#demo').get('children').addClass('demostyle');
    Y.all('#demo li').on('click', function(e){ alert(e.currentTarget.get('innerHTML')); }); 
}); 
</script>

</body>
</html>

気づいた点としてはjQueryに似てメソッドチェーンが出来るようになっているところ。多分2.xはできなかったはず。あとオブジェクト名が短くなっている!YAHOO.lang.JSONはY.JSON、YAHOO.util.CookieはY.Cookieってな具合に。メソッド名も短くなったかな。