ページ

ラベル GAE の投稿を表示しています。 すべての投稿を表示
ラベル GAE の投稿を表示しています。 すべての投稿を表示

2015年4月18日土曜日

GAEと戯れる 23 - メモ集 -

忘れないうちのメモ集


・jspのcタグで空判定する場合
   例)
  <c:if test="${!empty param.css}">
  <link rel="stylesheet" type="text/css" href="${param.css}">

  </c:if>

上記の場合
param.cssが空でない場合にcssが読み込まれる
List要素の空判定にも使える


・jspでif 〜 else if 〜 else 〜をやりたい場合
   例)
            <c:choose>
              <c:when test="${empty members}">
                <font color="red">※設定画面でメンバーを登録して下さい</font>
              </c:when>
              <c:otherwise>
                <select name="organizerId">
                  <c:forEach var="member" items="${members}">
                    <option value="${member.key.id}">${member.name}</option>
                  </c:forEach>
                </select>
              </c:otherwise>

            </c:choose>

  上記の場合C言語風に書くと・・・
  if (members == empty) {
     <font color=“red”>※設定画面でメンバーを・・・
  } else {
    <select name=“organizerId”>・・・
  }
  になる

・画像をボタンみたいにする
  例)
    <div id="work_area">
      <a href="#" onclick="doPost(document.register_form, '/register/', '', '', 'register');">
        <img src="/res/register_off.png" alt="登録" border=0 width=30 height=35>
      </a>&nbsp;登録   

    </div>

   表示)



※ちなみにaタグの下線を引く設定をなしにしとかないと、アンダーバー(_)みたいなのが入ってしまう。

↓下線無効化
a {
text-decoration: none;

}


・input要素にフォーカスが当たったら背景色を変える
  cssに以下記述を追加
/* input要素にフォーカスが当たった時に背景色変更 */
input:focus { background: skyblue; }

※全てのinput要素に反映されるので注意

  表示例)
・フォーカス前
     



・フォーカス後


以上〜。


2015年4月11日土曜日

GAEと戯れる 22 - jQuery UI 確認ダイアログ -

jQuery UIを使用した確認ダイアログを作ってみる。

・概要















×を押した時に削除してもいいかの確認ダイアログを表示。
OKの場合実際の削除処理を行う。

まずは表示用のdivタグを作成。





















どの画面からでも呼べるように共通JSPに記述。
次にダイアログの表示をjQueryを使って作成

 * 確認ダイアログ
 * 
 * @param msg ダイアログ本文
 * @param callback OK時の処理
 */
function showConfirmDialog(msg, callback) {
$('#confirm_dialog').html(msg);
$('#confirm_dialog').dialog({
modal: true,
title: "確認",
buttons: {
"OK": function() {
callback();
$(this).dialog("close");
},
"CANCEL": function() {
$(this).dialog("close");
}
}
});

}

JSPに追加したdivタグにメッセージ文字列を追加。
ボタンとして「OK」、「CANCEL」を用意
OKがおされた場合、引数で指定されたコールバックを実行する。

・メソッド使用箇所
 <a href="#" onclick="showConfirmDialog('削除してもよろしいですか?’, 
     function() {
        doPost(document.list_form, '/settings/memberList', 'id', ${member.key.id}, 'delete’);
     });” >
    <img src="/res/delete_off.png" alt="削除" border=0 width=20 height=20>

 </a>

コールバックとしてPOST処理を行う。


↓実行イメージ

















2015年3月16日月曜日

GAEと戯れる 21 - トラブル集 -

トラブル集

「必要な .class ファイルから間接的に参照されています」が発生した場合



ビルドパスの構成より、ライブラリを一旦削除し再度追加する。


↓それでも無理な場合


「.externalToolBuilders」について



ディレクトリトップに.externalToolBuildersが出来ていたので削除したらコンパイルがNGになってしまいました。
「.project」ファイルの中身

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
 <name>eNaviPrj</name>
 <comment></comment>
 <projects>
 </projects>
 <buildSpec>
  <buildCommand>
   <name>org.eclipse.jdt.core.javabuilder</name>
   <arguments>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
   <triggers>full,incremental,</triggers>
   <arguments>
    <dictionary>
     <key>LaunchConfigHandle</key>
     <value>&lt;project&gt;/.externalToolBuilders/com.google.appengine.eclipse.core.enhancerbuilder.launch</value>
    </dictionary>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
   <triggers>full,incremental,</triggers>
   <arguments>
    <dictionary>
     <key>LaunchConfigHandle</key>
     <value>&lt;project&gt;/.externalToolBuilders/com.google.appengine.eclipse.core.projectValidator.launch</value>
    </dictionary>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
   <triggers>full,incremental,</triggers>
   <arguments>
    <dictionary>
     <key>LaunchConfigHandle</key>
     <value>&lt;project&gt;/.externalToolBuilders/com.google.gdt.eclipse.core.webAppProjectValidator.launch</value>
    </dictionary>
   </arguments>
  </buildCommand>
 </buildSpec>
 <natures>
  <nature>org.eclipse.jdt.core.javanature</nature>
  <nature>com.google.appengine.eclipse.core.gaeNature</nature>
  <nature>com.google.gdt.eclipse.core.webAppNature</nature>
 </natures>
