文档章节

jfinal初探

沧海一刀
 沧海一刀
发布于 2017/07/17 19:05
字数 1586
阅读 275
收藏 0

RT学习了一下jfinal 从一个快速入门案例开始学习

demo来自连接:http://www.jfinal.com/

ALT+Z用jetty启动web项目:

http://localhost:8080/jfinal_demo_for_maven/

项目启动完毕

从工程目录结构看,jfinal也是三层架构MVC 

controller,service、dao层

其中DAO层和model层无缝连接了 ,从源码可以发现:

service引用dao层的时候:

package com.demo.blog;

import com.demo.common.model.Blog;
import com.jfinal.plugin.activerecord.Page;

/**
 * 本 demo 仅表达最为粗浅的 jfinal 用法,更为有价值的实用的企业级用法
 * 详见 JFinal 俱乐部: http://jfinal.com/club
 * 
 * BlogService
 * 所有 sql 与业务逻辑写在 Service 中,不要放在 Model 中,更不
 * 要放在 Controller 中,养成好习惯,有利于大型项目的开发与维护
 */
public class BlogService {
	
	/**
	 * 所有的 dao 对象也放在 Service 中
	 */
	private static final Blog dao = new Blog().dao();
	
	public Page<Blog> paginate(int pageNumber, int pageSize) {
		return dao.paginate(pageNumber, pageSize, "select *", "from blog order by id asc");
	}
	
	public Blog findById(int id) {
		return dao.findById(id);
	}
	
	public void deleteById(int id) {
		dao.deleteById(id);
	}
}

 Blog.java

/**
 * 本 demo 仅表达最为粗浅的 jfinal 用法,更为有价值的实用的企业级用法
 * 详见 JFinal 俱乐部: http://jfinal.com/club
 * 
 * Blog model.
 * 数据库字段名建议使用驼峰命名规则,便于与 java 代码保持一致,如字段名: userId
 */
@SuppressWarnings("serial")
public class Blog extends BaseBlog<Blog> {
	
}

BaseBlog<Blog>这个泛型类再点进去看:

package com.demo.common.model.base;

import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.IBean;

/**
 * Generated by JFinal, do not modify this file.
 */
@SuppressWarnings({"serial", "unchecked"})
public abstract class BaseBlog<M extends BaseBlog<M>> extends Model<M> implements IBean {

	public M setId(java.lang.Integer id) {
		set("id", id);
		return (M)this;
	}

	public java.lang.Integer getId() {
		return get("id");
	}

	public M setTitle(java.lang.String title) {
		set("title", title);
		return (M)this;
	}

	public java.lang.String getTitle() {
		return get("title");
	}

	public M setContent(java.lang.String content) {
		set("content", content);
		return (M)this;
	}

	public java.lang.String getContent() {
		return get("content");
	}

}

BaseBlog最终是继承Model类的

注意这段,物理分页列表的实现

	public Page<Blog> paginate(int pageNumber, int pageSize) {
		return dao.paginate(pageNumber, pageSize, "select *", "from blog order by id asc");
	}

传入了页码、页面大小,选择的列,排序方式 

paginat(int pageNumber, int pageSize)方法在内部实现了分页字段填充、ResultSet拆解,实体类属性注入等操作(代码不贴了,就是操作JDBC),最后如你所料,返回的是一个带Blog泛型的Page对象

值得一提,在getConnection()的时候使用了ThreadLocal<Connection>

	/**
	 * Get Connection. Support transaction if Connection in ThreadLocal
	 */
	public final Connection getConnection() throws SQLException {
		Connection conn = threadLocal.get();
		if (conn != null)
			return conn;
		return showSql ? new SqlReporter(dataSource.getConnection()).getConnection() : dataSource.getConnection();
	}

SqlReporter这里使用了代理模式(JDK动态代理),有点意思~

 在JDBC 的prepareStatement()执行前加了切面,就是输出SQL日志,代码如下:

/** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */
/**
 * Copyright (c) 2011-2017, James Zhan 瑭规尝 (jfinal@126.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jfinal.plugin.activerecord;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import com.jfinal.log.Log;

/**
 * SqlReporter.
 */
public class SqlReporter implements InvocationHandler {
	
	private Connection conn;
	private static boolean logOn = false;
	private static final Log log = Log.getLog(SqlReporter.class);
	
	SqlReporter(Connection conn) {
		this.conn = conn;
	}
	
	public static void setLog(boolean on) {
		SqlReporter.logOn = on;
	}
	
	@SuppressWarnings("rawtypes")
	Connection getConnection() {
		Class clazz = conn.getClass();
		return (Connection)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{Connection.class}, this);
	}
	
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		try {
			if (method.getName().equals("prepareStatement")) {
				String info = "Sql: " + args[0];
				if (logOn)
					log.info(info);
				else
					System.out.println(info);
			}
			return method.invoke(conn, args);
		} catch (InvocationTargetException e) {
			throw e.getTargetException();
		}
	}
}



至此,jfinal的 ORM部分就看完了,不得不佩服jfinal的代码写的真的很简介,看起来并不难

视线转移到前端,看控制器部分,也就是MVC中的C。

一个典型的controller代码如下所示:

package com.demo.blog;

import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import com.demo.common.model.Blog;

@Before(BlogInterceptor.class)
public class BlogController extends Controller {
	
	static BlogService service = new BlogService();
	
	public void index() {
		setAttr("blogPage", service.paginate(getParaToInt(0, 1), 10));
		render("blog.html");
	}
}

setAttr没什么好说的,就是servlet基础知识中的request.setAttribute(name, value);

值得看的是最后一行的render("blog.html");很容易让人想起springMVC的 return "xxx.jsp" 

没错,这就是返回视图的意思!

render()方法点进去看源码:

	/**
	 * Render with view use default type Render configured in JFinalConfig
	 */
	public void render(String view) {
		render = renderManager.getRenderFactory().getRender(view);
	}

最后返回的render是一个 abstract class ,这里用了抽象工厂模式返回的是一个具体的视图实现类

Render的实现类有这么多,look~

但是还有不清楚的地方,按理说一个servlet处理完业务之后不是应该有类似如下的一些转发操作吗(重定向同理)

request.getRequestDispatcher(view).forward(request, response);

 

但是我点跟进

render("index.html");

这个源码并没有看到有这种操作啊 。原因在哪里呢 ,一时还看不出来,继续跟源码吧

我先启动工程运行到render("index.html")处打上断点,然后进入 com.jfinal.core.Controller

看到Factory类的具体实现类是renderFactory,这个renderFactory是IRenderFactory的一个实现类

熟悉工厂设计模式的朋友肯定想到了, 先找一下给抽象工厂注入具体实现的调用处

那么你或许能找到蛛丝马迹

在getRenderFactory()处按下 ctrl+shift+G,看看能搜出什么来

果然搜出来了 ,就在上图这个ActionHandler这里

继续跟源码进去看

找到这个

点进render()方法进去瞧一瞧,应该快水落石出了

强大的eclipse告诉我,有如下类实现了抽象类Render的抽象方法render()

我先选个JspRender进去看下实现吧,看到如下代码。这下终于跑不掉了吧

	public void render() {
		// 在 jsp 页面使用如下指令则无需再指字符集, 否则是重复指定了,与页面指定的不一致时还会出乱码
		// <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
		// response.setContentType(contentType);
		// response.setCharacterEncoding(encoding);
		
		try {
			if (isSupportActiveRecord)
				supportActiveRecord(request);
			request.getRequestDispatcher(view).forward(request, response);
		} catch (Exception e) {
			throw new RenderException(e);
		}
	}

其中 终于出现了我们熟悉的servletAPI:

request.getRequestDispatcher(view).forward(request, response);

问题解决但是还存在疑问

