快速上手JFinal

JFinal是國產的MVC框架,由 Handler、Interceptor、Controller、Render、Plugin 五大部分組成。本文經過一個例子上手JFinal,旨在熟悉JFinal中各組件的用法。html

目標

  • 用戶登陸/註冊
  • 用戶上傳圖片
  • 登陸權限驗證

訪問路徑

用戶登陸:IP/user/login
用戶註冊:IP/user/register
用戶上傳圖片:IP/user/image
登陸後能訪問: IP/user/showmysql

依賴

  • druid-1.0.5.jar
  • cos-26Dec2008.jar
  • jfinal-2.0-bin.jar
  • log4j-1.2.16.jar

AppConfig

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

在根目錄下新建一個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.properties

這樣就能使用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

而後在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>

Model

定義用戶實體,代碼很是簡單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

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;
    }
}

Interceptor

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攔截器,不過咱們的例子裏沒這需求,因此沒用到,具體各位仍是看官網文檔吧。

AuthInterceptor

簡易的權限攔截器,這裏的做用是隻有登陸的才能執行。在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("/");
    }
}

LoginValidator

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) {

    }
}

Controller

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,若是以前有基礎,上手會很是快。

UserController

映射 /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");
        }
    }
}
  • getPara() 從請求中獲取參數
  • getFile() 支持文件上傳
  • renderJson() 返回JSON,JFinal提供了一系列的render方法,目前支持的視圖類型有:
    FreeMarker、JSP、Velocity、JSON、File、Text、Html 等等。

IndexController

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還有不少組件沒有提到,各位請到官網查看詳細文檔。

相關文章
相關標籤/搜索