</projectDescription>
赤字の箇所でディレクトリを指定している。
試しに新規にGAEプロジェクトを作成しても.externalToolBuildersは作成されない。


↓新規に作成したプロジェクトの.projectファイル
<buildSpec>
  <buildCommand>
   <name>org.eclipse.wst.common.project.facet.core.builder</name>
   <arguments>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>org.eclipse.jdt.core.javabuilder</name>
   <arguments>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>com.google.gdt.eclipse.core.webAppProjectValidator</name>
   <arguments>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>com.google.appengine.eclipse.core.enhancerbuilder</name>
   <arguments>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>com.google.appengine.eclipse.core.gaeProjectChangeNotifier</name>
   <arguments>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>com.google.appengine.eclipse.core.projectValidator</name>
   <arguments>
   </arguments>
  </buildCommand>
  <buildCommand>
   <name>com.google.gwt.eclipse.core.gwtProjectValidator</name>
   <arguments>
   </arguments>
  </buildCommand>
 </buildSpec>


特に外部フォルダを作成しなくてもよさげ
※ビルド構成を見たい場合は、プロジェクト右クリック > 「プロパティ」、「ビルダー」で確認できる


Metaファイルが生成されない



いくらコンパイルしてもmetaファイルが生成されない場合


1.そもそもアノテーション処理が有効になっているか確認


プロジェクトのプロパティ > 「Javaコンパイラー」 > 「注釈処理」



















生成されるソースディレクトリには「src」を設定




2.ファクトリーパスにslim3-gen-XXX.jarが追加されているか


プロジェクトのプロパティ > 「Javaコンパイラー」 > 「注釈処理」 > 「ファクトリーパス」





















2015年3月13日金曜日

GAEと戯れる 20 - gdata スプレットシートのリンク取得 -

gdataを使って、スプレットシートのリンクを取得

・サンプル
protected Navigation run() throws Exception {

SpreadSheetService ss = new SpreadSheetService(“XXXXX");
SpreadsheetEntry se = ss.findSheet(“XXXXX");
System.out.println(se.getHtmlLink().getHref());
request.setAttribute("href", se.getHtmlLink().getHref()); // ★★
WorksheetEntry we = se.getDefaultWorksheet();

// 更新対象のセルを取得
        CellQuery cellQuery = new CellQuery(we.getCellFeedUrl());
        cellQuery.setRange("A1:C1");
        cellQuery.setReturnEmpty(true); // 空セルも返すようにする
        CellFeed cellFeed = ss.getCellFeed(cellQuery);

        // 更新
        CellEntry cellEntry;
        // A1
        cellEntry = cellFeed.getEntries().get(0);
        System.out.println(cellEntry.getTitle().getPlainText());
        cellEntry.changeInputValueLocal("3");
        cellEntry.update();
        // B1
        cellEntry = cellFeed.getEntries().get(1);
        System.out.println(cellEntry.getTitle().getPlainText());
        cellEntry.changeInputValueLocal("4");
        cellEntry.update();
        // C1
        cellEntry = cellFeed.getEntries().get(2);
        System.out.println(cellEntry.getTitle().getPlainText());
        cellEntry.changeInputValueLocal("=SUM(A1,B1)");
        cellEntry.update();

        System.out.println("セルの更新が完了しました。");
return super.run();

}

・JSP側
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Index</title>
</head>
<body>
<p>Hello Index !!!</p>
<a href="${href}">link</a>
</body>

</html>


★★の箇所がスプレットシートのリンクを取得している箇所
  SpreadsheetEntry#getHtmlLink()
  Link#getHref()

・実行












↓リンクを押すと・・


















ちゃんとスプレットシートに遷移しました^^
ただ、当然アカウントのログインは求められます。

2015年3月9日月曜日

GAEと戯れる 19 - gdataエラー -

gdataを使ったら叱られる

何も考えずに、gdataのjarをlibに入れて動かしたら以下のエラーが出た

HTTP ERROR 500

Problem accessing /. Reason:
    com/google/gdata/client/Query

Caused by:

java.lang.NoClassDefFoundError: com/google/gdata/client/Query
 at XX.XX.XXXXXX.org.controller.IndexController.run(IndexController.java:19)
 at org.slim3.controller.Controller.runBare(Controller.java:111)
 at org.slim3.controller.FrontController.processController(FrontController.java:491)
 at org.slim3.controller.FrontController.doFilter(FrontController.java:277)
 at org.slim3.controller.FrontController.doFilter(FrontController.java:237)
 at org.slim3.controller.FrontController.doFilter(FrontController.java:199)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.slim3.datastore.DatastoreFilter.doFilter(DatastoreFilter.java:55)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.slim3.controller.HotReloadingFilter.doHotReloading(HotReloadingFilter.java:223)
 at org.slim3.controller.HotReloadingFilter.doFilter(HotReloadingFilter.java:187)
 at org.slim3.controller.HotReloadingFilter.doFilter(HotReloadingFilter.java:157)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:127)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
 at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
 at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
 at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
 at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
 at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
 at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
 at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:98)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:490)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at org.mortbay.jetty.Server.handle(Server.java:326)
 at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
 at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
 at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
 at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
 at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
 at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
 at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.lang.ClassNotFoundException: com.google.gdata.client.Query
 at java.lang.ClassLoader.findClass(ClassLoader.java:531)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
 at org.slim3.controller.HotReloadingClassLoader.loadClass(HotReloadingClassLoader.java:114)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
 ... 46 more

