本文檔用於說明使用jFinal進行項目開發時,應該遵循的規範與慣用法等內容。javascript
雖然咱們指望數據庫可以在設計階段便可凍結,但每每要到開發的後期。這就勢必涉及到數據庫的更新與jFinal模型更新如何同步的問題。推薦作法以下:css
數據庫設計 => 生成sql => 更新數據庫 => 更新模型html
須要說明的是.sql文件也要歸入到版本管理系統中進行管理。前端
jFinal是一個標準的MVC框架,在使用其進行開發時,也應該按照MVC的結構進行組織。java
按照「先分功能,後分模塊」的思路,給出了推薦的一個代碼組織框架:jquery
ProjectRoot +----src | +----package | Config.java | ModelGenerator.java | +----package.models | | +----package.models.base | | +----packages.models.validators | +----package.controllers.moduleName | +----package.controllers.moduleName.admin +----sql +----web | +----templates | | +----include | | +----global | | +----modelName | | +----admin | | +----include | | +----modelName | | admin_base.ftl | | base.ftl | +----static | | +----css | | +----javascript | | +----zui | +----resources | | db.properties | | log4j.properties | | config.properties | +----WEB-INFO | +----classes
雖然jFinal支持的ActiveRecord模式進行開發。可是其對ActiveRecord的模式很是基礎,爲了更好地規範化代碼組織,咱們須要更加細化的要求。web
基本原則:sql
示例:數據庫
public class Column extends Model{ public finial static Column dao = new Column(); public List<Article> getArticleList(){ return Article.dao.findByColumnId(getId()); } } public class Article extends Model{ public final static Article dao = new Article(); public Column getColumn(){ return Column.dao.fineById(getColumnId()); } public List<Article> findByColumnId(int columnId){ .... } }
每一個項目中都包含一個ModelGenerator類,用於根據數據庫的變化更新模型。生成規則請參照上面的代碼組織。bash
特別說明: 數據庫字段名稱,必定要採用駝峯形式。
參閱文獻:《jFianl-2.2-manual.pdf》第0章 快速體驗Model與Bean合體
一個驗證器的例子:
/** * 欄目校驗 * Created by YuanXu on 2016/4/12. */ public class ColumnValidator extends Validator { @Override protected void validate(Controller c) { validateRequired("column.title", "titleError", "請輸入欄目名稱"); validateRequired("column.slug", "slugError", "請輸入Slug"); String slug = c.getPara("column.slug"); Integer id = c.getParaToInt("column.id"); if (slug != null && !slug.isEmpty()) { if (id == null || id == 0) { //new if (Column.dao.find("select id from cms_column where slug=?", slug).size() > 0) { addError("slugError", "Slug不能重複!"); } } else { if (Column.dao.find("select id from cms_column where slug=? and id !=?", slug, id).size() > 0) { addError("slugError", "Slug不能重複!"); } } } } @Override protected void handleError(Controller c) { c.keepModel(Column.class); c.renderFreeMarker("/templates/cms/admin/column_form.ftl"); } }
常規的數據處理控制器應該包含index、create、update、save、delete幾個方法。分別用於列表、建立的空白表單渲染、更新表單渲染、數據保存和刪除動做。
代碼示例
public class UserController extends Controller{ /** * 顯示數據列表 */ public void index(){ int page = getParaToInt("page", 1); Page<Model> page_obj = Article.dao.paginate(page, PAGE_SIZE,.....); setAttr("page_obj",page_obj); setAttr("object_list",page_obj.get_list()); renderFreemarker("/templates/module/model_list.ftl"); } /** * 新建數據 */ public void create(){ Model obj = new Model(); setAttr("object",obj); //TODO:新建模型所需其餘數據 renderFreemarker("/templates/module/model_form.ftl"); } /** * 更新數據 */ public void update(){ Model obj = Model.dao.findById(getParam("id")); if (obj == null){ renderError(404); return; } setAttr("object",obj); //TODO:更新模型所需其餘數據 renderFreemarker("/templates/module/model_form.ftl"); } /** * 保存數據 */ public void save(){ Model obj = getModel(Model.class); if (obj.getID() == null) obj.save(); else obj.update(); redirect(""); #TODO:轉到列表頁 } }
咱們使用freemarker做爲模板層,而且儘可能避免在模板中書寫邏輯代碼。 經過定義一個基類模板,在基模板中定義可被重寫的「片斷」。子模版引入(include)基類模板,而且經過宏的形式重寫/替換基類模板中的佔位符。 爲了方便區分html標記與模板標記,全部模板採用方括號形式。這就要求沒個模板的第一行寫入[#ftl]
這裏給出一個基類模板的了例子:
[#ftl] <html> <head> <title>[#if title??] [@title /][/#if]</title> <link rel="stylesheet" href="/static/zui/css/zui.css"> <script src="/static/zui/lib/jquery/jquery.js"></script> <script src="/static/zui/js/zui.js"></script> [#if head_css??] [@head_css][/@head_css] [/#if] [#if head_js??] [@head_js][/@head_js] [/#if] </head> <body class="[#if body_css??][@body_css][/@body_css] [/#if]"> <div class="container"> [#include '/templates/cms/admin/admin_nav.ftl' ] [#if main??] [@main][/@main] [/#if] </div> [#if body_js??] [@body_js][/@body_js] [/#if] </body> </html>
一樣給出一個子模版的例子。
[#ftl] [#assign active='column' /] [#include "/templates/admin_base.ftl" ] [#macro body_css]column[/#macro]] [#macro title]欄目管理[/#macro] [#macro main] <form action="" class="form form-horizontal" method="get"> <a href="/admin/cms/column/create">新建欄目</a> </form> <table class="table table-bordered table-hovered"> <tr> <th>編號</th> <th>slug</th> <th>標題</th> <th>建立時間</th> <th>更新時間</th> <th>動做</th> </tr> [#if column_list??] [#list column_list as column ] <tr> <td>${column_index+1}</td> <td>${column.slug!}</td> <td>${column.title!}</td> <td>${column.createAt!}</td> <td>${column.updateAt!}</td> <td><a href="/admin/cms/column/update?id=${column.id}" class="btn btn-default btn-sm"><i class="icon-edit">修改</i></a> <a href="javascript:void(0)" data-id="${column.id}" class="btn btn-delete btn-default btn-sm"><i class="icon-remove">刪除</i></a> </td> </tr> [/#list] [/#if] </table> [/#macro] [#macro body_js] <script src="/static/javascript/dibo.admin.article.js"></script> [/#macro]
推薦採用PRG模式進行處理。可參閱http://m.oschina.net/blog/143120 表單處理須要結合驗證器中的錯誤處理組織。通常來講,須要採用以下模式:
... <input type="hidden" name="column.id" value="${column.id!}"> ... <div class="form-group [#if titleError??]has-error[/#if]"> <label for="id_title" class="col-md-3 control-label">標題</label> <div class="col-md-9 "> <input type="text" class="form-control" name="column.title" id="id_title" required maxlength="50" value="${column.title!}"> [#if titleError??] <p class="help-block">${titleError}</p> [/#if] </div> </div> ...
主要目的:根據模型和校驗結果,生成模板。