JFinal是國產的MVC框架,由 Handler、Interceptor、Controller、Render、Plugin 五大部分組成。本文經過一個例子上手JFinal,旨在熟悉JFinal中各組件的用法。html
用戶登陸:IP/user/login
用戶註冊:IP/user/register
用戶上傳圖片:IP/user/image
登陸後能訪問: IP/user/showmysql
JFinal須要一個繼承 JFinalConfig
的子類,咱們這裏取名叫AppConfig,這個類的名字是隨便取的,我這裏取AppConfig。web
import com.jfinal.config.*; import com.jfinal.plugin.activerecord.ActiveRecordPlugin; import com.jfinal.plugin.druid.DruidPlugin; import com.jfinal.render.ViewType; import controller.IndexController; import controller.UserController; import model.User; /** * Created by reeco_000 on 2015/7/22. */ public class AppConfig extends JFinalConfig{ @Override public void configConstant(Constants constants) { constants.setEncoding("UTF-8"); constants.setDevMode(true); constants.setViewType(ViewType.JSP); } @Override public void configRoute(Routes routes) { routes.add("/", IndexController.class); routes.add("/user", UserController.class); } @Override public void configPlugin(Plugins plugins) { //這裏啓用Jfinal插件 PropKit.use("jdbc.properties"); final String URL =PropKit.get("jdbcUrl"); final String USERNAME = PropKit.get("user"); final String PASSWORD =PropKit.get("password"); final Integer INITIALSIZE = PropKit.getInt("initialSize"); final Integer MIDIDLE = PropKit.getInt("minIdle"); final Integer MAXACTIVEE = PropKit.getInt("maxActivee"); DruidPlugin druidPlugin = new DruidPlugin(URL,USERNAME,PASSWORD); druidPlugin.set(INITIALSIZE,MIDIDLE,MAXACTIVEE); druidPlugin.setFilters("stat,wall"); plugins.add(druidPlugin); ActiveRecordPlugin activeRecordPlugin = new ActiveRecordPlugin(druidPlugin); activeRecordPlugin.addMapping("user","userid", User.class); plugins.add(activeRecordPlugin); } @Override public void configInterceptor(Interceptors interceptors) { //這裏用於配置全局的攔截器,對全部請求進行攔截 } @Override public void configHandler(Handlers handlers) { } }
在根目錄下新建一個Jdbc.properties,用來保存數據庫鏈接信息。咱們在AppConfig中須要加載它,使用了JFinal的工具類PropKit。sql
driverClass=com.mysql.jdbc.Driver jdbcUrl=jdbc:mysql://localhost:3306/school user=root password=root initialSize=1 minIdle=1 maxActivee=20
這樣就能使用log4j進行日誌統計,在須要記錄的地方獲取logger對象便可數據庫
log4j.rootLogger=INFO, stdout, file log4j.appender.stdout.Target=System.out log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%n%-d{yyyy-MM-dd HH:mm:ss}%n[%p]-[Thread: %t]-[%C.%M()]: %m%n # Output to the File log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=./web.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%n%-d{yyyy-MM-dd HH:mm:ss}%n[%p]-[Thread: %t]-[%C.%M()]: %m%n # Druid log4j.logger.druid.sql=warn,stdout log4j.logger.druid.sql.DataSource=warn,stdout log4j.logger.druid.sql.Connection=warn,stdout log4j.logger.druid.sql.Statement=debug,stdout log4j.logger.druid.sql.ResultSet=warn,stdout
而後在web.xml裏配置JFinal的核心filter和咱們寫好的AppConfigapache
<filter> <filter-name>jfinal</filter-name> <filter-class>com.jfinal.core.JFinalFilter</filter-class> <init-param> <param-name>configClass</param-name> <param-value>AppConfig</param-value> </init-param> </filter> <filter-mapping> <filter-name>jfinal</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
定義用戶實體,代碼很是簡單ruby
package model; import com.jfinal.plugin.activerecord.Model; /** * Created by reeco_000 on 2015/7/22. */ public class User extends Model<User>{ }
繼承Model就好了,無需 getter、setter 方法,無需Annotation,無需xmlsession
這裏數據庫中user設計也很簡單,就三個字段,userid,username,password,貼下sql:app
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `userid` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`userid`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
service層,封裝業務邏輯。這裏用到了ActiveRecord插件,須要在AppConfig中註冊。框架
public void configPlugin(Plugins plugins) { //這裏啓用JFinal插件 DruidPlugin druidPlugin = new DruidPlugin(URL,USERNAME,PASSWORD); druidPlugin.set(INITIALSIZE,MIDIDLE,MAXACTIVEE); druidPlugin.setFilters("stat,wall"); plugins.add(druidPlugin); ActiveRecordPlugin activeRecordPlugin = new ActiveRecordPlugin(druidPlugin); //添加Model類和數據庫表的映射。user指的是表名,userid指的是主鍵 activeRecordPlugin.addMapping("user","userid", User.class); plugins.add(activeRecordPlugin); }
數據庫鏈接池使用的是Druid,JFinal還支持C3P0。
JFinal使用的是Db+Record 完成ORM。Db類提供了大量查詢的方法,這種模式相似於ruby on rails。
package service; import com.jfinal.plugin.activerecord.Db; import com.jfinal.plugin.activerecord.Record; /** * Created by reeco_000 on 2015/7/22. */ public class UserService { public boolean add(String username,String password){ String SQL = "SELECT userid FROM user WHERE username =?"; Integer result = Db.queryFirst(SQL, username); if(result==null){ Record user = new Record().set("username", username).set("password", password); Db.save("user", user); return true; } return false; } public boolean login(String username,String password){ String SQL = "SELECT userid FROM user WHERE username =? and password=?"; Integer result = Db.queryFirst(SQL, username, password); if(result!=null) return true; else return false; } }
JFinal裏的攔截器有三個做用域,全局,類和方法。利用JFinal的AOP,使用起來也很是方便。攔截器定義也很是簡單,只需繼承Interceptor接口重寫intercept方法。全局的攔截器是在AppConfig裏配置:
public void configInterceptor(Interceptors interceptors) { //這裏用於配置全局的攔截器,對全部請求進行攔截 // 添加控制層全局攔截器 interceptors.addGlobalActionInterceptor(new GlobalActionInterceptor()); // 添加業務層全局攔截器 interceptors.addGlobalServiceInterceptor(new GlobalServiceInterceptor()); }
類和方法使用@Before(Class.class)即能使用,具體能夠看下面Controller的例子。在JFinal2還提供了Inject攔截器,不過咱們的例子裏沒這需求,因此沒用到,具體各位仍是看官網文檔吧。
簡易的權限攔截器,這裏的做用是隻有登陸的才能執行。在session裏設置了一個變量flag,當是true時就執行。
package interceptor; import com.jfinal.aop.Interceptor; import com.jfinal.aop.Invocation; import com.jfinal.core.Controller; /** * Created by reeco_000 on 2015/7/22. */ public class AuthInterceptor implements Interceptor { @Override public void intercept(Invocation invocation) { Controller controller = invocation.getController(); Boolean loginUser = controller.getSessionAttr("flag"); if (loginUser ==true ) invocation.invoke(); else controller.redirect("/"); } }
Validator是JFinal提供的校驗組件。其核心是Interceptor,因此用法和Interceptor相似,繼承Validator類便可。
validate
提供了一系列的validateXXX方法
handleError
處理錯誤,常見的用法是
controller.keepPara(); controller.render("register.html");
意思是返回原頁面,保持傳入的參數。
package validator; import com.jfinal.core.Controller; import com.jfinal.validate.Validator; /** * Created by reeco_000 on 2015/7/22. */ public class LoginValidator extends Validator { @Override protected void validate(Controller c) { validateRequiredString("username","nameError","username is null"); validateRequiredString("password","passError","username is null"); } @Override protected void handleError(Controller c) { } }
JFinal的Controller須要繼承Controller類,類的映射是在AppConfig中配置:
public void configRoute(Routes routes) { routes.add("/", IndexController.class); routes.add("/user", UserController.class); }
咱們這裏配置意思是/訪問到IndexController這個類,/user 訪問到UserController。/user/login 默認訪問UserController.login()方法,這點相似於struct2,若是以前有基礎,上手會很是快。
映射 /user,在login()上使用了校驗攔截器LoginValidator,show()使用了權限攔截器AuthInterceptor。
package controller; import com.jfinal.aop.Before; import com.jfinal.core.Controller; import interceptor.AuthInterceptor; import service.UserService; import validator.LoginValidator; /** * Created by reeco_000 on 2015/7/22. */ public class UserController extends Controller{ private UserService userService = new UserService(); public void index(){} @Before(LoginValidator.class) public void login(){ String username = getPara("username"); String password = getPara("password"); boolean loginCheck = userService.login(username,password); if(loginCheck){ renderJson("10000"); getSession().setAttribute("flag",true); } else renderJson("10001"); } public void register(){ String username = getPara("username"); String password = getPara("password"); boolean result = userService.add(username,password); if(result) renderJson("10010"); else renderJson("10011"); } @Before(AuthInterceptor.class) public void show(){ renderJsp("user.jsp"); } public void image(){ try{ getFile(getPara("img"),"UTF-8"); renderJson("20010"); } catch (Exception e){ renderJson("20012"); } } }
package controller; import com.jfinal.core.Controller; /** * Created by reeco_000 on 2015/7/22. */ public class IndexController extends Controller{ public void index(){ renderJsp("index.jsp"); } }
index是Controller默認調用的方法
最後整個工程的文件如上圖所示,代碼很是簡單,我也就不上傳獻醜了。主要介紹了JFinal的Interceptor、Controller、Render、Plugin,Handler是對Controller和Interceptor的補充。ORM使用的是Db+ActiveRecord。JFinal還有不少組件沒有提到,各位請到官網查看詳細文檔。