JFinal 是基於 Java 語言的極速 WEB + ORM 框架,其核心設計目標是開發迅速、代碼量少、學習簡單、功能強大、輕量級、易擴展、Restful。在擁有Java語言全部優點的同時再擁有ruby、python、php等動態語言的開發效率!爲您節約更多時間,去陪戀人、家人和朋友 :)php
JFinal 官方網站:http://www.jfinal.comhtml
JFinal有以下主要特色:java
MVC架構,設計精巧,使用簡單python
遵循COC原則,零配置,無xmlweb
首創Db + Record模式,靈活便利數據庫
ActiveRecord支持,使數據庫開發極致快速後端
自動加載修改後的java文件,開發過程當中無需重啓web server瀏覽器
AOP支持,攔截器配置靈活,功能強大ruby
Plugin體系結構,擴展性強架構
多視圖支持,支持FreeMarker、JSP、Velocity
強大的Validator後端校驗功能
功能齊全,擁有struts2的絕大部分功能
體積小僅218K,且無第三方依賴
截至筆者撰寫此文時,JFinal已經發布到了1.6版本。
爲了使小白可以徹底的按步驟建立第一個JFinal應用並運行,筆者將以Java界最流行的Eclipse平臺爲例,搭建出全部基礎教程中喜歡的Hello world應用。
搭建Web應用,首選Eclipse JEE版本,請到圖所示的地址下載相應版本。
至於JDK的安裝,這裏就再也不說明了,本文面向的是JFinal小白,而不是李太白^_^。
解壓並運行Eclipse,你將看到下面的畫面:
若是彈出下面的畫面(多在內存小或Windows XP中出現),則須要修改eclipse.ini中的參數:
修改以下參數便可,若是仍是不行,請查詢百度:.
-startup plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar --launcher.library plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20140116-2212 -product org.eclipse.epp.package.jee.product --launcher.defaultAction openFile --launcher.XXMaxPermSize 256M -- 改成192或更小 -showsplash org.eclipse.platform --launcher.XXMaxPermSize 256m -- 優先修改此參數,改成192或更小 --launcher.defaultAction openFile --launcher.appendVmargs -vmargs -Dosgi.requiredJavaVersion=1.6 -Xms40m -Xmx512m |
雖然JFinal自帶的Demo運行在Jetty下,但本文仍是選擇以Tomcat爲Web容器作說明,已經知道如何設置Tomcat的小白可跳過此節。
運行Tomcat,打開菜單Windows-->Perferences,在彈出的窗口中按下圖選擇:
選擇習慣使用的Tomcat V6:
不必追求最新版本,在線安裝Eclipse推薦的Tomcat 6.0.37版本便可:
彈出License說明,直接點Finish便可:
下載完成後會讓你指定Tomcat存放的文件夾:
再次回到設置頁面,點Finish:
至此,Tomcat搭建完成:
在建立工程以前,先打開菜單Windows-->Perferences,在彈出的窗口中修改默認字符集:
在Eclipse的工具欄上可直接建立Dynamic Web工程:
彈出新建窗口,輸入新工程名MyJFinalApp,直接點Finish:
至此,Dynamic Web工程建立完成:
在工程的屬性中能夠看到,Web應用相關的Library已經默認包含:
既然基於JFinal框架,沒有理由不下載JFinal相關Jar包。打開JFinal官方網站http://www.jfinal.com/,下載相關內容:
下載jfinal-1.6-bin-with-src.jar是爲了使小白在使用中可方便地查看並分析源碼,下載jfinal-1.6_demo_for_jsp.zip是由於有部分必要的Jar包在Demo中能夠找到,並且,第一個Demo將採用JSP頁面。
將下載好的jfinal-1.6-bin-with-src.jar直接Copy到工程的下圖位置:
這一章節比較重要,介紹如何配置及編碼,完成第一個JFinal應用。
首先建立MyJFinal的配置類MyAppConfig.java:
在方法中添加以下代碼:
@Override public void configConstant(Constants me) { me.setDevMode(true); me.setEncoding("utf-8"); me.setViewType(ViewType.JSP); }
@Override public void configHandler(Handlers me) { me.add(new ContextPathHandler("basePath")); } |
既然MyAppConfig.java是入口,那麼,在Tomcat這個容器中,就須要配置這個入口,使得Tomcat啓動的同時加載這個入口類。
打開web.xml,追加內容:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>MyJFinalApp</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list>
<filter> <filter-name>jfinal</filter-name> <filter-class>com.jfinal.core.JFinalFilter</filter-class> <init-param> <param-name>configClass</param-name> <param-value>cn.myapp.config.MyAppConfig</param-value> </init-param> </filter>
<filter-mapping> <filter-name>jfinal</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> |
在建立JSP頁面以前先修改一下JSP文件的默認字符集。以下圖所示,打開菜單Windows-->Perferences,在彈出的窗口中修改默認字符集爲utf-8便可:
經過右建,在WebContent中new一個新的jsp文件:
文件名爲index.jsp,並放入WebContent中:
完成後可看到首先要打開的index.jsp已經有默認內容了,而且字符集爲utf-8:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body>
</body> </html> |
並在JSP文件的<body>標籤中追加以下代碼:
<body> <form action="${basePath}/sayHello" method="post"> 請輸入您的名字: <input type="text" name="userName" /> <input type="submit" value="肯定"/> </form> </body> |
一樣的步驟,再建立一個hello.jsp,並在<body>標籤中追加以下代碼:
<body> <p>${sayHello}</p><p><a href="${basePath}/"></a></p> </body> |
建立IndexController.java用於響應頁面請求,以下圖:
並添加代碼:
public class IndexController extends Controller {
public void index(){ this.render("/index.jsp"); } public void sayHello(){ String userName = this.getAttr("userName"); String sayHello = "Hello " + userName + ",welcome to JFinal world."; this.setAttr("sayHello", sayHello); this.render("/hello.jsp"); } } |
JSP頁面和Controller都準備完成後,就須要在MyAppConfig.java中將二者關聯起來,JFinal裏稱之爲Route(路由),下面是MyAppConfig類中追加的路由代碼:
@Override public void configRoute(Routes me) { me.add("/", IndexController.class); } |
上面全部工做完成後,則須要將App發佈到Tomcat。在Eclipse IDE的底部,找到Servers,並點擊下圖中標記的區域建立Tomcat實例(前面的Tomcat配置只是配置Eclipse中的Tomcat插件,這裏須要創建Tomcat實例。實例可配置多個,但端口不能衝突):
在彈出的對話框中作以下配置:
將MyJFinalApp加入到新建的Tomcat實例後點Finish:
選擇新建的Tomcat實例,並以Debug方式啓動:
啓動正常的話,可在控制檯下看到啓動信息:
打開瀏覽器,並輸入URL:http://localhost:8080/MyJFinalApp/,應該可看到以下畫面:
小白們,感動吧,終於將JFinal環境搭建起來了。
在輸入框中輸入「小白」,點擊肯定,出現下面的畫面:
很明顯,頁面中出現了錯誤,紅框中標識的內容是null,而不是期待的「小白」。
再看看控制檯的輸出:
在頁面中輸入的字串正確地傳給了後臺IndexController.sayHello()方法,那麼,爲何沒有顯示出來呢?請小白在IndexController.sayHello()中追加斷點:
而後再次打開URL:http://localhost:8080/MyJFinalApp/,在輸入框中輸入「小白」,點擊肯定。這時,Eclipse進入調試模式。經過調試查看userName取得的值爲null:
仔細分析發生錯誤的這行代碼,或直接查看此方法的源碼,原來,getArrt("userName")方法取到的是HttpServletRequest中的屬性,而不是請求參數。應該改爲從取參數的getPara("userName")方法:
public void sayHello(){ String userName = this.getPara("userName"); 。。。。。。 |
又一次打開UR:http://localhost:8080/MyJFinalApp/,在輸入框中輸入「小白」,點擊肯定,終於出現了使人期待的結果:
實際上,除去Eclipse和Tomcat的準備之外,配置及編碼那塊在熟練的人手裏只須要10分鐘左右,當之無愧的極速WEB開發。固然,前面只是使用到了JFinal的WEB框架,ORM框架在後面的教程中會介紹到。
這一章節,將粗略地講解一下JFinal的WEB部分是如何搭載在Tomcat容器中,啓動並響應用戶操做的過程。
另外,推薦小白們看完此章節後研究下張劍峯同窗寫的《JFinal技術架構淺析》一文。
前面,小白們建立MyAppConfig.java,同時修改web.xml。這就爲啓動JFinal作好了準備,下面咱們就來分析下Tomcat啓動的同時是怎麼初始化MyJFinalApp的。
先來看web.xml:
<filter> <filter-name>jfinal</filter-name> <filter-class>com.jfinal.core.JFinalFilter</filter-class> <init-param> <param-name>configClass</param-name> <param-value>cn.myapp.config.MyAppConfig</param-value> </init-param> </filter>
<filter-mapping> <filter-name>jfinal</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
xml中首先聲明瞭<filter>,它是JFinalFilter,同時定義了<init-param>,指向應用程序的配置類MyAppConfig.java。
在<filter-mapping>中,定義了<url-pattern>爲「/*」,也就是說,此Web應用全部的URL都將將由JFinalFilter這個過濾器來處理。
Tomcat啓動過程:
過程當中,對於JFinal開發人員來講,最有用操做就是「調用MyAppConfig各方法」,也就是執行了以下代碼:
@Override public void configConstant(Constants me) { me.setDevMode(true); me.setEncoding("utf-8"); me.setViewType(ViewType.JSP); }
@Override public void configHandler(Handlers me) { me.add(new ContextPathHandler("basePath")); }
@Override public void configRoute(Routes me) { me.add("/", IndexController.class); } |
各方法的做用請參考《JFinal-手冊-1.5.pdf》,此處再也不復述手冊可從官網http://www.jfinal.com/下載。
應用中,建立了兩個JSP頁面,分別是「index.jsp」和「hello.jsp」,在瀏覽器中訪問http://localhost:8080/MyJFinalApp/時明顯打開了index.jsp頁面。經歷過SSH或SpringMVC的小白應該會很奇怪,明明沒有像SpringMVC那樣用註解聲明Controller,也沒有在註解方法對應的URL,而JFinal卻正確地打開了index.jsp。
首先請看MyAppConfig.configRoute()方法中的URL路由代碼:
me.add("/", IndexController.class); |
這句代碼實際上已經配置了URL與Controller之間的對應關係,第一個參數"/"就是指的根。當用戶訪問根URL時,依據約定JFinal會將其路由到IndexController.index()方法。
那麼,在訪問http://localhost:8080/MyJFinalApp/時,JFinal如何知道訪問的是"/"(根)呢?
首先請小白雙擊Tomcat配置項:
在彈出的Tomcat實例屬性窗口中找到Ports選項:
這裏說明Tomcat實例使用的是8080端口,也就是經過http://localhost:8080可訪問此Tomcat。
而後請小白打開部署的Tomcat實例的server.xml:
在server.xml底部,咱們能夠發現MyJFinalApp的配置:
<Context docBase="MyJFinalApp" path="/MyJFinalApp" reloadable="true" source="org.eclipse.jst.jee.server:MyJFinalApp"/> |
請看path參數,它的值爲"/MyJFinalApp"(必定要和前面Context root配置同樣),說明此應用部署到Tomcat的後使用的根URL爲「http://localhost:8080」+ 「/MyJFinalApp」 = 「http://localhost:8080/MyJFinalApp」。
提示:修改reloadable的值爲false,在調試狀態,修改MyJFinalApp的代碼時Tomcat不會頻繁從新加載應用,節省開發調試時間。
經過上面,咱們已經知道,經過訪問http://localhost:8080/MyJFinalApp/,JFinal會將其路由到IndexController.index()方法,爲何是index()方法?其實這是一個約定,具體的約定請參考《JFinal-手冊-1.5.pdf》。
那麼它是如何打開index.jsp文件的呢?咱們來查看index()方法的代碼:
public class IndexController extends Controller { public void index(){ this.render("/index.jsp"); } 。。。。。。 |
只有一句代碼,做用是渲染\WebContent\index.jsp這個文件後返回給瀏覽器。小白們又糊塗了,爲何不return一個字串來指定渲染頁面呀?這裏就是JFinal設計者的聰明之處了,渲染頁面可能不止常見的JSP、FREE_MARKER、VELOCITY等幾種類型,隨着技術的發展,模板頁面類型會層出不窮。JFinal中,只須要擴展Render就可輕鬆支持,贊呀^_^。
打開index.jsp後,用戶在頁面中輸入名字,而後點擊肯定,這裏調用的是以下action代碼:
<form action="${basePath}/sayHello" method="post"> 請輸入您的名字: <input type="text" name="userName" /> <input type="submit" value="肯定"/> </form> |
action的值爲"${basePath}/sayHello",那麼${basePath}是什麼東東呢?有點JSP基礎的人都知道,basePath必須設置到HttpServletRequest中才能在頁面中使用。那麼又是何時設置進去的呢?請注意前面建立MyAppConfig.java中的一段代碼:
@Override public void configHandler(Handlers me) { me.add(new ContextPathHandler("basePath")); } |
在這裏配置了一個ContextPathHandler,構造參數是"basePath",難道它們有聯繫!沒錯,小白們可直接查看此Handler的源碼就能夠發現,一行代碼已經作必須的事情:
public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { request.setAttribute(contextPathName, request.getContextPath()); nextHandler.handle(target, request, response, isHandled); } |
ContextPathHandler就只作了這麼一件事情,就是在每次(注意是每次)請求時將Context Path(此應用中的值爲"/MyJFinalApp")設置到HttpServletRequest的屬性"basePath"中,這樣,頁面就可使用了。
爲了證明這一點,可在瀏覽器中打開index.jsp返回的html源碼:
此頁面中,點擊肯定,就將用戶輸入的」userName」,經過Post方式調用http://localhost:8080/MyJFinalApp/sayHello地址。最終,調用的是IndexController.sayHello()方法。
JFinal是怎麼知道調用的是此方法呢?其實很簡單,在JFinal的路由規則中,首先會去匹配地址」/sayHello」。顯然是找不到的,由於在MyAppConfig.configRoute()方法中根本就沒有配置與」/sayHello」對應的Controller。因此JFinal會截掉最後一個」/」後的內容再次匹配,」/sayHello」截取掉後就成了」/」,也就匹配到了IndexController。根據約定,被截取的內容」sayHello」應該是方法名,因此,也順序定位到了IndexController.sayHello()方法。
小白們,明白了吧,JFianl的路由約定拋棄掉了繁瑣的註解,這就是一種簡潔美。這種設計在JFianl中到處都存在,隨着對JFinal瞭解的加深,你們會慢慢體會到約定大於配置不僅僅是一句口號。
有部分人也提出了質疑:註解能規範編碼,一目瞭然……等等。但若是回過頭來想,註解實際上也就是一種顯示的約定而已,而JFianl將其當成了隱式約定。使用註解功能更強了點嗎?答案是沒有,SSH和SpringMVC的這類註解與JFinal的實際提供的路由在功能上沒有任何區別,沒有脫離Servlet的範疇。
提供源碼:小白的第一個JFinal程序.zip