1. 程式人生 > >JFinal+amazeUI+beetl+layer+shiro+poi+restful+handlebars初認識

JFinal+amazeUI+beetl+layer+shiro+poi+restful+handlebars初認識

剛入職公司,其用的框架為JFinal+amazeUI+beetl+layer+shiro+poi+restful+handlebars。這些一個都不熟悉,沒辦法,只能硬著頭皮上。

經過一週的琢磨,初步搞明白了這些框架的使用場景和基本用法。

JFinal的橫空出世,印證了那一句話:軟體分為兩種,一種設計簡單,明顯沒有Bug;一種設計複雜,沒有明顯Bug。JFinal是一個輕量級的MVC、ORM、AOP框架,作為後端開發的微核心全方位擴充套件的新一代框架,其易用性和開發效率都是難以比肩的,其外掛體系和Db+activeRecord架構也非常好。它主要由JFinalFilter、JFinalConfig、Handler、Interceptor、Controller、Render、Plugin等部分構成。每個部分都是基於介面實現的,支援完整的自定義,使用靈活,擴充套件性強。

其基本執行原理:

從一次新增頁面的add操作請求來看:

1. 首先是客戶端點選新增按鈕,提交一個新增請求,請求中會帶上服務端處理地址url

2. 所有請求都會被JFinalFilter攔截,然後呼叫Handler進行詳細處理

3. Handler是一個鏈條形式的呼叫,包括0-n個自定義Handler,以及最後一個ActionHandler,依次執行,當然可以自定義跳出。

4. 進入ActionHandler後,首先會根據請求的target從快取的ActionMapping中對映獲取到具體操作對應的Action物件,這個物件裡面封裝了方法名、方法上面的攔截器,方法所在的Controller

controller上面的攔截器等。然後根據Action以及Controller例項構造出ActionInvocation。

5. 接下來通過ActionInvocation的invoke進行具體處理,這是一個明顯的Command模式的實現。首先是攔截器的呼叫,攔截器呼叫中會重新回撥ActionInvocation的invoke,當攔截器呼叫完畢後,會呼叫當前操作的method

6. 當進入具體controller的新增方法add時,呼叫基類的getModel(Systemparam.class);這個方法會從request中解析出所需要的資料,通過反射設定給具體的Model實體類,最終通過ActiveRecord

來進行資料儲存

7. 最後是頁面渲染rerender

Controller的主要作用是從Request中獲取引數,往Request和Session中放入屬性、Cookie,使用ModelInjector的inject方法從Request中獲取model{網頁中的格式為user.name,user.age},該方法有兩個分支,如果model繼承於Model則呼叫set(attrName,attrValue),否則就是普通的JavaBean,呼叫setAttrName(attr)。

Controller呼叫cos框架獲取上傳的檔案,封裝成MultiPartRequest(繼承於HttpServletRequestWrapper),該類可以獲取檔案或者引數。

Handler是處理器,構成責任鏈,因為在handle方法中獲取到了Request和Response,所以它具備對請求的完全控制權。在JFinalFilter的init方法中,構建了這個鏈條,最後一個handler是ActionHandler,並獲取到第一個handler,其配置由JFinalConfig的configHandler完成。

Action就代表Controller中的一個方法,包括Controller這個Class,controllerKey,actionKey,Method,methodName,interceptors,viewPath,是一個簡單的只讀JavaBean。

ActionHandler中的handle方法中呼叫controller的init方法,通過Invocation呼叫controller之中的Interceptor,然後呼叫controller的getRender獲取Render,之後判斷是不是ActionRender,避免呼叫相同的controller的相同方法造成死迴圈。因為在一般的controller的方法中都會呼叫controller中的render()方法系列,將controller中的render引用為某render,故在ActionHandler的handler方法最後呼叫render.render()就會呼叫不同render的render方法。在配置Constans的時候調動setMainRenderFactory,就能設定程式的主Render工廠,以後獲取的就是這個工廠生產的Render,這就是典型的工廠方法模式。

Render代表渲染器,擁有request和response的引用,所以render()方法中就能作不同的處理,例如FileRender就會呼叫response的setHeader(“Content-disposition”,“attachment;filename=...”)等以實現檔案下載;BeetlRender就會呼叫載入模板和繫結屬性哪些方法(見以下分析)。

關於自動掃描classpath和jar包中的AutoBindRoutes的機制:

首先JFinalConfig中的configRoute(Routes me)方法中呼叫me.add(new AutoBindRoutes());其原始碼為

public Routes add(Routes routes) {
if (routes != null) {
routes.config();// very important!!!
map.putAll(routes.map);
viewPathMap.putAll(routes.viewPathMap);
}
return this;
}

使得Routes的map和viewPathMap中添加了AutoBindRoutes的map和viewPathMap,這個方法中,呼叫了routes.config方法,這個方法就要求你自己配置你的map和viewPathMap,這個是典型的模板方法模式。AutoBindRoutes繼承於Routes,其config方法中,

