プログラマ度診断結果
どんなもんか試してみました。
基本的な性格は意外と合ってる気がします。
適正も多分、こんなもんだと思います。
http://www7.plala.or.jp/keny01/consult/exam.html
SaStrutsのvalidationをJSON形式で返す 2
先日の続き。
View側の処理
クライアント側での処理概要
・非同期通信のレスポンスが帰ってきたときに、データ形式を判定(JSON形式かどうか)。
・JSON形式のデータからvalidationのメッセージを取得して、入力チェック等のあった部品の横に
メッセージを表示。(saveErrorsメソッドを使用する場合には、divのidがerrorsの箇所に表示される。)
非同期通信完了時のファンクションを設定。
$(function() { $.ajaxSetup({ timeout : 180000, cache: false, complete : onAjaxComplete }); }); /** * ajax通信完了時の処理 * @param xmlRequest * @param textStatus * @return */ function onAjaxComplete(xmlRequest, textStatus) { if (isJsonData(xmlRequest)) { processJson($.httpData(xmlRequest, 'json'), textStatus); } else { if ($("td").is("#main")) { $("#main").html(xmlRequest.responseText); } else { $("body").html(xmlRequest.responseText); } } } /** * form送信後のデータがJSON形式だった場合の処理 * @param data * @param status * @return */ function processJson(data, status) { // validate error の場合 if (data.status == 'validate') { var allInput = $(':input'); // input 要素取得 var errors = data.errors; // プロパティの一致した箇所を探す。 for (var cnt = 0; cnt < allInput.length; cnt++) { for (var cnt2 = 0; cnt2 < errors.length; cnt2++) { if (allInput[cnt].name != '' && allInput[cnt].name == errors[cnt2].name) { var id = allInput[cnt].name; $(allInput[cnt]).addClass('error'); // プロパティの一致した箇所の部品の大きさを取得 var targetTop = $(allInput[cnt]).offset().top; var targetLeft = $(allInput[cnt]).offset().left; var itemWidth = $(allInput[cnt]).outerWidth(); var left = Math.floor(parseInt(targetLeft) + parseInt(itemWidth) + 10); var msg = '<div id="' + id + '"class="colorred bgFFFFFF">' + errors[cnt2].val + '</div>'; $('body').append(msg); $('#' + id).css({float: 'left', position: 'absolute', top: targetTop, left: left}); } } } // saveErrorsメソッドを使用した時 for (var cnt = 0; cnt < errors.length; cnt++) { if (errors[cnt].name == '') { $('#errors').append('<div class="colorred bgFFFFFF">' + errors[cnt].val + '</div>'); } } } /** * ajax通信後のデータ形式がJSONかどうかを判定します。 * @param XMLHttpRequest * @return */ function isJsonData(XMLHttpRequest) { var contentType = XMLHttpRequest.getResponseHeader('Content-Type'); if (contentType.indexOf("json") > -1) { return true; } return false; }
SaStrutsのvalidationをJSON形式で返す
入力チェック等のValidationの処理をSaStruts側(アノテーションとか)で処理して結果を非同期で返す(JSON)処理を作ってみました。
処理の流れ
・サーバーサイドにリクエストが送られてくる。
・SaStruts側でValidationチェックを行う。
・処理結果をActionWrapperクラスを継承したクラスでJSON形式にフォーマットしてレスポンスを返す。
・クライアントサイドでレスポンスを受け取りJSON形式からエラーメッセージのhtmlを生成して表示。
修正箇所(サーバーサイド)
SaStruts側の修正部分は、ActionWrapperクラスとS2RequestProcessorを修正というか
継承して、変更を加えたい箇所のメソッドをオーバーライドします。
あと、非同期で返す処理だということを認識させるためのアノテーションを作成と
S2RequestProcessorから新しく作成するRequestProcessorに変更するので
struts-config.xmlを修正します。
アノテーションクラス
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * <pre> * Ajax * 非同期通信でvalidationエラーを返すためのアノテーション * </pre> * @version 1.0.0 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) @Documented public @interface Ajax { String input = "ajax"; }
ActionWrapperを継承したクラス。
import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import javax.servlet.http.HttpServletRequest; import net.arnx.jsonic.JSON; import net.arnx.jsonic.JSONException; import org.apache.struts.Globals; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import org.apache.struts.util.MessageResources; import org.apache.struts.validator.Resources; import org.seasar.framework.container.deployer.InstanceDefFactory; import org.seasar.framework.util.MethodUtil; import org.seasar.struts.action.ActionWrapper; import org.seasar.struts.config.S2ActionMapping; import org.seasar.struts.config.S2ExecuteConfig; import org.seasar.struts.config.S2ValidationConfig; import org.seasar.struts.util.ActionMessagesUtil; import org.seasar.struts.util.RequestUtil; import org.seasar.struts.util.ResponseUtil; /** */ public class SaStrutsActionWrapper extends ActionWrapper { /** * コンストラクタ * @param actionMapping */ public SaStrutsActionWrapper(S2ActionMapping actionMapping) { super(actionMapping); } @Override protected ActionForward execute(HttpServletRequest request, S2ExecuteConfig executeConfig) { ActionMessages errors = new ActionMessages(); List validationConfigs = executeConfig.getValidationConfigs(); if (validationConfigs != null) { for (S2ValidationConfig cfg : validationConfigs) { if (cfg.isValidator()) { ActionMessages errors2 = validateUsingValidator(request, executeConfig); if (errors2 != null && !errors2.isEmpty()) { errors.add(errors2); if (executeConfig.isStopOnValidationError()) { return processErrors(errors, request, executeConfig); } } } else { Object target = actionForm; if (cfg.getValidateMethod().getDeclaringClass() .isAssignableFrom( actionMapping.getComponentDef() .getComponentClass())) { target = action; } ActionMessages errors2 = (ActionMessages) MethodUtil .invoke(cfg.getValidateMethod(), target, null); if (errors2 != null && !errors2.isEmpty()) { errors.add(errors2); if (executeConfig.isStopOnValidationError()) { // @executeのinputがajaxだった場合 if (executeConfig.getInput().equals("ajax")) { // JSON形式のERROR MSGを作成 createJsonErrMsg(errors, request); return null; } return processErrors(errors, request, executeConfig); } } } } } if (!errors.isEmpty()) { return processErrors(errors, request, executeConfig); } String next = (String) MethodUtil.invoke(executeConfig.getMethod(), action, null); if (executeConfig.isRemoveActionForm() && !ActionMessagesUtil.hasErrors(request)) { if (actionMapping.getActionFormComponentDef().getInstanceDef() .equals(InstanceDefFactory.SESSION)) { RequestUtil.getRequest().getSession().removeAttribute( actionMapping.getActionFormComponentDef() .getComponentName()); } else { RequestUtil.getRequest().removeAttribute( actionMapping.getActionFormComponentDef() .getComponentName()); } RequestUtil.getRequest().removeAttribute( actionMapping.getAttribute()); } else { if (ActionMessagesUtil.hasErrors(request)) { // @executeのinputがajaxだった場合 if (executeConfig.getInput() != null && executeConfig.getInput().equals("ajax")) { errors.add((ActionMessages) request.getAttribute(Globals.ERROR_KEY)); // JSON形式のERROR MSGを作成 createJsonErrMsg(errors, request); return null; } } } boolean redirect = executeConfig.isRedirect(); if (redirect && ActionMessagesUtil.hasErrors(request)) { redirect = false; } return actionMapping.createForward(next, redirect); } @Override protected ActionForward processErrors(ActionMessages errors, HttpServletRequest request, S2ExecuteConfig executeConfig) { // @executeのinputがajaxだった場合 if (executeConfig.getInput().equals("ajax")) { // JSON形式のERROR MSGを作成 createJsonErrMsg(errors, request); return null; } return super.processErrors(errors, request, executeConfig); } /** * JSON形式のエラーメッセージを生成します。 * @param errors * @param request * @throws JSONException */ @SuppressWarnings("unchecked") private void createJsonErrMsg(ActionMessages errors, HttpServletRequest request) throws JSONException { // JSON形式で返す Map map = new HashMap(); map.put("status", "validate"); List<Object> list = new ArrayList<Object>(); for (Iterator<String> it = errors.properties(); it.hasNext();) { Map<String, String> err = new HashMap<String, String>(); String key = it.next(); err.put("name", key); for (Iterator<ActionMessage> ite = errors.get(key); ite.hasNext();) { ActionMessage error = ite.next(); System.out.println(error); MessageResources mResouces = Resources.getMessageResources(request); String msg = mResouces.getMessage((Locale)null, error.getKey(), error.getValues()); System.out.println(msg); err.put("val", msg); } list.add(err); } map.put("errors", list); ResponseUtil.write(JSON.encode(map), "application/json"); } }
S2RequestProcessorを継承したクラス
import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionMapping; import org.seasar.struts.action.S2RequestProcessor; import org.seasar.struts.config.S2ActionMapping; /** * <pre> * SaStrutsRequestProcessor * * </pre> * @version 1.0.0 */ public class SaStrutsRequestProcessor extends S2RequestProcessor { /* * (非 Javadoc) * @see org.seasar.struts.action.S2RequestProcessor#processActionCreate(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.apache.struts.action.ActionMapping) */ @Override protected Action processActionCreate(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException { Action action = null; try { action = new SaStrutsActionWrapper(((S2ActionMapping) mapping)); } catch (Exception e) { log.error(getInternal().getMessage("actionCreate", mapping.getPath()), e); response .sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, getInternal().getMessage("actionCreate", mapping.getPath())); return null; } action.setServlet(servlet); return action; } }
<controller maxFileSize="1024K" bufferSize="1024" processorClass="xxx.xxx.xxxx.wrapper.SaStrutsRequestProcessor" multipartClass="org.seasar.struts.upload.S2MultipartRequestHandler"/>
Actionクラス
(validatorをtrueにして、inputをさっき作ったAjaxアノテーションクラスで指定
/** * ログイン処理アクション * @return */ @Execute(validator = true, input = Ajax.input) public String index(){ }
とりあえずjava側の修正は終了。
あとは、改めて。。。
Googleカレンダーをjavaで操作
引っ越し前のblogにも載せてましたが、諸事情によりこちらにも載せておきます。
最近、マッシュアップとかいうやつに興味を持って
少し勉強しようとしてます。
手始めに、Google API を使用してみたいと思ってます。
準備
Google カレンダーを作成
Google カレンダーを持ってない人は作成してください。
Google API(jarファイル)を取得
http://code.google.com/apis/gdata/client-java.html から Download the Java client library.」をクリックして「gdata-xxx.zip」を取得
プログラム作成
概要
Google APIは、gdataというAtom 1.0(またはRSS 2.0)に準じたフィードデータを使用してHTTP通信でやり取りするらしいです。
イベントの追加、変更、削除を行うアプリケーションでは一般的に、
「http://www.google.com/calendar/feeds /default/private/full」に対してリクエストを送信して行うらしいです。
・Eclipseでプロジェクトの作成とクラスパスの追加
・Eclipseのプロジェクトを作成(とりあえず、今回は、「googleCalApi」というJavaプロジェクトを作成)
・作成したプロジェクトにダウンロードした「gdata-xxx.zip」の中から以下のjarファイルを取得してクラスパスに追加
・gdata-calendar-2.0.jar
・gdata-core-1.0.jar
・gdata-client-1.0.jar
import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import com.google.gdata.client.Query; import com.google.gdata.client.calendar.CalendarService; import com.google.gdata.data.DateTime; import com.google.gdata.data.Entry; import com.google.gdata.data.Feed; import com.google.gdata.data.Person; import com.google.gdata.data.PlainTextConstruct; import com.google.gdata.data.calendar.CalendarEventEntry; import com.google.gdata.data.extensions.EventEntry; import com.google.gdata.data.extensions.When; import com.google.gdata.data.extensions.Where; import com.google.gdata.util.AuthenticationException; import com.google.gdata.util.ServiceException; /** * * GoogleCalendar APIで実行 * @version 1.0.0 */ public class GoogleCalMain { // Google アカウント private static String GOOGLE_ACCOUNT = "xxxxxxx@gmail.com"; // Google アカウントのパスワード private static String GOOGLE_PASSWORD = "xxxxxxxx"; // 送信URL private static String GOOGLE_CAL_URL = "http://www.google.com/calendar/feeds/default/private/full"; /** * Google カレンダーAPIを使用して、登録と参照 * @param args */ public static void main(String[] args) { GoogleCalMain main = new GoogleCalMain(); main.googleCalAddAndRef(); } /** * Google カレンダーAPIを使用して、 * 登録と登録したデータの参照を行います。 */ private void googleCalAddAndRef() { String title = "javaからの登録"; String place = "鹿児島"; String memo = "テスト"; try { URL postURL = new URL(GOOGLE_CAL_URL); // イベント登録クラス CalendarEventEntry myEntry = new CalendarEventEntry(); // スケジュールのタイトル myEntry.setTitle(new PlainTextConstruct(title)); // スケジュールの詳細 myEntry.setContent(new PlainTextConstruct(memo)); // 作成アプリ名 Person author = new Person("Mashup Sample Test", null, GOOGLE_ACCOUNT); myEntry.getAuthors().add(author); DateTime startTime = new DateTime(); startTime.setTzShift(9); startTime = DateTime.parseDateTime("2006-04-17T08:00:00"); DateTime endTime = new DateTime(); endTime.setTzShift(9); endTime = DateTime.parseDateTime("2006-04-17T17:00:00"); // 開始終了日時をWhen型オブジェクトに代入し、イベントクラスに追加 When eventTimes = new When(); eventTimes.setStartTime(startTime); eventTimes.setEndTime(endTime); myEntry.addTime(eventTimes); // 場所をWhere型オブジェクトに代入し、イベントクラスに追加 Where evLocation = new Where(); evLocation.setValueString(place); myEntry.addLocation(evLocation); // Google Calendarサービスに接続 CalendarService calService = new CalendarService("sample"); calService.setUserCredentials(GOOGLE_ACCOUNT, GOOGLE_PASSWORD); // スケジュールを追加する CalendarEventEntry insertEntry = calService.insert(postURL, myEntry); // 特定のスケジュールを操作するリクエストを取得 URL entryUrl = new URL(insertEntry.getSelfLink().getHref()); EventEntry retrievedEntry = calService.getEntry(entryUrl, EventEntry.class); // 特定のスケジュールを探す Query myQuery = new Query(postURL); myQuery.setFullTextQuery(title); Feed myResultsFeed = calService.query(myQuery, Feed.class); if (myResultsFeed.getEntries().size() > 0) { Entry firstMatchEntry = myResultsFeed.getEntries().get(0); System.out.println("Titie: " + firstMatchEntry.getTitle().getPlainText()); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } }