Kobe GTUGの画像をタイトルに設定してみました。
うん、かっこいいです!
まずは Javaです。講師の takagig さんから、スライドを見ながら、GAEの概要説明。昨今色々な Cloud 環境が出て来ていますし、GAE についても色々な議論があるようですが、やはり魅力的な環境であることに違いは無いかと思います。個人的には、なんとなく玄人っぽくて、かなり好きな方です♪//モデルの定義(JDO使用)
@PersistenceCapable
public class Post {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent
private String message;
@Persistent
private Date date;
public Post(String message, Date date) {
this.message = message;
this.date = date;
}
public Key getKey() {
return key;
}
public String getMessage() {
return this.message;
}
public Date getDate() {
return this.date;
}
public void setMessage(String message) {
this.message = message;
}
public void setDate(Date date) {
this.date = date;
}
}
//リクエストハンドラ
@SuppressWarnings("serial")
public class SampleServlet extends HttpServlet {
//メッセージ一覧と投稿フォームの表示
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
PrintWriter w = resp.getWriter();
w.println("<html><head><title>Java</title><body>");
//メッセージ一覧の取得と表示
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery(Post.class);
query.setOrdering("date desc"); //日付降順でソート
try {
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd hh:mm:ss ");
@SuppressWarnings("unchecked")
List<Post> posts = (List<Post>) query.execute();
if (!posts.isEmpty()) {
for (Post p : posts) {
w.print(dateFormat.format(p.getDate()));
w.print(p.getMessage());
w.println("<br />");
}
}
} finally {
query.closeAll();
}
//投稿フォームの表示
w.println("<form method='post'>");
w.println("<div><textarea name='message' rows='3' cols='60'></textarea></div>");
w.println("<div><input type='submit' value='Send'></div>");
w.println("</form>");
w.println("</body></html>");
}
//投稿処理
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String message = req.getParameter("message");
Post post = new Post(message, new Date());
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(post);
} finally {
pm.close();
}
resp.sendRedirect("/"); //一覧画面へリダイレクト
}
}
サンプルコード(勉強会使用分の一部):
少しの休憩をはさんで、まだ Java 熱冷めやらぬ中、そろそろ Python… の声があがって下田さんの登場です。急病で自宅から Google+ Hangouts での解説です。すごい執念です。takagig さんが Hangouts のセットアップをして…ぉお、下田さんの声が聞こえます。やや小さいか…。まぁ、突然のことなので仕方ないですね (; ^ω^)。#モデルの定義
class Post(db.Model):
message = db.StringProperty()
date = db.DateTimeProperty()
#リクエストハンドラ
class PostAction(webapp.RequestHandler):
#投稿一覧と投稿フォームの表示
def get(self):
out = self.response.out.write
out("<html><head></head><body>")
#メッセージ一覧の取得と表示
posts = Post.all()
posts.order("-date") #日付降順でソート
for post in posts:
out(post.date.strftime("%Y-%m-%d %H:%M:%S: "))
out(post.message)
out('<br />')
#投稿フォームの表示
out('<form method="post">')
out('<div><textarea name="message" rows="3" cols="60"></textarea></div>')
out('<div><input type="submit" value="Send"></div>')
out('</form>')
out('</body></html>')
#投稿処理
def post( self ):
post = Post()
post.date = datetime.today()
post.message = self.request.get('content')
post.put()
self.redirect('/') //一覧画面へリダイレクト
ちょっと押し気味で Go 言語開始。プロペラブのちいといつさん登場です。いつも通りの軽妙トークでサクサクと進行して頂きました。まずは環境構築。まだ Windows 用の環境は無いため、Windows の方は VM 使ったりして取り組んでおられたみたいです。手順はざっと次の通り://モデルの定義
type Post struct {
Message string //型は後ろに書く。先頭大文字がpublic
Date datastore.Time
}
//メッセージ一覧と投稿フォームの表示
func getList(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write([]byte(`<html><head><title>Go</title></head><body>`))
//メッセージ一覧の取得と表示
c := appengine.NewContext(r)
q := datastore.NewQuery("Posts")
q.Order("-Date") //日付降順でソート
count, err := q.Count(c) //Goは関数が複数値を返せる
if err != nil { }
posts := make([]Post, 0, count) //Goのデータ型の1つ、slice の初期化
_, err = q.GetAll(c, &posts)
if err != nil { }
for _, post := range posts {
date := time.SecondsToLocalTime(int64(post.Date) / 1000000)
datestr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second)
wk := fmt.Sprintf("%s: %s<br />", datestr, post.Message)
w.Write([]byte(wk))
}
//投稿フォームの表示
w.Write([]byte(`<form action="register" method="post">`))
w.Write([]byte(`<div><textarea name="message" rows="3" cols="60"></textarea></div>`))
w.Write([]byte(`<div><input type="submit" value="Send"></div>`))
w.Write([]byte(`</form>`))
w.Write([]byte(`</body></html>`))
}
//投稿処理
func putPost(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
var post Post
post.Message = r.FormValue("message")
post.Date = datastore.SecondsToTime(time.Seconds())
_, err := datastore.Put(c, datastore.NewIncompleteKey(c, "Posts", nil), &post)
if err != nil { }
http.Redirect(w, r, "/", http.StatusFound) //一覧画面へリダイレクト
}
ところで、ちいといつさんご用意ので、サンプルプログラムを実行するとコンパイルエラー。ちいといつさんに伺うと、なんでも理解を深めるために意図的に仕組んだそうで...ww Σ(゚Д゚;)!イジワル…
飛び込み?で @esperia09 さんが GAE と HTML5 を駆使した Web シーケンサーを紹介して頂きました。確かお風呂で思いつかれて半日で作られたとか。スゴスです。機能を簡単に紹介すると次のような感じになります。