Caused by:

java.lang.ClassNotFoundException: com.google.gdata.client.Query
 at java.lang.ClassLoader.findClass(ClassLoader.java:531)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
 at org.slim3.controller.HotReloadingClassLoader.loadClass(HotReloadingClassLoader.java:114)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
 at XX.XX.XXXXXX.org.controller.IndexController.run(IndexController.java:19)
 at org.slim3.controller.Controller.runBare(Controller.java:111)
 at org.slim3.controller.FrontController.processController(FrontController.java:491)
 at org.slim3.controller.FrontController.doFilter(FrontController.java:277)
 at org.slim3.controller.FrontController.doFilter(FrontController.java:237)
 at org.slim3.controller.FrontController.doFilter(FrontController.java:199)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.slim3.datastore.DatastoreFilter.doFilter(DatastoreFilter.java:55)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.slim3.controller.HotReloadingFilter.doHotReloading(HotReloadingFilter.java:223)
 at org.slim3.controller.HotReloadingFilter.doFilter(HotReloadingFilter.java:187)
 at org.slim3.controller.HotReloadingFilter.doFilter(HotReloadingFilter.java:157)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:127)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
 at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
 at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
 at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
 at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
 at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
 at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
 at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:98)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:490)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at org.mortbay.jetty.Server.handle(Server.java:326)
 at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
 at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
 at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
 at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
 at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
 at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
 at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

Powered by Jetty://


以下ソース
public class IndexController extends BaseController {

/* (non-Javadoc)
* @see XX.XX.XXXXXX.org.controller.BaseController#run()
*/
@Override
protected Navigation run() throws Exception {
SpreadSheetService ss = new SpreadSheetService("test");
//SpreadsheetEntry se = ss.findSheet("aaa");
return super.run();
}

}

なぜかSpreadSheetServiceをnewしている箇所で
com/google/gdata/client/Queryクラスが見つからない?

色々調べた所、場所が間違っていましたorz
プロジェクト直下のlibフォルダにjarをコピーしていましたが、
正解はWEB-INF/lib配下にコピーし、ビルドパスも通さないといけない模様。
















2015年2月28日土曜日

GAEと戯れる 18 - スクロールするテーブル -

今回は画面関連を色々・・・


