主页面
显示当前发表博客的完整内容,以及历史博客列表
Bootstrap Job
一个play job任务就是一个在没有任何http请求的情况下执行一些特定的方法
应用程序在启动时或间隔一定时间后自动执行某个方法
应用程序启动便执行基础数据的初始化操作:
import models.User; import play.jobs.Job; import play.jobs.OnApplicationStart; import play.test.Fixtures; /** * 使用@OnApplicationStart注释Job,告诉Play在应用程序启动时便执行这个任务 * DEV模式和PROD模式下,任务执行情况不同 * DEV模式:等到第一个客户端请求才会执行 * PROD模式:应用程序启动时就执行 * @author lenovo * */ @OnApplicationStart public class Bootstrap extends Job { public void doJob() { //检查用户是否为空 if(User.count()==0) { Fixtures.loadModels("initial-data.yml"); } } }
其中,在yabe\conf目录下新建initial-data.yml文件,用来初始化Blog系统的基础数据!
# Test data User(bob): email: bob@gmail.com password: secret fullname: Bob isAdmin: true User(jeff): email: jeff@gmail.com password: secret fullname: Jeff User(paul): email: paul@gmail.com password: secret fullname: Paul Post(firstBobPost): title: About the model layer postedAt: 2009-06-14 author: bob content: > The model has a central position in a Play! application. It is the domain-specific representation of the information on which the application operates. Martin fowler defines it as : Responsible for representing concepts of the business, information about the business situation, and business rules. State that reflects the business situation is controlled and used here, even though the technical details of storing it are delegated to the infrastructure. This layer is the heart of business software. Post(secondBobPost): title: Just a test of YABE postedAt: 2009-03-25 author: bob content: > Well, it's just a test. Post(jeffPost): title: The MVC application postedAt: 2009-06-06 author: jeff content: > A Play! application follows the MVC architectural pattern as applied to the architecture of the Web. This pattern splits the application into separate layers: the Presentation layer and the Model layer. The Presentation layer is further split into a View and a Controller layer. Comment(c1): author: Guest content: > You are right ! postedAt: 2009-06-14 post: firstBobPost Comment(c2): author: Mike content: > I knew that ... postedAt: 2009-06-15 post: firstBobPost Comment(c3): author: Tom content: > This post is useless ? postedAt: 2009-04-05 post: secondBobPost
打开yabe\app\controllers\Application.java,修改index()
package controllers; import play.*; import play.mvc.*; import java.util.*; import models.*; public class Application extends Controller { public static void index() { //最新的博客 Post frontPost = Post.find("order by postedAt desc").first(); //过去的博客 List<Post> olderPosts = Post.find("order by postedAt desc").from(1).fetch(10); render(frontPost,olderPosts); } }
修改yabe\app\views\Application\index.html
action通过render()传递对象,在模块中只需要使用${xxx}就能获取到相应的对象,进而展现数据。
#{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('MMMdd')}</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}
抽取相同部分出来,提高代码复用性
新增yabe\app\views\tags\display.html
display.html被index.html使用标签(另一个模板)方式进行操作
由于index.html中通过#{display post:frontPost, as:'home' /}来调用display.html模板
则display.html中就可以通过_post 和 _as 来获取对应的参数值
#{extends 'main.html' /} #{set title:'Home' /} <div class="post ${_as == 'teaser' ? 'teaser' : ''}"> <h2> <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-data">${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}
修改index.html,直接通过display模板完成页面的显示
#{extends 'main.html' /} #{set title:'Home' /} #{if frontPost} <!--调用display模板--> #{display post:frontPost, as:'home' /} #{if olderPosts.size()} <div class="older-posts"> <h3> Older posts <span class="form">from this blog</span> </h3> #{list items:olderPosts ,as:'oldPost'} <!--调用display模板--> #{display post:oldPost, as:'teaser' /} #{/list} </div> #{/if} #{/if} #{else} <div class="empty"> There is currently nothing to read here! </div> #{/else}
刷新页面
修改yabe\public\stylesheets\main.css,对页面进行美观修饰
附:main.css
/** Main layout **/ html, body { background: #364B66 !important; font-family: Helvetica, Arial, Sans !important; } body { width: 900px; padding: 0 30px; margin: auto; } /** Blog header **/ #header { padding: 10px 0; position: relative; } #logo { display: block; height: 49px; margin-left: 20px; color: #fff; font-size: 48px; font-weight: bold; letter-spacing: -4px; text-shadow: 1px 2px 2px #000; } #logo span { color: #f00; font-size: 70%; } #tools { list-style: none; margin: 0; padding: 0; position: absolute; right: 0; top: 30px; right: 20px; } #tools a { color: #fff; text-decoration: none; } #title { background: #B8C569; padding: 20px 30px 30px 20px; margin: 20px 0; color: #3C4313; position: relative; -webkit-border-radius: 16px; -webkit-box-shadow: 0 2px 0 #93A045; -moz-border-radius: 16px; } /** A little hacky to create arrows without images **/ .about { text-indent: -999em; display: block; width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 10px solid #BAC36E; border-top: 0; position: absolute; top: -10px; left: 60px; } #title h1 { font-size: 64px; margin: 0; } #title h1 a { text-decoration: none; color: inherit; } #title h2 { font-size: 26px; margin: 0; font-weight: normal; } /** Main content **/ #main { background: #314660; background: -webkit-gradient(linear, left top, left 30%, from(#314660), to(#364B66)); -webkit-border-radius: 16px; -moz-border-radius: 16px; padding: 20px; } /** Post **/ .post .post-title { margin: 0; } .post .post-title a { font-size: 36px; color: #F5C2CC; text-decoration: none; } .post .post-metadata { color: #BAC36E; display: block; font-size: 70%; display: inline-block; } .post .post-author { font-size: 130%; font-weight: bold; } .post .post-metadata a { color: #9FA85D; } .post .post-content { position: relative; background: #fff; padding: 10px; margin: 10px 0 50px 0; -webkit-border-radius: 10px; -moz-border-radius: 10px; -webkit-box-shadow: 0 2px 0 #BBBBBB; } .post .about { text-indent: -999em; display: block; width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 10px solid #fff; border-top: 0; position: absolute; top: -6px; left: 24px; } /** Older posts **/ .older-posts h3 { color: #869AB1; font-size: 28px; margin-bottom: 15px; } .older-posts h3 .from { font-weight: normal; font-size: 70%; } .older-posts .post { margin-bottom: 15px; border-left: 3px solid #869AB1; padding-left: 10px; } .older-posts .post-title a { padding: 0; color: #131921; font-size: 20px; } .older-posts .post-metadata { color: #869AB1; padding: 0; font-size: 12px; } .older-posts .post-metadata a { color: #869AB1; } /** Comments **/ .comments { margin-bottom: 30px; } h3 { color: #869AB1; font-size: 18px; margin-bottom: 15px; } h3 span { font-size: 80%; font-weight: normal; } .comment { width: 70%; clear: both; } .comment .comment-metadata { color: #869AB1; display: block; font-size: 50%; display: block; float: left; width: 80px; text-align: right; } .comment .comment-author { font-size: 150%; font-weight: bold; display: block; } .comment .comment-content { position: relative; background: #E4EAFF; color: #242C58; font-size: 80%; margin-top: 10px; margin-bottom: 10px; margin-left: 100px; padding: 10px; -webkit-border-radius: 10px; -moz-border-radius: 10px; } .comment .about { text-indent: -999em; display: block; width: 0; height: 0; border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-right: 10px solid #E4EAFF; border-left: 0; position: absolute; top: 4px; left: -4px; } /** Form **/ form { padding: 10px; background: #253142; background: -webkit-gradient(linear, left top, left 60%, from(#253142), to(#364B66)); -webkit-border-radius: 10px; -moz-border-radius: 10px; } form .error { background: #c00; color: #fff; font-size: 90%; padding: 3px 5px; -webkit-border-radius: 6px; -moz-border-radius: 6px; -webkit-box-shadow: 0 2px 0 #800; } form .error:empty { display: none; } form p { margin: 5px 0 0 0; } form textarea { width: 70%; height: 150px; } form input, form textarea { font-size: 14px; } form label { display: block; font-weight: bold; font-size: 90%; color: #aaa; margin-bottom: 3px; } #captcha{ display: block; height: 50px; } .success { background: #67AD10; color: #fff; padding: 10px; -webkit-border-radius: 6px; -moz-border-radius: 6px; -webkit-box-shadow: 0 2px 0 #4E840B; } /** Pagination **/ #pagination { list-style: none; padding: 0; position: relative; color: #869AB1; font-size: 90%; top: -20px; margin-bottom: 30px; } #pagination a { color: #869AB1; font-size: 90%; } #pagination #previous { position: absolute; top: 0; left: 0; } #pagination #previous:before { content: '<< '; } #pagination #next { position: absolute; top: 0; right: 0; } #pagination #next:after { content: ' >>'; } /** Footer **/ #footer { border-top: 1px solid #45597A; font-size: 70%; padding: 10px 30px; text-align: center; color: #869AB1; margin-top: 30px; } #footer a { color: #869AB1; font-weight: bold; } /** Admin **/ .tags-list .tag { cursor: pointer; color: red; } #adminMenu { list-style: none; padding: 0; margin: 0 0 20px 0; } #adminMenu li { display: inline; } #adminMenu li a { color: #fff; text-decoration: none; font-size: 80%; background: #591C64; padding: 2px 10px; -webkit-border-radius: 9px; -moz-border-radius: 9px; } #adminMenu li.selected a { background: #82A346; } #crudContent { color: #8B98AD; } #crudContent h2 { color: #EDC3CD !important; } #crudContent thead tr { background: #512162 !important; } #crudContent table { border: none !important; } #crudContent table td { color: #444; } tr.odd { background: #BECCE7 !important; } #crud #crudContent, #crudContent form, #crudListSearch, #crudListPagination, .crudButtons { background: transparent; border: none; padding: 0; } #crudListTable { margin: 10px 0; } .crudField, .objectForm { border: none; padding-left: 0; } .crudField label { color: #B8FA5C; } .crudHelp { color: #fff !important; } .crudField .tag { color: #111; font-size: 80%; } .crudButtons input { font-size: 110%; } .crudButtons { margin-top: 20px; border-top: 1px dotted #8B98AD; padding-top: 10px; } .crudFlash { border: 0; -webkit-border-radius: 8px; font-size: 80%; padding: 2px 10px; } .crudField .tag.selected { -webkit-border-radius: 8px; -moz-border-radius: 8px; } .crudField .error { background: transparent; border: none; padding: 0; color: pink; -webkit-box-shadow: none; } /** Login **/ #login form { background: #8B98AD !important; border: 0 !important; -webkit-border-radius: 16px; -moz-border-radius: 16px; } #login label, #password-field label, #username-field label { color: #161D28 !important; font-size: 110% !important; } #remember-field { display: none; } /** My posts **/ #admin .post { background: #fff; padding: 4px; margin: 0; font-size: 90%; } #admin .post.odd { background: #C0CBE5; } #admin .post a { color: #444; } #newPost { border-top: 1px dotted #C0CBE5; padding-top: 15px; } #newPost a { background: #C88116; -webkit-border-radius: 12px; -moz-border-radius: 12px; padding: 5px 10px; font-size: 80%; text-decoration: none; color: #fff; font-weight: bold; -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,.3); } #newPost a span { background: #7D510E; -webkit-border-radius: 8px; -moz-border-radius: 8px; padding: 0 5px 2px 5px; position: relative; top: -1px; } #postContent { width: 100%; height: 300px; } .hasError { background: pink; }
相关推荐
"yabe"这个文件名可能是项目的简称或别名,具体含义可能需要查看项目源代码才能明确。通常,一个Play项目会包含以下主要目录结构: 1. `app`:包含所有应用程序代码,如控制器、模型、视图和服务。 2. `conf`:存储...
在本教程中,我们将深入理解如何使用Play框架创建一个完整的Web项目,以一个博客应用为例,名为Yabe(Yet Another Blog Engine)。 首先,确保你的计算机已经安装了Java 5或更高版本,因为Play框架依赖于Java环境。...
综上所述,"yabe:另一个博客引擎 - Curso Play 1.3.1"涉及到使用Java语言和Play框架开发的一个博客引擎项目。通过学习这个课程或教程,开发者可以了解如何使用Play框架构建Web应用,并可能涉及数据库集成、模板引擎...
在CMD中运行`play new yabe`,然后进入项目目录并执行`play run`启动项目。在浏览器输入`http://localhost:9000`,如果看到项目启动成功,说明配置完成。若要将项目转换为Eclipse项目,可以使用`play eclipsify`命令...
安装Play框架很简单,从官方下载页面获取最新二进制包并解压。将Play目录添加到PATH环境变量中,这样就可以在命令行直接使用`play`命令。通过运行`play`检查安装是否成功,如果显示帮助信息,说明已安装正确。 创建...
矢部 另一个博客引擎(Play Framework 1.3.x)
同时,这两个工具也适用于实际项目中的设备调试和系统集成工作。安装文件"SetupYabe_v1.2.2.exe"是Yabe的安装程序,而"VTS_3.6.7.zip"则是VTS的压缩包,解压后即可运行。 总的来说,熟悉并掌握Yabe和VTS的使用,...
yabe:另一个后端库
User类应该位于`/yabe/app/models/User.java`,并使用`@Entity`注解来声明这是一个JPA实体。`@Entity`告诉JPA框架这个类应该被当作数据库表来处理。此外,User类扩展了`play.db.jpa.Model`类,这个类提供了一些辅助...
用C#编写的图形化资源管理器程序,用于浏览BACnet设备(在Windows和Linux上运行)。 当前同时支持BACnet IPv4,IPv6 + BACnet MSTP + BACnet PTP + BACnet以太网。 用于读取,写入,读取多个,写入多个,iam,whois...
"yabe_sql" 可能是一个开源项目或工具的名字,而 "剧本1.3.x教程" 指的是该项目或工具的1.3.x版本的相关教学材料。"紧随其后" 暗示这是一个系列教程中的一个后续部分,可能是对之前版本的更新或者扩展。 【描述分析...
软件平台:stm32cubemx keil5 使用hal库生成基础代码,然后添BACnet mtsp部分,已经成功和电脑BACnet模拟软件Yabe通讯成功。 硬件平台:基于正点原子stm32f407探索者开发板硬件。
"矢部网上商城"是一个基于GitHub Pages部署的在线商城项目,其源代码托管在"yabe-online-mall.github.io"的仓库中。这个项目主要利用HTML(HyperText Markup Language)来构建网页结构,展示了如何使用基本的Web技术...
一些常用的BACnet点位扫描工具包括Yabe,BACnetscan 等。 BACnet主站模拟工具:主站模拟工具用于模拟BACnet主站的功能,以便测试和验证设备的响应和行为。它们允许开发人员发送和接收BACnet命令和数据,并模拟不同的...
通过理解和研究这个源码,开发者可以更好地了解如何在实际项目中实现BACnet设备之间的通信,提高楼宇自动化的互操作性和效率。然而,由于BACnet协议的复杂性,初学者可能需要花费一定时间来熟悉其细节。希望这个源码...
Currently supports both BACnet IPv4, IPv6 + BACnet MSTP + BACnet PTP + BACnet Ethernet. Basic functions for read, write, read multiple, write multiple, iam, whois, subscribeCOV, notify, WriteFile, ...
"yetanotherbacnetexplorer-code-282-trunk"可能表示的是YABE项目的某个版本或分支。"code-282"可能是一个版本号,而"trunk"通常指的是主分支,意味着这是项目的主线开发代码。解压这个文件后,开发者将能看到源代码...
语言:English 更好的书签弹出窗口 功能:1.左键单击可在新选项卡中打开书签。 2.单击鼠标中键或Ctrl键并单击以在新的背景选项卡中打开书签。 3.通过打开另一个文件夹来关闭所有打开的文件夹。...