JFinal開發Demo

nyyb 9年前發布 | 27K 次閱讀 JFinal Web框架

JFinal初識

MVC架構,設計精巧,使用簡單

遵循COC原則,零配置,無xml

獨創Db + Record模式,靈活便利

ActiveRecord支持,使數據庫開發極致快速

自動加載修改后的java文件,開發過程中無需重啟web server

?AOP支持,攔截器配置靈活,功能強大

Plugin體系結構,擴展性強

多視圖支持,支持FreeMarker、JSP、Velocity

強大的Validator后端校驗功能

10 功能齊全,擁有struts2的絕大部分功能

11 體積小僅218K,且無第三方依賴

 

二、Jfinal開發核心

 

1.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>com.demo.jfinal.config.CoreConfig</param-value>

</init-param>

</filter>

 

<filter-mapping>

<filter-name>jfinal</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

2.CoreConfig

 

public class CoreConfig extends JFinalConfig {

 

/** 常量配置 **/

@Override

public void configConstant(Constants me) {

loadPropertyFile("system_config_info.txt");

// 設置開發模式

me.setDevMode(getPropertyToBoolean("devMode"true));

me.setUrlParaSeparator(Const.SYMBOLAMPERSAND);

}

 

/** 處理器配置 接管所有web請求,可在此層做功能性的拓展 **/

@Override

public void configHandler(Handlers me) {

DruidStatViewHandler dvh =  new DruidStatViewHandler("/druid");

me.add(dvh);

}

 

/** 攔截器配置 類似與struts2攔截器,處理action **/

@Override

public void configInterceptor(Interceptors me) {

 

me.add(new TxByMethods("find","update","delete","save")); //聲明式事物管理

}

 

/** 插件配置 JFinal集成了很多插件:redis,druid,quartz... **/

@Override

public void configPlugin(Plugins me) {

 

/** 數據庫監控druid **/

DruidPlugin dp = new DruidPlugin(getProperty("jdbcUrl"),

getProperty("user"), getProperty("password"));

dp.addFilter(new StatFilter()); //sql監控

dp.addFilter(new WallFilter()); //防止sql注入

WallFilter wall = new WallFilter();

wall.setDbType("mysql");  //mysql

dp.addFilter(wall);

me.add(dp);

ActiveRecordPlugin arp = new ActiveRecordPlugin(dp);

me.add(arp);

//表映射關系

arp.addMapping(BlogConst.BLOGTABLE"id", Blog.class);

/** redis緩存支持根據不同模塊使用緩存,目前我創建一個關于blog的緩存塊 **/

RedisPlugin blogRedis = new RedisPlugin(BlogConst.BLOGTABLE,

"localhost");

me.add(blogRedis);

 

/** 定時任務插件 目前配置了一個每5秒鐘執行一次的定時腳本**/

QuartzPlugin quartzPlugin =  new QuartzPlugin("job.properies");

me.add(quartzPlugin);

 

}

 

/** 路由配置:1.如下配置;2.寫個類如:BlogRoute繼承Routes,配置,me.add(new BlogRoute());也可 **/

/** 路徑設置:1.第三個參數;2.可通過注解@ActionKey("/index")方式 **/

@Override

public void configRoute(Routes me) {

 

me.add("/", IndexController.class"/index");

/** controller配置路徑 **/

me.add("/blog", BlogController.class);

 

}

/*插件關閉之前【方法可選擇性使用】**/

public void beforeJFinalStop(){

System.out.println("插件關閉");

};

/*插件加載完后【方法可選擇性使用】**/

public void afterJFinalStart(){

System.out.println("加載完畢");

};

 

}

 

三.Jfinal MVC思想

 

 

1. Model:

 

public class Blog extends Model<Blog> {

 

private static final long serialVersionUID = -3649555563326235483L;

 

// 方便于訪問數據庫,不是必須

public static final Blog dao = new Blog();

/**

 * 分頁查詢數據,jfinal使用原生sql處理數據,會節省解析性能

 * @param pageNumber

 * @param pageSize

 * @return

 */

public Page<Blog> paginate(int pageNumberint pageSize) {

return paginate(pageNumberpageSize"select * ","from blog order by id asc");

}

public Blog getLastInsertBlog(){

return findFirst("select * from blog order by id desc"); //降序

}

}

 

 