1. スクロール付きのテーブルを作る
     MFCなんかでいうListCtrlみたいなもん?

     ポイントは<table>の中に<table>を作るらしい。
     内側のtableの属性がoverflow: autoを設定してやる。

     例)
    <div id="list_area">
      <table id="tbl_outside">
        <caption>登録お店情報一覧</caption>
        <thead>
          <tr>
            <th width="3%">ID</th>
            <th width="12%">名前</th>
            <th width="15%">住所</th>
            <th width="10%">座標</th>
            <th width="10%">電話番号</th>
            <th width="10%">予約変更可能日</th>
            <th width="5%">前回ステータス</th>
            <th width="5%">前回参加人数</th>
            <th width="5%">前回総支出</th>
            <th width="25%">メモ</th>
          </tr>
        </thead>
        <tfoot>
          <tr>
            <td colspan="10">登録お店情報一覧</td>
          </tr>
        </tfoot>
        <tbody>
          <tr>
            <td colspan="10">
              <div style="height:300px; overflow:auto;">
                <table id="tbl_inside">
                  <c:forEach var="shop" items="${shops}">
                    <tr>
                      <td width="3%">${shop.key.id}</td>
                      <td width="12%">${shop.name}</td>
                      <td width="15%">${shop.address}</td>
                      <td width="10%">${shop.coordinate}</td>
                      <td width="10%">${shop.telephone}</td>
                      <td width="10%">${shop.checkDate}</td>
                      <td width="5%">${shop.lastStatus}</td>
                      <td width="5%">${shop.lastPartakeNum}</td>
                      <td width="5%">${shop.lastPayment}</td>
                      <td width="25%">${shop.memo}</td>
                    </tr>
                  </c:forEach>
                </table>              
              </div>
            </td>
          </tr>
        </tbody>
      </table>

    </div>

イメージ







参考サイト
http://javascript123.seesaa.net/article/103060039.html
関連
http://www12.plala.or.jp/costellazione/css-make/write.html
http://yume.hacca.jp/koiki/css/table/table.htm


2. 戻るボタンを作る
    よくある前のページに戻るボタンを作ってみる。マウスをかざしたら絵が変わる。

    戻る処理は
    onclick=“history.back(); return false;”

    マウスをかざしたら絵が変わるやつはjQueryを使用すると便利な事に!!
/**
 * 画像切り替え
 */
$(function(){
     $('a img').hover(function(){
        $(this).attr('src', $(this).attr('src').replace('_off', '_on'));
          }, function(){
             if (!$(this).hasClass('currentPage')) {
             $(this).attr('src', $(this).attr('src').replace('_on', '_off'));
        }
   });

});

自動で画像ファイルのon/off文字列を変更してくれる。便利〜。

例)







↓マウスをかざすと







いい感じ^^

参考サイト
http://www.tohoho-web.com/how2/link.htm
http://www.red.oit-net.jp/tatsuya/java/image3.htm
http://neet-navi.info/wordpress/431/








2015年2月22日日曜日

GAEと戯れる 17 - Validatorsについて -

Validatorsについて

Slim3にはValidatorsクラスがあり、チェックを行いたい項目をVaidatorsクラスに
セットし、チェックを行う。

例) コントローラ内で、isPost() == trueの場合に名前入力チェックを行う
        // 入力チェック
        Validators v = new Validators(request);
        v.add(PROPERTY_NAME, v.required());
        if (!v.validate()) {
            // チェックエラー
            ※追記
            Errors err = v.getErrors();
            //errors.put("message", err.get(PROPERTY_NAME));
            わざわざerrors.putしなくても、Validatorsクラスでは内部で
            errorsを持っているのでjspでそっちを表示できる
            return;
        }


・v.addメソッドでチェック対象項目と、チェックの種類を指定できる。
・v.validateメソッドで指定された内容に従ってチェックを行う
・v.getErrorsメソッドでエラーメッセージを取得
 ※エラーメッセージはapplication_XX.propertiesに
      validator.required={0} XXXXXXXXXXX
      という形で設定されている。

エラーメッセージの{0}にはチェック対象項目が入るが、上記の例では
PROPERTY_NAME = "name";
で定義している為、{0}にはnameが入る。
{0}に入る値を変更したい場合は、application_XX.propertiesに以下の様に定義
       label.name=名前

validator.required={0}は必須です。
validator.byteType={0}はバイトでなければいけません。
validator.shortType={0}は短整数でなければいけません。
validator.integerType={0}は整数でなければいけません。
validator.longType={0}は長整数でなければいけません。
validator.floatType={0}は単精度実数でなければいけません。
validator.doubleType={0}は倍精度実数でなければいけません。
validator.numberType={0}は数値({1})ではありません。
validator.dateType={0}は日付({1})ではありません。
validator.minlength={0}の長さが最小値({1})未満です。
validator.maxlength={0}の長さが最大値({1})を超えています。
validator.range={0}は{1}と{2}の間でなければいけません。
validator.regexp={0}が不正です。

label.name=名前


JSP側)
        <div id="err">
          ${errors.message}
        </div>

※errorsは継承元クラスで定義されているオブジェクト

表示例)














2015年2月14日土曜日

GAEと戯れる 16 - Polymorphic Model -

Slim3のPolymorphic Modelについて

Polymorphic Modelについてお勉強。
簡単に言えば・・・

A extends B
C extends B