public void config()
 {
     List controllerClasses = ClassSearcher.of(Controller.class).includeAllJarsInLib(this.includeAllJarsInLib).injars(this.includeJars).search();
     ControllerBind
controllerBind = null;
     for (Class controller : controllerClasses)
       if (!this.excludeClasses.contains(controller))
      {
        controllerBind = (ControllerBind)controller.getAnnotation(ControllerBind.class);
        if (controllerBind == null) {
          if (this.autoScan)
         {
            add(controllerKey(controller), controller);
          } } else if (StrKit.isBlank(controllerBind.viewPath())) {
           add(controllerBind.controllerKey(), controller);
         } else {
           add(controllerBind.controllerKey(), controller, controllerBind.viewPath());
        }
      }
 }

首先委託ClassSearcher去ClassPath和Jar包中去掃描Controller的子類(要求以Controller結尾,是COC原則),然後檢查該類上是否含有ControllerBind(強制修改路徑的)註解,有的話就按照ControllerBind的路徑執行,否則按照預設的規則執行。ClassSearcher.search方法就自己想吧,程式碼不是很複雜。

至此,AutoBindRoutes中含有了Controller的資訊,在JFinalFilter的init方法中

if (jfinal.init(jfinalConfig, filterConfig.getServletContext()) == false)
throw new RuntimeException("JFinal init error!");

init方法裡面

boolean init(JFinalConfig jfinalConfig, ServletContext servletContext) {
this.servletContext = servletContext;
this.contextPath = servletContext.getContextPath();

initPathUtil();

Config.configJFinal(jfinalConfig);// start plugin and init logger factory in this method
constants = Config.getConstants();

initActionMapping();
initHandler();
initRender();
initOreillyCos();
initTokenManager();

return true;
}

configJFinal方法中

static void configJFinal(JFinalConfig jfinalConfig) {
jfinalConfig.configConstant(constants);initLoggerFactory();
jfinalConfig.configRoute(routes);
jfinalConfig.configPlugin(plugins);startPlugins();// very important!!!
jfinalConfig.configInterceptor(interceptors);
jfinalConfig.configHandler(handlers);
}

這個方法中呼叫JFinalConfig的configRoutes就會呼叫前面說的那些方法。此時Config類中就保留了Routes資訊。

initActionMapping方法中

private void initActionMapping() {
actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());
actionMapping.buildActionMapping();
}

就用Config的getRoutes獲取Routes構造出actionMapping,然後呼叫buildActionMapping

void buildActionMapping() {
mapping.clear();
Set<String> excludedMethodName = buildExcludedMethodName();
ActionInterceptorBuilder interceptorBuilder = new ActionInterceptorBuilder();
Interceptor[] globalInters = interceptors.getGlobalActionInterceptor();
interceptorBuilder.addToInterceptorsMap(globalInters);
for (Entry<String, Class<? extends Controller>> entry : routes.getEntrySet()) {
Class<? extends Controller> controllerClass = entry.getValue();
Interceptor[] controllerInters = interceptorBuilder.buildControllerInterceptors(controllerClass);

boolean sonOfController = (controllerClass.getSuperclass() == Controller.class);
Method[] methods = (sonOfController ? controllerClass.getDeclaredMethods() : controllerClass.getMethods());
for (Method method : methods) {
String methodName = method.getName();
if (excludedMethodName.contains(methodName) || method.getParameterTypes().length != 0)
continue ;
if (sonOfController && !Modifier.isPublic(method.getModifiers()))
continue ;

Interceptor[] methodInters = interceptorBuilder.buildMethodInterceptors(method);
Interceptor[] actionInters = interceptorBuilder.buildActionInterceptors(globalInters, controllerInters, methodInters, method);
String controllerKey = entry.getKey();

ActionKey ak = method.getAnnotation(ActionKey.class);
String actionKey;
if (ak != null) {
actionKey = ak.value().trim();
if ("".equals(actionKey))
throw new IllegalArgumentException(controllerClass.getName() + "." + methodName + "(): The argument of ActionKey can not be blank.");

if (!actionKey.startsWith(SLASH))
actionKey = SLASH + actionKey;
}
else if (methodName.equals("index")) {
actionKey = controllerKey;
}
else {
actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
}

Action action = new Action(controllerKey, actionKey, controllerClass, method, methodName, actionInters, routes.getViewPath(controllerKey));
if (mapping.put(actionKey, action) != null)
throw new RuntimeException(buildMsg(actionKey, controllerClass, method));
}
}

// support url = controllerKey + urlParas with "/" of controllerKey
Action actoin = mapping.get("/");
if (actoin != null)
mapping.put("", actoin);
}