2.Controller:

 

public class CoreConfig extends JFinalConfig {

 

/** 常量配置 **/

@Override

public void configConstant(Constants me) {

loadPropertyFile("system_config_info.txt");

// 設置開發模式

me.setDevMode(getPropertyToBoolean("devMode"true));

me.setUrlParaSeparator(Const.SYMBOLAMPERSAND);

}

 

/** 處理器配置 接管所有web請求,可在此層做功能性的拓展 **/

@Override

public void configHandler(Handlers me) {

DruidStatViewHandler dvh =  new DruidStatViewHandler("/druid");

me.add(dvh);

}

 

/** 攔截器配置 類似與struts2攔截器,處理action **/

@Override

public void configInterceptor(Interceptors me) {

 

me.add(new TxByMethods("find","update","delete","save")); //聲明式事物管理

}

 

/** 插件配置 JFinal集成了很多插件:redis,druid,quartz... **/

@Override

public void configPlugin(Plugins me) {

 

/** 數據庫監控druid **/

DruidPlugin dp = new DruidPlugin(getProperty("jdbcUrl"),

getProperty("user"), getProperty("password"));

dp.addFilter(new StatFilter()); //sql監控

dp.addFilter(new WallFilter()); //防止sql注入

WallFilter wall = new WallFilter();

wall.setDbType("mysql");  //mysql

dp.addFilter(wall);

me.add(dp);

ActiveRecordPlugin arp = new ActiveRecordPlugin(dp);

me.add(arp);

//表映射關系

arp.addMapping(BlogConst.BLOGTABLE"id", Blog.class);

/** redis緩存支持根據不同模塊使用緩存,目前我創建一個關于blog的緩存塊 **/

RedisPlugin blogRedis = new RedisPlugin(BlogConst.BLOGTABLE,

"localhost");

me.add(blogRedis);

 

/** 定時任務插件 目前配置了一個每5秒鐘執行一次的定時腳本**/

QuartzPlugin quartzPlugin =  new QuartzPlugin("job.properies");

me.add(quartzPlugin);

 

}

 

/** 路由配置:1.如下配置;2.寫個類如:BlogRoute繼承Routes,配置,me.add(new BlogRoute());也可 **/

/** 路徑設置:1.第三個參數;2.可通過注解@ActionKey("/index")方式 **/

@Override

    public void configRoute(Routes me) {

 

me.add("/", IndexController.class"/index");

/** controller配置路徑 **/

me.add("/blog", BlogController.class);

 

}

/*插件關閉之前【方法可選擇性使用】**/

public void beforeJFinalStop(){

System.out.println("插件關閉");

};

/*插件加載完后【方法可選擇性使用】**/

public void afterJFinalStart(){

System.out.println("加載完畢");

};

 

}

 

3.View:

 

Jfinal支持FreeMarker、JSP、Velocity

 

四.Jfinal 組合插件:

 

1.Druid:

 

 配置插件:

 

/** 數據庫監控druid **/

DruidPlugin dp = new DruidPlugin(getProperty("jdbcUrl"),

getProperty("user"), getProperty("password"));

dp.addFilter(new StatFilter()); //sql監控

dp.addFilter(new WallFilter()); //防止sql注入

WallFilter wall = new WallFilter();

wall.setDbType("mysql");  //mysql

dp.addFilter(wall);

me.add(dp);

配置Handler:

 

DruidStatViewHandler dvh =  new DruidStatViewHandler("/druid");

me.add(dvh);

訪問路徑:

 

        localhost:8080/Jfinal/druid/index.html

 

2.Redis:

 

  配置插件:

 

/** redis緩存支持根據不同模塊使用緩存,目前我創建一個關于blog的緩存塊 **/

RedisPlugin blogRedis = new RedisPlugin(BlogConst.BLOGTABLE,"localhost");

