ユーザのタイムゾーンや日付と時刻の形式に対応するためのサンプルプログラム¶
本章では、ユーザが設定したタイムゾーンや日付と時刻の形式に従って、画面表示したり、画面から入力できるようにするためのサンプルプログラムを紹介します。 本章で紹介するサンプルプログラムは以下の考え方に基づいています。
前提¶
サンプルプログラムは、以下のテーブルが作成されていることを前提としたプログラムです。
テーブル定義
CREATE TABLE example_table ( user_cd VARCHAR(100) NOT NULL, update_date TIMESTAMP NOT NULL, PRIMARY KEY (user_cd) );example_table テーブルの参照や更新を行うために、「データベース」に従って作成されたエンティティクラスとリポジトリインタフェースが用意されていることを前提とします。
データベースアクセス
example_table のレコード情報を格納するためのエンティティクラスです。ExampleTableexample_table の参照、更新を行うリポジトリインタフェースです。ExampleTableRepositoryまた、入力値や出力結果は以下の設定を前提として記載します。
- 各種設定値
設定項目 設定値 アカウントタイムゾーン (ユーザのタイムゾーン) (GMT+09:00) 日本 / 東京 システムタイムゾーン (GMT+00:00) UTC 日付と時刻の形式 英語形式 日付(標準表示) MMM d, yyyy 日付(簡易表示) MMM d 日付(入力) yyyy/MM/dd 時刻(標準表示) h:mm a 時刻(タイムスタンプ表示) h:mm:ss a 時刻(入力) HH:mm
日付¶
ユーザが設定したタイムゾーンや日付と時刻の形式に従って、以下のように日付を相対的に扱うための流れを説明します。
日付を保存する¶
画面から入力された日付データをサーバ側で解析して、データベースに保存するまでの流れを説明します。画面には、ユーザの日付入力形式で次の値が入力され、サーバに送信されたとします。2012/09/19サーバ側のプログラムは以下の通りです。package sample.timezone; import java.util.Date; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.context.Contexts; import jp.co.intra_mart.foundation.context.model.AccountContext; import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException; import jp.co.intra_mart.foundation.i18n.timezone.SystemTimeZone; import sample.timezone.domain.model.ExampleTable; import sample.timezone.domain.repository.ExampleTableRepository; @Controller @RequestMapping("sample/tgfw/date") public class SampleDateController { @Inject ExampleTableRepository exampleTableRepository; /** * 画面から送信された日付をデータベースに保存します。 * @param sampleDateForm 画面から送信された Form */ @RequestMapping("register") public String registerDate(final SampleDateForm sampleDateForm) throws DateTimeFormatterException { // 画面から送信された日付文字列 final String inputDateStr = sampleDateForm.getInputDate(); /* * 1. 画面から送信された日付文字列を解析します。 */ final Date inputDate = AccountDateTimeFormatter.parse(inputDateStr, SystemTimeZone.getDefaultTimeZone(), Date.class, DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_INPUT); /* * 2. データベースへ保存します。 */ final ExampleTable entity = new ExampleTable(); entity.userCd = Contexts.get(AccountContext.class).getUserCd(); entity.updateDate = inputDate; exampleTableRepository.insert(entity); return "sample/tgfw/date/output.jsp"; } }ユーザの入力形式に沿った日時文字列を解析するためには、AccountDateTimeFormatter を使用します。日付文字列の場合、時刻部分は「00:00:00」として解析されます。AccountDateTimeFormatter にシステムタイムゾーンを指定すると、システムタイムゾーンのデータとして以下のように解析されます。2012-09-19T00:00:00+00:00データベースには、システムタイムゾーンに変換された日付データを保存します。以下のようなデータが保存されます。2012-09-19 00:00:00.000
保存されている日付を画面に表示する¶
データベースに保存されている日付を、ユーザの日付の表示形式を使って日付文字列に整形し、画面に表示するまでの流れを説明します。サーバ側のプログラムは以下の通りです。package sample.timezone; import java.util.Date; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.context.Contexts; import jp.co.intra_mart.foundation.context.model.AccountContext; import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException; import jp.co.intra_mart.foundation.i18n.timezone.SystemTimeZone; import sample.timezone.domain.model.ExampleTable; import sample.timezone.domain.repository.ExampleTableRepository; @Controller @RequestMapping("sample/tgfw/date") public class SampleDateController { @Inject ExampleTableRepository exampleTableRepository; @RequestMapping public String index(final SampleDateForm sampleDateForm) { /* * 1. データベースから日付を取得します。 */ final ExampleTable entity = exampleTableRepository.selectOne(Contexts.get(AccountContext.class).getUserCd()); if (entity == null) { return "sample/tgfw/date/index.jsp"; } /* * 2. 日付文字列に整形します。 */ final String outputDate = AccountDateTimeFormatter.format(entity.updateDate, SystemTimeZone.getDefaultTimeZone(), DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_STANDARD); sampleDateForm.setOutputDate(outputDate); return "sample/tgfw/date/index.jsp"; } }データベースには、システムタイムゾーンに変換された日付データが保存されています。具体的には以下のようなデータが保存されていたとします。2012-09-19 00:00:00.000ユーザの日付と時刻の表示形式で整形する場合、AccountDateTimeFormatter を使用します。以下の結果が得られます。Sep 19, 2012
日付を現在時刻と比較する¶
データベースに保存されている日付と、ユーザの現在時刻を比較する流れを説明します。サーバ側のプログラムは以下の通りです。package sample.timezone; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.context.Contexts; import jp.co.intra_mart.foundation.context.model.AccountContext; import jp.co.intra_mart.foundation.i18n.datetime.DateTime; import jp.co.intra_mart.foundation.i18n.timezone.SystemTimeZone; import sample.timezone.domain.model.ExampleTable; import sample.timezone.domain.repository.ExampleTableRepository; @Controller @RequestMapping("sample/tgfw/comparison") public class SampleDateComparisonController { @Inject ExampleTableRepository exampleTableRepository; @RequestMapping public String index() { /* * 1. データベースから日付を取得します。 */ final ExampleTable entity = exampleTableRepository.selectOne(Contexts.get(AccountContext.class).getUserCd()); if (entity == null) { return "sample/tgfw/comparison/index.jsp"; } /* * 2. ユーザのタイムゾーンの「00:00:00」に変換します。 */ final DateTime updateDateTime = new DateTime(SystemTimeZone.getDefaultTimeZone(), entity.updateDate); final DateTime outputDateTime = new DateTime(Contexts.get(AccountContext.class).getTimeZone(), updateDateTime.getYear(), updateDateTime.getMonthOfYear(), updateDateTime.getDayOfMonth()); /* * 3. ログインユーザの現在時刻を取得します。 */ final DateTime currentDateTime = DateTime.now(Contexts.get(AccountContext.class).getTimeZone()); /** * 4. 現在時刻と比較します。 */ if (currentDateTime.compare(outputDateTime) < 0) { // 何らかの処理 } return "sample/tgfw/comparison/index.jsp"; } }データベースには、システムタイムゾーンに変換された日付データが保存されています。具体的には以下のようなデータが保存されていたとします。2012-09-19 00:00:00.000取得した日付データをユーザのタイムゾーンの時刻部分が「00:00:00」のデータに変換します。以下のようなデータに変換されます。2012-09-19T00:00:00+09:00ユーザのタイムゾーンでの現在時刻を取得します。ログインユーザのタイムゾーンの現在時刻を取得するには DateTime を利用します。最後に、現在時刻と比較します。
アノテーションを利用して日付を Date型で受け取る¶
画面から入力された日付文字列を Date型のプロパティにバインドします。日付に対応するアノテーションは以下の通りです。
パターン アノテーション フォーマット 日付 @AccountDateFormat 日付(入力) 画面から入力された文字列をユーザのタイムゾーンとし、Date型プロパティに設定する例を次に示します。package sample.timezone; import java.util.Date; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateFormat; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateTimeFormat; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountTimeFormat; public class SampleAnnotationDateForm { // ここではシステムタイムゾーンは UTC とします。 // 日付文字列を Date型のプロパティにバインドします。 // (String) 2000/01/01 が (Date) 2000-01-01T00:00:00+00:00 になります。 // デフォルトではタイムゾーンを変換しません。 @AccountDateFormat private Date date; public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }画面には、ユーザの日付入力形式で次の値が入力され、サーバに以下の文字列が送信されたとします。2012/09/19@AccountDateFormat が付与されたプロパティには以下のデータがセットされます。2012-09-19T00:00:00+00:00コラム
フォーマット変換に失敗した場合のエラーメッセージコードの解決については Spring Frameworkの仕様に従います。「Resolving Codes to Error Messages」 を参照してください。
Data binding を利用して日付を Date型で受け取る¶
Controller クラスに @InitBinder を設定したメソッドを作成し、データバインドの定義を登録します。以下に、@InitBinder を使用したデータバインドの例を示します。package sample.timezone; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds; @Controller @RequestMapping("sample/tgfw/databinding") public class SampleDataBindingController { @RequestMapping public String index() { return "sample/tgfw/databinding/index.jsp"; } @RequestMapping("sample") public String sample(final SampleDataBindingForm sampleDataBindingForm, final BindingResult result) { // 登録して、入力画面を再表示 // 登録処理など ... return "sample/tgfw/databinding/output.jsp"; } @InitBinder public void initBinder(final WebDataBinder binder) { // プロパティ"date"に対するデータバインド設定 // "日付(入力)"フォーマットパターンを取得します。 final String datePattern = AccountDateTimeFormatter.getPattern(DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_INPUT); // DateFormatを生成します。 final DateFormat dateFormat = new SimpleDateFormat(datePattern); // プロパティ"date"に対するデータバインドを登録します。 binder.registerCustomEditor(Date.class, "date", new CustomDateEditor(dateFormat, true)); } }package sample.timezone; import java.util.Date; public class SampleDataBindingForm { private Date date; public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }画面から入力された文字列をDate型のプロパティにセットしています。
JSON 内の日付を Date型で受け取る¶
Spring Framework MVC では、リクエストやレスポンスに JSON をセットして送る場合に、Jackson を利用して JSON と Java のオブジェクトとを変換しています。Jackson では、デフォルトで Date型のプロパティはエポックミリ秒で出力され、日付項目の文字列は yyyy-MM-dd’T’HH:mm:ss.SSSZ 形式でパースされます。これをアカウントに設定された日付フォーマットで変換するようにします。Date型プロパティと JSON との変換のフォーマットを指定できるようにするために、Jackson の設定を行います。これにより、フォームやモデルクラスに @AccountDateFormat アノテーションなどを設定して日付をフォーマットして出力できます。
bean 定義 xml ファイルの設定mvc:message-converters を設定します。 コントローラクラスの設定リクエストを JSON で受け取るようにします。レスポンスに JSON をセットするようにします。 フォームやモデルクラスの設定Date型のプロパティにアノテーションを設定します。 JSP の設定送信データを JSON データにします。JSP 側で JSON データを受け取ります。
1. bean 定義 xml ファイルの設定¶
applicationContext-im_tgfw_web.xml の mvc:annotation-drivenタグに mvc:message-convertersタグを追加します。Message converter に MappingJackson2HttpMessageConverter を設定し、その objectMapper プロパティに AccountDateObjectMapper を設定します。AccountDateObjectMapper により、アノテーションが動作します。<mvc:annotation-driven conversion-service="conversionService"> <!-- 略 --> <!-- jackson message converter --> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="jp.co.intra_mart.framework.extension.spring.http.converter.json.AccountDateObjectMapper" /> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
2. コントローラクラスの設定¶
SpringFramework MVC に従って、リクエスト、レスポンスに JSON をセットするように設定します。この例では、メソッドの引数に @RequestBody アノテーションを設定し、メソッドの戻り値に JSON にするクラスを定義しメソッドに @ResponseBody アノテーションを設定します。package sample.timezone; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("sample/tgfw/json") public class SampleJsonController { @RequestMapping public String index() { return "sample/tgfw/json/index.jsp"; } @RequestMapping("conv") @ResponseBody public SampleJsonModel conv(@RequestBody SampleJsonForm form) { final SampleJsonModel model = new SampleJsonModel(); model.setDate(form.getDate()); return model; } }
3. フォーム(モデル)クラスの設定¶
必要に応じて、Date型のプロパティに @AccountDateFormat アノテーションを設定します。package sample.timezone; import java.util.Date; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateFormat; public class SampleJsonForm { @AccountDateFormat private Date date; public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }package sample.timezone; import java.util.Date; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateFormat; public class SampleJsonModel { @AccountDateFormat private Date date; public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } }
4. JSPの設定¶
Ajax で JSON データを送信、受信する場合の例を示します。<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib prefix="imui" uri="http://www.intra-mart.co.jp/taglib/imui" %> <%@ taglib prefix="im" uri="http://www.intra-mart.co.jp/taglib/im-tenant" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!-- HEADタグ --> <imui:head> <title>Json のサンプルプログラム</title> <script type="text/javascript"> $(function () { $('#button').click(function () { $.ajax({ dataType : 'json', url : '<c:url value="sample/tgfw/json/conv"/>', contentType: 'application/json', data : JSON.stringify({ date : $('#inputDate').val() }), type :'POST', success : function (data, textStatus, jqXHR) { // 受け取ったデータ(data)の処理の例 $('#outputDate').val(data.date); } }); }); }); </script> </imui:head> <!-- 画面上に表示されるタイトル --> <div class="imui-title"> <h1>Json のサンプルプログラム (TERASOLUNA)</h1> </div> <!-- 入力画面 --> <div class="imui-form-container-narrow"> <p> <label for="name">Please input the date. </label> </p> <div> <label>Date:</label> <div> <label> <imui:textbox type="text" value="" id="outputDate" name="outputDate" size="20" class="imui-text-readonly" readonly /> </label> </div> <div> <!-- テキストボックス --> <imui:textbox type="text" value='2000/01/01' id="inputDate" name="inputDate" size="12" /> <im:calendar floatable="true" altField="#inputDate" /> </div> </div> <!-- submitボタン --> <imui:button name="button" value="Register!!" class="mt-10" id="button" /> </div>
クライアント側で日付を扱う¶
クライアント側で、ユーザのタイムゾーンの今日から3日間の日付を生成し、最後の日付をサーバ側へ送信するまでの流れを説明します。このサンプルを通して、csjs で日付や日時を扱う際の注意点を説明します。
1. ユーザのタイムゾーンの今日を取得する¶
ユーザのタイムゾーンにおける「今日」を csjs で取得するためには、intra-mart Accel Platform から提供されている ImDate を使用します。注意
ユーザのタイムゾーンにおける「今日」の取得に、csjs の new Date を利用しないでください。csjs の new Date はクライアント OS のタイムゾーンにおける現在日時データを返しますが、ユーザのタイムゾーンがクライアント OS のタイムゾーンと一致しているとは限りません。<script type="text/javascript" src="im_i18n/timezone/im_date_timezone.js"></script> <script type="text/javascript"> var firstDate = ImDate.now(); </script>
2. 今日から3日間の日付を生成する¶
Date に標準で用意されているメソッドを使用して構いません。var dateArray = new Array(); var date = firstDate; for (var i = 0; i < 3; i++) { dateArray[i] = date; date.setDate(date.getDate() + 1); }
3. 日付をサーバ側へ送信する¶
年月日の値から日付文字列を作ります。var lastDate = dateArray[2]; var lastDateStr = lastDate.getFullYear() + "-" + (lastDate.getMonth() + 1) + "-" + lastDate.getDate();注意
ImDate.now() で生成した Date のエポックミリ秒は送信しないでください。ImDate.now() の返す Date は、ユーザのタイムゾーンにおける「今日」の年月日時分秒を持っていますが、エポックミリ秒は正しいとは限りません。理由は、クライアント側で Date を生成しているためです。Date の持つエポックミリ秒は、クライアント OS のタイムゾーンで計算された値となり、ユーザのタイムゾーンで計算された値と一致しない可能性があります。
4. クライアント側から送信された日付文字列から Date を生成する¶
サーバ側のプログラムは以下の通りです。package sample.timezone; import java.util.Date; import java.util.TimeZone; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.context.Contexts; import jp.co.intra_mart.foundation.context.model.AccountContext; import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException; import jp.co.intra_mart.foundation.i18n.timezone.SystemTimeZone; import sample.timezone.domain.model.ExampleTable; import sample.timezone.domain.repository.ExampleTableRepository; @Controller @RequestMapping("sample/tgfw/dtf") public class SampleDTFController { @Inject ExampleTableRepository exampleTableRepository; @RequestMapping("sample") public String sample(final SampleDTFForm sampleDTFForm) throws DateTimeFormatterException { final String inputDateStr = sampleDTFForm.getInputDate(); /* * 1. DateTimeFormatter を使用して、日付文字列から Date を生成します。 */ final DateTimeFormatter formatter = DateTimeFormatter.withPattern("yyyy-MM-dd"); formatter.setTimeZone(SystemTimeZone.getDefaultTimeZone()); final Date inputDate = formatter.parse(inputDateStr, Date.class); return "sample/tgfw/dtf/output.jsp"; } }日時文字列がユーザの日付と時刻の入力形式に沿っていない場合、DateTimeFormatter を使用します。DateTimeFormatter は、直接フォーマットパターンを指定できます。
日時¶
ユーザが設定したタイムゾーンや日付と時刻の形式に従って、以下のように日時を絶対的に扱うための流れを説明します。
日時を保存する¶
画面から入力された日時をサーバ側で解析して、データベースに保存するまでの流れを説明します。画面には、ユーザの日付と時刻の入力形式で次の値が入力され、サーバに送信されたとします。2012/09/19 03:46サーバ側のプログラムは以下の通りです。package sample.timezone; import java.util.Date; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.context.Contexts; import jp.co.intra_mart.foundation.context.model.AccountContext; import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException; import sample.timezone.domain.model.ExampleTable; import sample.timezone.domain.repository.ExampleTableRepository; @Controller @RequestMapping("sample/tgfw/datetime") public class SampleDateTimeController { @Inject ExampleTableRepository exampleTableRepository; /** * 画面から送信された日付をデータベースに保存します。 * @param sampleDateTimeForm 画面から送信された Form */ @RequestMapping("register") public String registerDateTime(final SampleDateTimeForm sampleDateTimeForm) throws DateTimeFormatterException { // 画面から送信された日時文字列 final String inputDateTimeStr = sampleDateTimeForm.getInputDateTime(); /* * 1. 画面から送信された日時文字列を解析します。 */ final Date inputDateTime = AccountDateTimeFormatter.parse(inputDateTimeStr, Date.class, DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_INPUT, DateTimeFormatIds.IM_DATETIME_FORMAT_TIME_INPUT); /* * 2. データベースへ保存します。 */ final ExampleTable entity = new ExampleTable(); entity.userCd = Contexts.get(AccountContext.class).getUserCd(); entity.updateDate = inputDateTime; exampleTableRepository.insert(entity); return "sample/tgfw/datetime/output.jsp"; } }ユーザの入力形式に沿った日時文字列を解析するためには、AccountDateTimeFormatter を使用します。AccountDateTimeFormatter にタイムゾーンを指定しなければ、ログインユーザのタイムゾーンのデータとして以下のように解析されます。2012-09-18T18:46:00+00:00データベースには、システムタイムゾーンに変換された日時データを保存します。以下のようなデータが保存されます。2012-09-18 18:46:00.000
保存されている日時を画面に表示する¶
データベースに保存されている日時を、ユーザのタイムゾーン、日付と時刻の表示形式を使って日時文字列に整形し、画面に表示するまでの流れを説明します。サーバ側のプログラムは以下の通りです。package sample.timezone; import java.util.Date; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.context.Contexts; import jp.co.intra_mart.foundation.context.model.AccountContext; import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException; import sample.timezone.domain.model.ExampleTable; import sample.timezone.domain.repository.ExampleTableRepository; @Controller @RequestMapping("sample/tgfw/datetime") public class SampleDateTimeController { @Inject ExampleTableRepository exampleTableRepository; @RequestMapping public String index(final SampleDateTimeForm sampleDateTimeForm) { /* * 1. データベースから日時を取得します。 */ final ExampleTable entity = exampleTableRepository.selectOne(Contexts.get(AccountContext.class).getUserCd()); if (entity == null) { return "sample/tgfw/datetime/index.jsp"; } /* * 2. 日時文字列に整形します。 */ final String outputDate = AccountDateTimeFormatter.format(entity.updateDate, DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_STANDARD, DateTimeFormatIds.IM_DATETIME_FORMAT_TIME_STANDARD); sampleDateTimeForm.setOutputDate(outputDate); return "sample/tgfw/datetime/index.jsp"; } }データベースには、システムタイムゾーンに変換された日時データが保存されています。具体的には以下のようなデータが保存されていたとします。2012-09-18 18:46:00.000ユーザの表示形式に沿った日時文字列に整形するためには、AccountDateTimeFormatter を使用します。AccountDateTimeFormatter は、ログインユーザのタイムゾーンにおける時刻を計算します。以下の結果が得られます。Sep 19, 2012 3:46 AM
アノテーションを利用して日時を Date型で受け取る¶
画面から入力された日時文字列を Date型のプロパティにバインドします。日時に対応するアノテーションは以下の通りです。
パターン アノテーション フォーマット 日時 @AccountDateTimeFormat 日付(入力) 時刻(入力) 画面から入力された日時文字列を、Date型プロパティに設定する例を次に示します。package sample.timezone; import java.util.Date; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateFormat; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateTimeFormat; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountTimeFormat; public class SampleAnnotationForm { // 日時文字列を Date型のプロパティにバインドします。 // ログインユーザのタイムゾーンが JST の場合、システムタイムゾーンの UTC に変換するため、 // (String) 2000/01/01 00:00 が (Date) 1999-12-31T15:00:00+00:00 になります。 @AccountDateTimeFormat private Date dateTime; public Date getDateTime() { return dateTime; } public void setDateTime(Date dateTime) { this.dateTime = dateTime; } }画面には、ユーザの日付入力形式で次の値が入力され、サーバに以下の文字列が送信されたとします。2012/09/19 03:46@AccountDateFormat が付与されたプロパティには以下のデータがセットされます。2012-09-18T18:46:00+00:00コラム
フォーマット変換に失敗した場合のエラーメッセージコードの解決については Spring Frameworkの仕様に従います。「Resolving Codes to Error Messages」 を参照してください。
Data binding を利用して日時を Date型で受け取る¶
Controller クラスに @InitBinder を設定したメソッドを作成し、データバインドの定義を登録します。以下に、@InitBinder を使用したデータバインドの例を示します。package sample.timezone; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter; import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds; @Controller @RequestMapping("sample/tgfw/databinding") public class SampleDataBindingController { @RequestMapping("register") public String registerDateTime(final SampleDataBindingForm sampleDataBindingForm, final BindingResult result) { // 登録して、入力画面を再表示 // 登録処理など ... return "sample/tgfw/databinding/output.jsp"; } @InitBinder public void initBinder(final WebDataBinder binder) { // プロパティ"datetime"に対するデータバインド設定 // "日付(入力)"と"時刻(入力)"フォーマットパターンを取得します。 final String datetimePattern = AccountDateTimeFormatter.getPattern(DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_INPUT, DateTimeFormatIds.IM_DATETIME_FORMAT_TIME_INPUT); // DateFormatを生成します。 final DateFormat datetimeFormat = new SimpleDateFormat(datetimePattern); // プロパティ"datetime"に対するデータバインドを登録します。 binder.registerCustomEditor(Date.class, "datetime", new CustomDateEditor(datetimeFormat, true)); } }package sample.timezone; import java.util.Date; public class SampleDataBindingForm { private Date dateTime; public Date getDateTime() { return dateTime; } public void setDateTime(Date dateTime) { this.dateTime = dateTime; } }画面から入力された文字列をDate型のプロパティにセットしています。
JSON 内の日時を Date型で受け取る¶
Spring Framework MVC では、リクエストやレスポンスに JSON をセットして送る場合に、Jackson を利用して JSON と Java のオブジェクトとを変換しています。Jackson では、デフォルトで Date型のプロパティはエポックミリ秒で出力され、日付項目の文字列は yyyy-MM-dd’T’HH:mm:ss.SSSZ 形式でパースされます。これをアカウントに設定された日時フォーマットで変換するようにします。Date型プロパティと JSON との変換のフォーマットを指定できるようにするために、Jackson の設定を行います。これにより、フォームやモデルクラスに @AccountDateTimeFormat アノテーションなどを設定して日時をフォーマットして出力できます。
bean 定義 xml ファイルの設定mvc:message-converters を設定します。 コントローラクラスの設定リクエストを JSON で受け取るようにします。レスポンスに JSON をセットするようにします。 フォームやモデルクラスの設定Date型のプロパティにアノテーションを設定します。 JSP の設定送信データを JSON データにします。JSP 側で JSON データを受け取ります。
1. bean 定義 xml ファイルの設定¶
applicationContext-im_tgfw_web.xml の mvc:annotation-drivenタグに mvc:message-convertersタグを追加します。Message converter に MappingJackson2HttpMessageConverter を設定し、その objectMapper プロパティに AccountDateObjectMapper を設定します。AccountDateObjectMapper により、アノテーションが動作します。<mvc:annotation-driven conversion-service="conversionService"> <!-- 略 --> <!-- jackson message converter --> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="jp.co.intra_mart.framework.extension.spring.http.converter.json.AccountDateObjectMapper" /> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
2. コントローラクラスの設定¶
SpringFramework MVC に従って、リクエスト、レスポンスに JSON をセットするように設定します。この例では、メソッドの引数に @RequestBody アノテーションを設定し、メソッドの戻り値に JSON にするクラスを定義しメソッドに @ResponseBody アノテーションを設定します。package sample.timezone; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("sample/tgfw/json") public class SampleJsonController { @RequestMapping public String index() { return "sample/tgfw/json/index.jsp"; } @RequestMapping("conv") @ResponseBody public SampleJsonModel conv(@RequestBody SampleJsonForm form) { final SampleJsonModel model = new SampleJsonModel(); model.setDateTime(form.getDateTime()); return model; } }
3. フォーム(モデル)クラスの設定¶
必要に応じて、Date型のプロパティに @AccountDateFormat アノテーションを設定します。package sample.timezone; import java.util.Date; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateTimeFormat; public class SampleJsonForm { @AccountDateTimeFormat private Date dateTime; public Date getDateTime() { return dateTime; } public void setDateTime(Date dateTime) { this.dateTime = dateTime; } }package sample.timezone; import java.util.Date; import jp.co.intra_mart.framework.extension.spring.format.annotation.AccountDateTimeFormat; public class SampleJsonModel { @AccountDateTimeFormat private Date dateTime; public Date getDateTime() { return dateTime; } public void setDateTime(Date dateTime) { this.dateTime = dateTime; } }
4. JSPの設定¶
Ajax で JSON データを送信、受信する場合の例を示します。<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib prefix="imui" uri="http://www.intra-mart.co.jp/taglib/imui" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="im" uri="http://www.intra-mart.co.jp/taglib/im-tenant" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!-- HEADタグ --> <imui:head> <title>Json のサンプルプログラム</title> <script type="text/javascript"> $(function () { $('#button').click(function () { $.ajax({ dataType : 'json', url : '<c:url value="sample/tgfw/json/conv"/>', contentType: 'application/json', data : JSON.stringify({ dateTime : $('#inputDateTime').val() }), type :'POST', success : function (data, textStatus, jqXHR) { // 受け取ったデータ(data)の処理の例 $('#outputDateTime').val(data.dateTime); } }); }); }); </script> </imui:head> <!-- 画面上に表示されるタイトル --> <div class="imui-title"> <h1>Json のサンプルプログラム (TERASOLUNA)</h1> </div> <!-- 入力画面 --> <div class="imui-form-container-narrow"> <p> <label for="name">Please input the date. </label> </p> <div> <label>DateTime:</label> <div> <label> <imui:textbox type="text" value="" id="outputDateTime" name="outputDateTime" size="20" class="imui-text-readonly" readonly /> </label> </div> <!-- テキストボックス --> <div> <imui:textbox type="text" value='2000/01/01 00:00' id="inputDateTime" name="inputDateTime" size="20" /> </div> </div> <!-- submitボタン --> <imui:button name="button" value="Register!!" class="mt-10" id="button" /> </div>