本篇引导重点在于使用playframework实现一个网页,使用groovy模板等技术。本系列代码已经上传至github,有需要的可以自行下载
上一篇我们已经建立了博客的数据模型data model
,现在来实现一个博客中最常用的页面:最新文件展示页。
我们先脑补一下实现的效果:
启动时加载默认数据
此页面需要数据才能展示出效果,所以这里使用上一篇的yml
的方式在应用启动时载入数据。
创建/app_1/app/Bootstrap.java
作业,使用Fixtures
加载默认数据集:
import models.User;
import play.Logger;
import play.jobs.Job;
import play.jobs.OnApplicationStart;
import play.test.Fixtures;
@OnApplicationStart
public class Bootstrap extends Job {
@Override
public void doJob() {
if (User.count() == 0) {
Fixtures.loadModels("inital-data.yml");
Logger.info("init complated");
}
}
}
@OnApplicationStart
注解告诉Play在应用启动时执行任务。
实际上任务会运行在
DEV
或者PROD
模式下。在DEV模式下,Play会等待第一个请求去启动,所以Job会在收到请求时同步执行。用这种方式任务出错会在浏览器上显示错误信息;而在PROD模式下,任务会在应用启动时执行,与play run命令同步执行,如果任务发出错错误,将会阻止应用的启动。
这里用到的默认数据文件inital-data.yml
放在app_/conf
目录下,你可以把上一篇的data.yml
复制过来使用。
博客的首页
现在,我们可以真正开始编码博客的首页
你还记得通过play new 生成的项目第一个页面是如何显示出来的吗?首先,指定路由的URL/
会调用controllers.Application.index()
方法,然后这个方法会调用render()
并且执行模板/app_1/app/views/Application/index.html
在本例中,我们继续使用他原有的代码,并在其基础上改一下。
打开/app_1/app/controllers/Application.java
controller并且修改index()
方法,如下:
package controllers;
import models.Post;
import play.mvc.Controller;
import java.util.List;
public class Application extends Controller {
public static void index() {
// 取出第一篇文章
Post frontPost = Post.find("order by postedAt desc").first();
// 取出第二篇到第11篇文章
List<Post> olderPosts = Post.find("order by postedAt desc").from(1).fetch(10);
render(frontPost, olderPosts);
}
}
你能看到我们为render()
方法传递了参数,它允许我们使用在模板通过相同的名字使用这些对象。也就是,frontPost
和olderPosts
可以在模板中使用。
打开文件app_1/app/views/Application/index.html
按如下修改:
#{extends 'main.html' /}
#{set title:'Home' /}
#{if frontPost}
<div class="post">
<h2 class="post-title">
<a href="#">${frontPost.title}</a>
</h2>
<div class="post-metadata">
<span class="post-author">by ${frontPost.author.fullName}</span>
<span class="post-date">${frontPost.postedAt.format('MMM dd')}</span>
<span class="post-comments">
|
${frontPost.comments.size() ?: 'no'}
comment${frontPost.comments.size().pluralize()}
#{if frontPost.comments}
, latest by ${frontPost.comments[-1].author}
#{/if}
</span>
</div>
<div class="post-content">
${frontPost.content.nl2br()}
</div>
</div>
#{if olderPosts}
<div class="older-posts">
<h3>Older posts <span class="from">from this blog</span></h3>
#{list items:olderPosts, as:'oldPost'}
<div class="post">
<h2 class="post-title">
<a href="#">${oldPost.title}</a>
</h2>
<div class="post-metadata">
<span class="post-author">
by ${oldPost.author.fullName}
</span>
<span class="post-date">
${oldPost.postedAt.format('dd MMM yy')}
</span>
<div class="post-comments">
${oldPost.comments.size() ?: 'no'}
comment${oldPost.comments.size().pluralize()}
#{if oldPost.comments}
- latest by ${oldPost.comments[-1].author}
#{/if}
</div>
</div>
</div>
#{/list}
</div>
#{/if}
#{/if}
#{else}
<div class="empty">
There is currently nothing to read here.
</div>
#{/else}
你可以在模板章节 中看到Groovy是如何工作的。从根本上说,它允许你动态地访问Java对象。在Groovy模板引擎下,你能使用很多很好的结构(比如?:
操作符),但你并不需要学习Groovy去写Play的模板,如果你对其他任何一门模板语言熟悉,比如JSP和JSTL,你将无师自通,得心应手。
添加样式文件
为了页面更美观,需要为页面添加样式,编样式文件/public/stylesheets/main.css
,为了学便大家学习,可以在这里下载此css文件 。
刷新首页能看到如下效果:
一个简单的首页做完了,但你会发现页面模板中有很多重复的代码,比说文章内容和评论等,此时作为一名资深的程序员,如果在Java代码中,应该想要为相同的代码创建一个方法供模板调用,在Play中你可以使用Play tag
标签来实现这个功能。
要创建一个标签,只需要在views/tags创建模板即可。本例中创建文件/app_1/app/views/tags/display.html
,一个标签本质上就是一个模板,它像一个函数
一样拥有参数,#{display /}
标签有两个参数,Post model和显示模式home
,teaser
,full
,代码如下
*{ 使用`full`, `home`, 'teaser`三种模式显示文章内容 }*
<div class="post ${_as == 'teaser' ? 'teaser' : ''}">
<h2 class="post-title">
<a href="#">${_post.title}</a>
</h2>
<div class="post-metadata">
<span class="post-author">by ${_post.author.fullName}</span>,
<span class="post-date">${_post.postedAt.format('dd MMM yy')}</span>
#{if _as != 'full'}
<span class="post-comments">
| ${_post.comments.size() ?: 'no'}
comment${_post.comments.size().pluralize()}
#{if _post.comments}
, latest by ${_post.comments[-1].author}
#{/if}
</span>
#{/if}
</div>
#{if _as != 'teaser'}
<div class="post-content">
<div class="about">Detail: </div>
${_post.content.nl2br()}
</div>
#{/if}
</div>
#{if _as == 'full'}
<div class="comments">
<h3>
${_post.comments.size() ?: 'no'}
comment${_post.comments.size().pluralize()}
</h3>
#{list items:_post.comments, as:'comment'}
<div class="comment">
<div class="comment-metadata">
<span class="comment-author">by ${comment.author},</span>
<span class="comment-date">
${comment.postedAt.format('dd MMM yy')}
</span>
</div>
<div class="comment-content">
<div class="about">Detail: </div>
${comment.content.escape().nl2br()}
</div>
</div>
#{/list}
</div>
#{/if}
在模板中使用标签:
#{extends 'main.html'/}
#{set title :'Home' /}
#{if frontPost}
#{display post:frontPost, as: 'home'/}
#{if olderPosts.size()}
<div class="older-posts">
<h3>Older posts <span class="from">from this blog</span> </h3>
#{list items:olderPosts, as :'oldPost'}
#{display post:oldPost, as:'teaser'/}
#{/list}
</div>
#{/if}
#{/if}
#{else}
<div class="empty">
There is currently nothing to read here.
</div>
#{/else}