me.add(blogRedis);

 

  Redis非web環境下測試:

 

   public class TestRedis {

public static void main(String[] args) {

RedisPlugin redisPlugin = new RedisPlugin("test""localhost");

redisPlugin.start();

Redis.use("test").set("testDemo""tdd");

System.out.println(Redis.use("test").get("testDemo"));

}

}

 

3.Quartz:

 

 配置插件:

 

  QuartzPlugin quartzPlugin =  new QuartzPlugin("job.properies");

me.add(quartzPlugin);

 

配置job.properies:

 

a.job=com.demo.jfinal.job.JobDemo

a.cron=*/5 * * * * ?

a.enable=true

 

JobDemo類:

 

public class JobDemo implements Job {

 

@Override

public void execute(JobExecutionContext jobExecutionContextthrows JobExecutionException {

System.out.println("JobDemo開始執行啦" + System.currentTimeMillis());

}

 

}

 

 

4.log4j

 

log4j.properties:

 

#log level:[ERROR,WARN,INFO,DEBUG]

log4j.rootLogger=INFO,appender1,appender2

 

#log print in layout

log4j.appender.appender1=org.apache.log4j.ConsoleAppender

log4j.appender.appender1.layout=org.apache.log4j.PatternLayout

log4j.appender.appender1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss:SSS}[%p]: %m%n

 

# log print in file

#log4j.appender.file=org.apache.log4j.FileAppender

#log4j.appender.file.File=../logs/Jfinal.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

 

log4j.appender.appender2=org.apache.log4j.jdbc.JDBCAppender

log4j.appender.appender2.driver=com.mysql.jdbc.Driver

log4j.appender.appender2.URL=jdbc:mysql://localhost:3306/jfinal_demo?useUnicode=true&characterEncoding=UTF-8

log4j.appender.appender2.user=root

log4j.appender.appender2.password=root

log4j.appender.appender2.sql=insert into log (create_time,log) VALUES ('%d{yyyy-MM-dd hh:mm:ss}', '%c %p %m %n')

log4j.appender.appender2.layout=org.apache.log4j.PatternLayout

 

 

Job表:

 