のモデルがあった場合、BでqueryするとA, Cがヒットされ
AでqueryするとAだけがヒットされるという便利そうな仕組み。
プロパティが親子で重複するとエラーになる。

試しに作ってみた

・基底クラス
/**
 * 基底モデルクラス
 *
 * @author slowhand
 */
@Model
public abstract class BaseModel implements Serializable {

    /** デフォルトシリアルID */
    private static final long serialVersionUID = 1L;
   
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(version = true)
    private Long version;

    ・・・以下略・・・
}

・継承したクラス

@Model(schemaVersion = 1)
public class MemberListModel extends BaseModel {

    private static final long serialVersionUID = 1L;

    /** メンバー名 */    private String name;
   
    /** メールアドレス */
    private String mailAdr;

    ・・・以下略・・・
}

こうするとmetaクラスがBaseModelとMemberListModel用の2つ作成される。





それぞれのMetaクラスのコンストラクタで階層を作成している。
・BaseModelMeta





・MemberListModelMeta




参考URL
http://d.hatena.ne.jp/bufferings/20100121/1264093364

簡単な登録・参照ページを作成してみる。
・member_list.jsp
<%@page pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@taglib prefix="f" uri="http://www.slim3.org/functions"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>メンバーリスト</title>
</head>
<body>
<p>新規登録</p>
<form method="post" action="/settings/memberList">
<table>
<tr><td>名前</td><td><input type="text" ${f:text("name")}></td></tr>
<tr><td>メールアドレス</td><td><input type="text" ${f:text("mail")}></td></tr>
<tr><td></td><td><input type="submit"></td></tr>
</table>
</form>
<hr>
<table border="1">
<c:forEach var="member" items="${members}">
<tr>
<td>${member.key}</td>
<td>${member.name}</td>
<td>${member.mailAdr}</td>
</tr>
</c:forEach>
</table>
</body>
</html>

・MemberListController
public class MemberListController extends BaseController {

    private static final String RETURN_PATH = "member_list.jsp";
   
    private static final String PROPERTY_NAME = "name";
    private static final String PROPERTY_MAILADR = "mail";
   
    private static final String PROPERTY_MEMBERS = "members";
   
    @Override
    public Navigation run() throws Exception {
        if (isPost()) {
            register();
        }
       
        // メンバー一覧の取得
        List<MemberListModel> memberList = Datastore.query(MemberListModel.class).asList();
        request.setAttribute(PROPERTY_MEMBERS, memberList);
        return forward(RETURN_PATH);
    }
   
    /**
     * メンバー新規登録
     */
    private void register() {
        String name = asString(PROPERTY_NAME);
        String mailAdr = asString(PROPERTY_MAILADR);
       
        MemberListModel memberListModel = new MemberListModel();
        memberListModel.setKey(Datastore.allocateId(MemberListModelMeta.get()));
        memberListModel.setName(name);
        memberListModel.setMailAdr(mailAdr);
        // データストアに新規登録
        Datastore.put(memberListModel);
    }
}

・実行結果























・データストアの中身









Entityは基底クラスのBaseModelしか作成されておらず、
フィールドのslim3.classHierarchyListにサブクラスが設定されている。
query時にはこの項目をwhereに追加し検索する。

※idフィールドを作成し、auto incrementにしようとしたが、
   entityのKeyにIDで採番が可能。
   Entity#setKey(Datastore.allocateId(EntityMeta.get()));
参考URL
http://www.casleyconsulting.co.jp/blog-engineer/gae/【入門編】slim3で始める!gaejでwebアプリケーション開-4/

2015年1月15日木曜日

GAEと戯れる 15 - セッション -

Google Appsとの連携の前に・・・ちょっとセッションを使ってみる。

まず、使えるようにするには、「appengine-web.xml」を修正する。
























<session-enabled>をtrueにする。
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>acount-war</application>
<version>1</version>
<precompilation-enabled>true</precompilation-enabled>
<system-properties>
    <property name="slim3.hotReloading" value="true"/>
    <!--
        <property name="slim3.datastoreDeadline" value="8"/>
        <property name="slim3.uploadSizeMax" value="1000000"/>
        <property name="slim3.uploadFileSizeMax" value="100000"/>
        -->
    <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties"/>
</system-properties>
<sessions-enabled>true</sessions-enabled>
<threadsafe>true</threadsafe>
</appengine-web-app>

使い方
  1. 設定方法
   sessionScope("key"“value");  

  2. 取り出し方
   String value = this.sessionScope("key");

  3. 削除
  removeSessionScope("key);

  まあ、分かりやすい^^

また、セッションはDatastoreに蓄積するらしいので定期的に削除してやらないといけないらしい。

参考URL