這裡面就涉及Before、Clear、ActionKey的執行邏輯(略)。

AmazeUI是一個前端框架,主要提供一些元件和佈局。

beetl是新一代Java模板引擎,在後端執行,通過ResoureLoader和Configeration獲取模板,編譯後通過繫結資料渲染出需要的頁面。與JFinal的整合就是通過註冊一個BeetlRenderFactory(me.setMainRenderFactory(new BeetlRenderFactory());),如此在渲染的時候就生成BeetlRender進行渲染,當然也會執行beetl的一些步驟。通過看原始碼知道,BeetlRenderFactory.getRender方法返回一個BeetlRender,他繼承於Render,在render方法中

this.response.setContentType(contentType);
WebRender webRender = new WebRender(this.gt);
webRender.render(this.view, this.request, this.response, new Object[0]);

這個render方法中

Enumeration attrs = request.getAttributeNames();
while (attrs.hasMoreElements())
 {
String attrName = (String)attrs.nextElement();
template.binding(attrName, request.getAttribute(attrName));
}

WebVariable webVariable = new WebVariable();
webVariable.setRequest(request);
webVariable.setResponse(response);
template.binding("session", new SessionWrapper(request.getSession(false)));

template.binding("servlet", webVariable);
template.binding("request", request);
template.binding("ctxPath", request.getContextPath());

這就是在頁面中能夠使用request中的資料的奧祕。

layer是一個效果很好的彈出層。

shiro是一個可以認證、授權、加密、會話管理、與Web整合、快取的Java安全框架。目前還沒研究透徹。

poi用於生成Excel表格。

restful主要是控制程式碼風格的。

handlebars是一個網頁前端js的模板技術,在瀏覽器view source的時候還能看見其特有的語法{{}},說明是在瀏覽器中執行的。基本的使用步驟是

1:用script標籤放入模板程式碼:

<script id="entry-template" type="text/x-handlebars-template">
  template content
</script>
2:編譯模板
var source   = $("#entry-template").html();
var template = Handlebars.compile(source);

3:引入資料,當然這個資料的來源就不定了,可以是本地的,也可以是伺服器來的

var context = {title: "My New Post", body: "This is my first post!"}
var html    = template(context);

得到下面的HTML

<div class="entry">
  <h1>My New Post</h1>
  <div class="body">
    This is my first post!
  </div>