Create Table: CREATE TABLE `log` (

  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,

  `create_time` datetime NOT NULL,

  `log` varchar(200) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=168 DEFAULT CHARSET=utf8

 

應用:

 

  public void find() {

//先從緩存里面找數據

Blog cacheBlog = BlogRedis.getBlogFromCache(getParaToInt(BlogConst.ID));

 

if(!BeanUtil.isBeanEmpty(cacheBlog)){

logger.info("查找成功");

renderJson(ControllerCommon.ctrCommon.returnJsonToClient(cacheBlog));

}else {

//緩存沒有數據,從DB讀

Blog blog = BlogService.blogService.findBlogById(getParaToInt(BlogConst.ID));

if (BeanUtil.isBeanEmpty(blog)) {

logger.error("查找失敗");

ControllerCommon.errorMsg("數據為空");

}

logger.info("查找成功");

renderJson(ControllerCommon.ctrCommon.returnJsonToClient(blog));

}

}

 

5.JFinal Test

JFinalModelCase:

 

public class JFinalModelCase {

 

protected static DruidPlugin dp;

protected static ActiveRecordPlugin activeRecord;

 

/**

 * 數據連接地址

 */

private static final String URL = "jdbc:mysql://127.0.0.1/jfinal_demo?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull";

private static final String USERNAME = "root";

private static final String PASSWORD = "root";

private static final String DRIVER = "com.mysql.jdbc.Driver";

private static final String DATABASE_TYPE = "mysql";

 

/**

 * @throws java.lang.Exception

 */

@BeforeClass

?public static void setUpBeforeClass() throws Exception {

dp = new DruidPlugin(URLUSERNAMEPASSWORDDRIVER);

dp.addFilter(new StatFilter());

dp.setInitialSize(3);

dp.setMinIdle(2);

dp.setMaxActive(5);

dp.setMaxWait(60000);

dp.setTimeBetweenEvictionRunsMillis(120000);

dp.setMinEvictableIdleTimeMillis(120000);

 

WallFilter wall = new WallFilter();

wall.setDbType(DATABASE_TYPE);

dp.addFilter(wall);

 

dp.getDataSource();

dp.start();

 

activeRecord = new ActiveRecordPlugin(dp);

activeRecord.setDialect(new MysqlDialect()).setDevMode(true)

.setShowSql(true); // 是否打印sql語句

 

// 映射數據庫的表和繼承與model的實體

// 只有做完該映射后,才能進行junit測試

activeRecord.addMapping(BlogConst.BLOGTABLE, Blog.class); // 測試其他Model可以繼續添加配置

activeRecord.start();

}

 

/**

 * @throws java.lang.Exception

 */

@After

public void tearDown() throws Exception {

activeRecord.stop();

dp.stop();

}

 

}

 

編寫測試類(需繼承JFinalModelCase)

 

public class TestBlog extends JFinalModelCase {

 

@Test

public void testFind() {

 

Blog blog = BlogService.blogService.findBlogById(1);

System.out.println(blog);

}

 

@Test

public void testJson() {

 

// HashMap<String, String> map = ControllerCommon.errorMsg("失敗");

// String string = JsonKit.toJson(map);

 

String columns = BlogConst.CONTENT + Const.SYMBOLCOMMA

+ BlogConst.TITLE;

Blog blog = Blog.dao.findById(1, columns);

 

ControllerCommon.errorMsg("執行");

 

JFinalTestUtil.print(JsonKit.toJson(ControllerCommon.ctrCommon

.returnJsonToClient(blog)));

 

}

 

@Test

public void testFindFirst() {

 

Blog blog = Blog.dao.getLastInsertBlog();

JFinalTestUtil.print(String.valueOf(blog.getInt("id")));

}

}

 

五、開發實例

 

index:

 

http://localhost:8080/Jfinal/blog/index?pageNumber=1&pageSize=10

 

{

  "result": {

    "pageSize": 10,

    "pageNumber": 1,

    "list": [

      {

        "content": "JFinal Demo Content here",

        "id": 1,

        "title": "JFinal Demo Title here"

      },

      {

        "content": "test 1",

        "id": 2,

        "title": "test 1"

      },

      {

        "content": "test 2",

        "id": 3,

        "title": "test 2"

      },

      {

        "content": "test 3",

        "id": 4,

        "title": "test 3"

      },

      {

        "content": "test 4",

        "id": 5,

        "title": "test 4"

      }

    ],

    "totalRow": 5,

    "totalPage": 1

  },

  "status": "200000",

  "msg": "成功"

}

 

find:

 

http://localhost:8080/Jfinal/blog/find?id=2

 

{

  "result": {

    "content": "test 1",

    "title": "test 1"

  },

  "status": "200000",

  "msg": "成功"

}

 

delete:

 

    http://localhost:8080/Jfinal/blog/delete?id=1

 

{

  "result": true,

  "status": "200000",

  "msg": "成功"

}

 

save:

 

    http://localhost:8080/Jfinal/blog/save?title=1&content=1

 

{

  "result": "",

  "status": "200000",

  "msg": "成功"

}

 

update:

 

http://localhost:8080/Jfinal/blog/update?id=6&title=2

 

{

  "result": true,

  "status": "200000",

  "msg": "成功"

}

 

六、Jfinal擴展

 1. 本demo中我建立了blog模塊,其他模塊建議以下架構風格:一個模塊一個service,一個模塊一個Redis,一個模塊多個Model,一個模塊一個Controller

 2. 項目擴展:建議抽象出BaseModel,所有的model只需要集成它,減少代碼的冗余

 3. 日志:實際開發過程中會使用到更多可用字段:userId,iP等;建議抽象log代碼塊,或者在filter中做相應處理

         4 為了極速開發,中小型項目,可以不使用Service層,而且業務全部放入Model,稱之為充血領域模型

 

七、項目git地址 

    https://github.com/1011641270/Jfinal

來自:http://my.oschina.net/tdd/blog/543021

 本文由用戶 nyyb 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!