好好的代码怎么就莫名其妙的和这个什么handler勾搭上了? 

怎么调用的?答案就在就这个过滤器里面 

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 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">
  <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.common.DemoConfig</param-value>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>jfinal</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

好了,以上就是jfinal源码的一点小探索,重点就是分享一下阅读源码的思路

© 著作权归作者所有

沧海一刀

沧海一刀

粉丝 10
博文 82
码字总数 51790
作品 0
黄浦
程序员
私信 提问
学JFinal不迷路,JFinal优质资源列表(欢迎反馈更新)

学JFinal不迷路,记录一下JFinal相关的资源、产品、讲师等信息(所有信息排名不分先后)。 一、相关站点: 1、JFinal官网-问答、分享、文档、交流、俱乐部 http://www.jfinal.com 2 、JFina...

山东-小木
05/25
425
0
jfinal sdk和jfinal weixin区别

@JFinal ,你好,我的项目现在继承了jfinal 3.2版本,但是突然加入了公众号需求,想知道jfinal 3.2和jfinal weixin 1.2有什么区别?如果jfinal weixin是直接在jfinal 上扩展的,那我是不是把j...

pkxutao
2017/08/09
217
2
JFinal Weixin 2.3 发布,支持微信小程序开发

jfinal weixin 项目早在五年前就发布了第一个版本,是老牌的微信公众号开发 SDK,已稳定、可靠服役多年。因为极简设计、良好的开发体验,所以深受开发者的喜爱。 五年来 jfinal weixin 一直紧...

JFinal
02/01
2.3K
6
jfinal的缓存处理

@JFinal 你好,想跟你请教个问题: 我刚过了下jfinal官方提供的实例->jfinal_blog,想到以下几点,不知有价值没,如下: 1、 @Before(CacheInterceptor.class) @CacheName("jfinal_cache") p...

lewjun072
2014/06/06
3K
6
SoJpt Boot 2.0-3.8 发布,Spring Boot 使用 Jfinal 特性极速开发

SoJpt Boot,在Spring Boot框架下使用Jfinal特性极速开发。 可以在Spring Boot中向使用Jfinal一样使用Enjoy, Aop, controller的一系列方法(如: getFile(), renderFile....),以及ActiveRecor...

Sohnny
04/09
634
0

没有更多内容

加载失败,请刷新页面

加载更多

使用TensorFlow的AI程序运行报错AttributeError: module 'tensorflow' has no attribute 'xxx'

使用TensorFlow的AI程序,在运行时报错AttributeError: module 'tensorflow' has no attribute 'xxx',首先检查是否是包路径不对,一般是版本变化所致。...

织梦之魂
32分钟前
2
0
提示浏览器版本低

本文转载于:专业的前端网站➭提示浏览器版本低 网站网页在遇到浏览器低版本(尤其是IE浏览器)时,提示浏览器版本低(如IE8以及以下),建议用户升级浏览器以获得最好体验。以下是代码: 1...

前端老手
34分钟前
5
0
CentOS 7系统增加swap

转载请注明文章出处:CentOS 7系统增加swap swap是位于磁盘上的特殊文件(或分区),属于“虚拟内存”的一部分。通俗点就是内存的备胎,内存充足的情况下,基本上没swap什么事(和设置有关)...

tlanyan
57分钟前
6
0
基于Prometheus和Grafana的监控平台 - 环境搭建

相关概念 微服务中的监控分根据作用领域分为三大类,Logging,Tracing,Metrics。 Logging - 用于记录离散的事件。例如,应用程序的调试信息或错误信息。它是我们诊断问题的依据。比如我们说...

JAVA日知录
今天
6
0
PHP运行时全局构造体

struct _php_core_globals { zend_bool magic_quotes_gpc; // 是否对输入的GET/POST/Cookie数据使用自动字符串转义。 zend_bool magic_quotes_runtime; //是否对运行时从外部资源产生的数据使...

冻结not
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部