</div>
還可以通過註冊函式實現自己的邏輯
Handlebars.registerHelper('list', function(items, options) {
  var out = "<ul>";

  for(var i=0, l=items.length; i<l; i++) {
    out = out + "<li>" + options.fn(items[i]) + "</li>";
  }

  return out + "</ul>";
});
{{#list people}}{{firstName}} {{lastName}}{{/list}}

使用一下資料

{
  people: [
    {firstName: "Yehuda", lastName: "Katz"},
    {firstName: "Carl", lastName: "Lerche"},
    {firstName: "Alan", lastName: "Johnson"}
  ]
}

就能渲染出以下效果

<ul>
  <li>Yehuda Katz</li>
  <li>Carl Lerche</li>
  <li>Alan Johnson</li>
</ul>

以上是對這些框架的一個初步認識,隨著時間的推移和我的堅持,應該能啃下他們。

相關推薦

JFinal+amazeUI+beetl+layer+shiro+poi+restful+handlebars認識

剛入職公司,其用的框架為JFinal+amazeUI+beetl+layer+shiro+poi+restful+handlebars。這些一個都不熟悉,沒辦法,只能硬著頭皮上。 經過一週的琢磨,初步搞明白了這些框架的使用場景和基本用法。 JFinal的橫空出世,印證了那一

springboot2.0---02、beetl整合shiro

第一步、Maven <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl-framework-starter</artifa

jfinal 配置beetl模板引擎

新建屬性功能檔案“beetl.properties” # To change this license header, choose License Headers in Project Properties. # To change this template file

談談你對restful規範的認識

#首先restful是一種軟體架構風格或者說是一種設計風格,並不是標準,它只是提供了一組設計#原則和約束條件,主要用於客戶端和伺服器互動類的軟體。 #就像設計模式一樣,並不是一定要遵循這些原則,而是基於這個風格設計的軟體可以更簡潔,更#有層次,我們可以根據開發的實際情況,做相應的改變。 #

RESTful 的基本認識

在很早之前接觸 Spring MVC 的時候,都知道 Spring MVC 支援 RESTful 風格API的開發,但對於 RESTful 只是有個模糊的認識,以至於甚至在開發寫出來的介面其實不符合 RESTful 的要求。 定義 REST 的全稱是 R

SSM組合+ springmvc+mybatis+shiro+restful+bootstrap

讀寫 安全 commons 核心 cit 支持 服務 編碼 數據 平臺簡介 Jeesz是一個分布式的框架,提供項目模塊化、服務化、熱插拔的思想,高度封裝安全性的Java EE快速開發平臺。 Jeesz本身集成Dubbo服務管控、Zookeep

分布式框架簡介SSM組合+ springmvc+mybatis+shiro+restful+bootstrap

dubbo+springmvc+mybatis+ehcache+redis J2ee分布式架構 restful kafka shiro 摘要: 核心框架:spring framework 安全框架:Apache Shiro 1.2 視圖框

Spring Cloud + Spring Boot + Mybatis + shiro + RestFul + 微服務 技術分享

trap 企業 緩存 瓶頸 定位 spa comm 功能 中心 1. 介紹 Commonservice-system是一個大型分布式、微服務、面向企業的JavaEE體系快速研發平臺,基於模塊化、服務化、原子化、熱插拔的設計思想,使用成熟領先的無商業限制的主流開源技術構建

企業分布式微服務雲架構技術分享 Spring Cloud + Spring Boot + Mybatis + shiro + RestFul + 微服務

行數 進行 互聯網產品 strong 日誌管理 平臺 bootstra work oot 1. 介紹 Commonservice-system是一個大型分布式、微服務、面向企業的JavaEE體系快速研發平臺,基於模塊化、服務化、原子化、熱插拔的設計思想,使用成熟領先的無

SpringBoot+JWT+Shiro+MybatisPlus實現Restful快速開發後端腳手架

防火 算法 錯誤 模塊 mys 管理員 pro 其他 col 一、背景前後端分離已經成為互聯網項目開發標準,它會為以後的大型分布式架構打下基礎。SpringBoot使編碼配置部署都變得簡單,越來越多的互聯網公司已經選擇SpringBoot作為微服務的入門級微框架。 Myba

jfinal整合shiro樣例

之前看了一篇部落格介紹的jfinal2.0整合shiro的,我仿照那個寫了一個jfinal3.4整合shiro的,簡單整合,樣例 目錄結構圖: jar包目錄: web.xml <?

jfinal 整合shiro的使用

meaven 專案轉化為 web 專案並在 tomcat 釋出過程:http://www.cnblogs.com/zhanggl/p/4733654.html shiro 筆記 1.shiro jar匯入                   <dependency&g

Jfinal配合Shiro進行許可權控制

web專案總免不了使用者的管理與註冊,需求稍微再多一點兒,就涉及使用者的角色及許可權管理了,下面根據自己專案的實際經驗,介紹如何在Jfinal專案中使用Shiro來進行簡單的登陸及許可權管理。 主角簡介 Jfinal 位居開源中國年度熱門開源專案前列,簡單

Jfinalshiro整合實現動態URL鑑權,不裝外掛只需要一個類

Jfinal與Shiro整合,有瑪雅牛和dreamip兩個Jfinal外掛,但還是想以簡單的方式實現動態URL鑑權。 本人的實現思路是,利用Shiro本身的過濾器擴充套件來實現動態通過資料庫URL授權。方法如下: 1. 新建一個JFinal Maven專案 2. pom.x

jfinal+poi匯出excel

廢話不說了,開始了!  方案一:JFinal的renderFile("路徑")功能   先說說我的邏輯:     前臺頁面點選請求傳送到後臺Controller,然後Controller層主要根據所需條件進行表格的組裝,組裝好上傳到伺服器後,然後跳轉到前臺直接顯示下載框,下載即可。 前臺jsp部分: <

JFinal新增Shiro外掛功能,支援Shiro所有註解-使用篇

基於JDK1.6打包好的包括原始碼的Shiro外掛在以下地址: http://git.oschina.net/myaniu/jfinalshiroplugin/blob/master/dist/JFinalShiroPlugin-1.0.jar Shiro共有5個註解,

RESTful API 設計指南

head 簡單 option eat set 取出 tro 其他 first   網絡應用程序,分為前端和後端兩個部分。當前的發展趨勢,就是前端設備層出不窮(手機、平板、桌面電腦、其他專用設備……)。   因此,必須有一種統一的機制,方便不同的前端設備與後端進行通信。這

POI操作Excel詳解,讀取xls和xlsx格式的文件

shee xss split 類型 後綴 .sh lan xls lin package org.ian.webutil; import java.io.File; import java.io.FileInputStream; import java.io.FileN

Yii2 Restful Api 401

原因 數據 app -s style font code ont ram 采用Yii2 Restful Api方式為APP提供數據,默認你已經做好了所有的編碼和配置工作。采用Postman測試接口: 出現這個畫面的一個可能原因是:access_token的寫法有誤,如果你

使用POI操作Excel時new XSSFWorkbook ()報錯java.lang.NoSuchMethodError解決方式

lin line java sts factor 出現 class padding test 使用最新的POI3.11時,在執行 Workbook workBook = new XSSFWorkbook ();這段代碼時出現錯誤: java.lang.NoSu