Java 框架起步

简单的开场白:把我开发 Java Web 框架过程中想说的话,给说出来。先介绍下作者的背景,本人最先比较熟悉 JS,先是接触过 ASP(VBS)、ASP(用 JScript 编写,花时间不少)、ASP.net(不算太深入)、Java。最后确定了 Java 作为目标开发平台。小弟 2004 年学 MS Classic ASP 最老的那种 ASP,非 Net。到现在开始,正式使用 JSP。虽然小弟之前很早就接触 Java 了,大概知道一点点,却又不尽然。因此还是要边学边用。又因自学的,或者工作过程中自己摸索的,所以应该有非常多“小白”的地方,因此唐突不对的地方,请大家一一指正。是以为笔记吧。

缘由……演进史

我的 Web 开发知识始发于微软 ASP,自然比较熟悉,所以遇到其他 Web 开发平台,难免不作为比较。ASP 更多的考虑是页面怎么样输出 HTML,一个 *.asp 页面固定为一个 URL,也对应着一个请求。同时期的 JSP/PHP 也是相仿的道理,当然 JSP 可以编写自己的  Servlet 显得更强大一些。于是后来的 .net 提出的 WebForm、Code Behind 也是力求页面与逻辑分离,这种概念当时大行其道,无不充分实践 Web 三层架构的旗号。其中值得一提的是 Classic ASP 也就是我刚才说我入门的 ASP,属于比较古老的语言,但架构上可以支持 COM/COM+ 组件开发——为此我还特意地买了一本很厚的 O'Reilly 出版的书《ASP 组件开发》,专门介绍不同的语言开发 ASP dll 组件。实话说,这种架构很不错,对开发者也挺友好(囊括 C++/Java/Python/Perl/WSH/JavaScript 等语言,只要有解析器的就可以),但随着 .Net 大势,COM/COM+ 技术也逐渐没落……

表示层、业务层、数据层,不论不同语言和平台有着它们不同的名词,但大体上 Web 架构的划分就是从这三个大块开始的,意思差不多。

ASP/PHP/JSP 这类的共同点都是有个 Pages,都内置了 Web 开发所必须的几大对象,例如 ASP 的 Request、Response、Session、Server、Application,JSP 对应的都有!从 ASP 到 JSP,后者只是把 Visual Basic Script 换成了 Java,然后这几大对象的 API 有所不同而已,都有 Request、Response 等等,但页面生成方式还是也页面为优先切入点,不约而同的使用 <%=%> 输出动态内容。当然了,HTML还是 HTML,CSS 还是 CSS,这些知识无论 ASP/PHP/JSP 都是一致的,应该说是毫无“违和感”的。总之,早期类型的开发模型做起页面来都是很快手,适合于前端优先的学习路径,——以至对影响我很深,使得我一直不肯放弃 <%=XXX%> 大法,甚至还一度排斥 Servlet:认为“直接输出 HTML 很爽,容易看到效果”、“Java 又不用编译、写 Servlet 麻烦”,那时候,我写 Java 不是写一个个 Class,而是一个个 JSP 然后 include……这种“避重就轻”的状况坚持了很久,直到今天,我所设计的程序结构,虽然已大幅度改善,更多地利用 Java 语言传统优势和 Java Web 框架的固有优点,但必须承认,中间“说服自己”的过程(弯路)走了很久……

对于复杂的逻辑还是需要更高层次的划分,那便是 MVC 了。MVC 足够经典,所以很有必要回顾以一下 Servlet。早期 Servlet 模型很朴素,1、Web.xml 指定 url;2、继承 HttpServlet,重写 doGet/doPost 方法;3、数据库 SQL 操作,例如读取一条记录(此为业务逻辑范畴);4、得到数据,塞入 request.setAttribute("name", rs.getString("name")) 然后分发到 JSP 到:req.getRequestDispatcher("hello.jsp").forward(req, resp);;5、JSP 模板中使用 EL 表达式或者标签渲染最终 HTML 出来。简单说,乃是 Servlet+Java Bean + JSP。随后 Struts/FreeMaker/Spring MVC 均为 MVC 模式的实作。

随着 Servlet 的发展,到 3.0 的 Servlet 已经支持注解等诸多方便功能了,无须其他第三方库都可以完成一般的工作了。

推荐教程:《Servlet/JSP 學習筆記》http://openhome.cc/Gossip/ServletJSP/

初期目标

我觉得,框架开发乃“摸着石头过河”,边写边修正目标,因此谈不上“超越 XX 框架”,或者更遑论“推广,介绍别人使用”!质言之,是为了记录下一些自问有价值的内容,是为笔记。根据自己的一点经验,初期的目标应该如下。

  • 轻量级,或曰“羽量级”。什么事轻量级呢?我认为,首先不要太多概念,众所周知,Java 是“名词帝国”,因此我们就是要避免走进为概念而概念的误区,其次尽可能不依赖太多第三方库,最后对于功能而言,先实现功能,再完善!
  • 逻辑尽可能自然,解决思路要彻底而且不失灵活,不要太 Hack。
  • 代码可读性要高,不要晦涩的代码。
  • 混合型编程,主张多语言参与开发。

很多事物应该是做出来了,才算有某个特性吧。这些特性如果不太偏离当初的目标,就可以具体化了。现在这个目标是比较模糊的,——等框架差不多的时候,再罗列一次各项特点。

基本选型如下。

前端:HTML5/CSS/JavaScript/LESS/Sea.js/Step.js/Bigfoot.js

后端:Java/JSP/Tag Files/Rhino

数据库:SQLite/MySql

项目构建:Eclipse/Node.js/Grunt

测试框架:JUnit/Mockito

上面我谈到了“混合型编程”,那么,什么是混合型编程呢?下面讲讲我的看法,当然其中也借鉴了别人的观点,包括图片资源也是。

混合型编程

现在有种混合型编程的观点,正好符合我使用 Rhino 的想法。具体说,就是大家针对 Java 静态类型不太灵活,编译比较麻烦,部署需要重启服务器,而且 Java 语法相对冗长,不够简洁等观点,提出在 JVM 上多语言开发的这么一种编程方式。他们认为,对于金字塔顶端的语言,应该是侧重的是灵活性和快速部署能力,而一方面,比较务实的做法是利用 Java 丰富的 API 和类库完成底层繁重的工作。

JVM 上有不少备用语言可供选择,如 JRuby、Groovy、Scala 和 Rhino 等,它们使用范围非常广泛,都是有相对生命力和影响力的语言,之所以选择 Rhino,基于下面的原因。

  • JavaScript 用起来比较顺手,简单
  • Rhino 从 Java 6 开始自带,无须额外依赖
  • Rhino 跟 Java 的交互操作十分容易,基本上它们之间是互通有无的。

实际上,我使用 ASP 开发之时,更多的是使用 JavaScript 的变种 JScript,生成 JSON 数据非常简单。JS 是动态语言,我认为在字符串处理(正则表达式)、反射、天然的 JSON 支持和函数式编程这几个方面有优势,就是十分便捷,Java 几十行的代码,JS 十几行或者更短就搞掂了。于是,我在这个 Java Web 框架中大量利用自带 JS 引擎 Rhino 来完成编码的工作。实际上,JavaScript 不负其名,果然是 Java 之脚本,既是 Java 的子集,也不与 Java 正面冲突,正好弥补 Java 静态语言的不足,定位十分鲜明准确。引申地想想,这不就像是 C 之于 C++,盖因很多人把 C 作为一种“脚本”了。

然而在实际尝试中,却走了一段弯路……

这个框架第一版的时候,我用力过猛,造成有点过犹不及,js 大面积地使用,在 JVM 上完全构建了一门 JavaScript 的动态层,丧失了 Java 作为静态、编译型语言所固有的优点,例如完整成熟的 OO、类型安全、集成便捷的 IDE 和工具。乃至于到项目后期的时候,面对一大堆难以维护的动态语言,写再多的注释感觉也是苍白(与写前端组件感觉类似)。接着磕磕碰碰到第二版时候,我决定重构,并花不少时间想,什么时候用 Java,什么时候用 JS。结论是,那应该根据 Java 和 JS 语言特性来决定的——贸然舍弃 Java 是不明智的,而且 Java 那么的优美,怎么能一刀切呢?我真是有眼不识泰山啊。及后,我把以前许多用 JS 写的逻辑移到 Java。JS 的位置,我想应该是“短平快”,具体就是提供某个特定函数,特别是字符串处理(Web 开发很多场景是处理 String)和反射的场景。注意 JS 代码不要过渡设计,不要太大颗粒度,不要太多继承,简简单单一个个函数传参数就好了。

我当前使用 JS 的地方:

  • 服务端 JSON 读取解析,使用 Rhino,没有依赖第三方 JSON JAR 包
  • 配置系统,用 JSON 保存配置信息
  • 接口 url 分发器,使用正则分发
  • ORM 的方案基于 SQL 字符串拼凑,里面全部的逻辑使用 JS 编写。

了解 Tomcat

开发者从对 Java 的热爱延伸到对 JSP 的热爱,同时 JSP 也是 J2EE 体系中最重要,而且又是最基础的一个组成部分,如果要体验 J2EE 带了的开发效率和优势,JSP 会是非常有效的入门方式。学习、使用 JSP 的好处如下:

  • JSP 程序容易上手,如果有 HTML 和 Java 的基本知识,或者接触过 ASP/PHP 的话,那么学习 JSP 程序就没有任何难度。
  • JSP 就是在 HTML 中嵌入 Java 代码,所以在本质上 JSP 程序就是 Java 程序,JSP 程序继承了Java 的一切优点(注,除了内部类稍有不同)。JSP 程序有严格的 Java 类库支持。JSP 页面在服务器中都会被 JSP 编译器编码称对应的 Servlet。
  • JSP 中可以使用 Java Bean 进行逻辑封装,这样就可以实现逻辑功能代码的重用,即经典的 Bean + Servlet + JSP,从而大大提高系统的可重用性,同时也提高了程序的开发效率。
  • 新版 Eclipse 4.2 完全做到对 JSP 开发给力的支持,包括错误校验、智能提示、调试等强大的辅助功能,甚至 include 文件的上下文都可支持。
  • 最重要的一点,JSP 不需要重启服务器!
总之,一个工具如果使用的好,取其长而去其短,自然可以飞花摘叶皆可伤人。

另请参阅 :http://javaonejcy.iteye.com/blog/505128《极简风格Web架构,jsp+jdbc的二次复辟》http://www.blogjava.net/calvin/archive/2008/07/31/218903.html


解决 EL & 表达式不能调用方法、传参数的问题

在自定义标签的使用中,EL 表达式是必不可少的一环。官方的 API 需要到了最新版本(EL v2.2, JDK7、Tomcat 7)才可以提供调用方法的直接方式。在老版本的 Tomcat 下,如何才可以像 Strus 那样调用方法呢?国外一位开发者给出了答案。首先复制以下两个类 ELMethod.java 和 Call.java 到你的项目中(适当修改包名)。

http://www.vineetmanohar.com/2010/07/how-to-pass-parameters-in-el-methods/

http://www.vineetmanohar.com/2010/08/calling-static-methods-from-el/

ELMethod.java:

package com.vineetmanohar.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Extend this class to implement a server side method that takes arguments that
 * you would like to call via expression language.
 * 
 * @author Vineet Manohar
 */
public abstract class ELMethod extends HashMap<Object, Object> {
	private static final long serialVersionUID = 1L;

	private final int numArgs;

	/**
	 * @param numArgs
	 *            number of arguments this method takes
	 */
	protected ELMethod(int numArgs) {
		this.numArgs = numArgs;
	}

	@Override
	public Object get(Object key) {
		// if exactly one argument, call the result() method
		if (numArgs == 1) {
			return result(new Object[] {key});
		}

		// if more tha one argument
		return new Arg(this, key);
	}

	public int getNumArgs() {
		return numArgs;
	}

	/**
	 * 1) Implement this method in the child class. This method becomes
	 * accesible via expression language.
	 * 
	 * 2) Call this method using map syntax, by treating the instance of the
	 * child class as a map of map of maps...
	 * 
	 * For example, you could extends this class and create a class called
	 * FormatDate. In that class, the result method would expect 2 arguments,
	 * format string and date object.
	 * 
	 * ${FormatDate["MMM dd"][user.creationDate]}, where dateFormat is an
	 * instance of the child class.
	 * 
	 * @param args
	 * @return
	 */
	public abstract Object result(Object[] args);
	
	public static class Arg extends HashMap<Object, Object> {
		private static final long serialVersionUID = 1L;
		private List<Object> args = new ArrayList<Object>();
		private ELMethod parent;

		public Arg(ELMethod eLMethod, Object key) {
			this.parent = eLMethod;
			this.args.add(key);
		}

		@Override
		public Object get(Object key) {
			this.args.add(key);

			// if all the arguments have been received, invoke the result method
			if (args.size() == parent.getNumArgs()) {
				Object retVal = parent.result(args.toArray());

				return retVal;
			}

			return this;
		}
	}
}
Call.java:
package com.vineetmanohar.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class lets you call static methods from EL
 * 
 * Step 1) Create an instance of this class and bind it to the "call" variable
 * in your EL. For example, in a JSP do the following:
 * request.setAttribute("call", new Call());
 * 
 * Step 2) Call any static method as follows:
 * 
 * ${call["some.package.SomeClass.methodName"]["arg1"][arg2]}
 * 
 * The first argument is the fully qualified class and method name. The
 * remaining arguments are arguments to the method that you are calling.
 * 
 * Note: method overloading not supported
 * 
 * Note: method must be static
 * 
 * @author Vineet Manohar
 */
public class Call extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;

	@Override
	public Object get(Object key) {
		String fullyQualifiedMethodName = (String) key;

		// format of key is package.Class.method
		Pattern pattern = Pattern.compile("(.+)\\.([^\\.]+)");
		Matcher m = pattern.matcher(fullyQualifiedMethodName);
		if (m.matches()) {
			String fqClassName = m.group(1);
			String methodName = m.group(2);
			Class<Object> clazz;
			try {
				clazz = (Class<Object>) Class.forName(fqClassName);
			} catch (ClassNotFoundException e) {
				throw new IllegalArgumentException("Invalid method name: "
						+ key, e);
			}
			Method[] methods = clazz.getMethods();
			for (final Method method : methods) {
				if ((method.getModifiers() & Modifier.STATIC) == 0) {
					continue;
				}

				if (method.getName().equals(methodName)) {
					// return the first method found
					int numParameters = method.getParameterTypes().length;

					if (numParameters == 0) {
						return invokeMethod(method);
					}

					return new ELMethod(numParameters) {
						@Override
						public Object result(Object[] args) {
							return invokeMethod(method, args);
						}
					};
				}
			}
		}

		throw new IllegalArgumentException("Invalid method name: " + key
				+ ". Must be a fully qualified class and method name");
	}

	private Object invokeMethod(final Method method, Object... args) {
		try {
			return method.invoke(null, args);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException("Exception while executing method", e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException("Exception while executing method", e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException("Exception while executing method", e);
		}
	}
}
然后实例化 Call 对象。反正在 JSP 里随你喜欢即可,如 request.setAttribute("call"new Call()); 或 <jsp:useBean id="call" class="Call" scope="application" /> 都冇问题。

最后一步就是解决问题的目标,调用方法并传参数了。试写出表达式:${call["com.mycompany.util.DateUtils.formatDate"]["MMM, dd"][account.creationDate]},其中 com.mycompany.util.DateUtils.formatDate 是 Java 静态方法,要写全称。最后两项是传入的参数,分别可以是字符串和当然 EL 对象(如account.creationDate)。

观其上述源码,实际是利用了 Java 反射的原理调用方法。不要注意一点的是,不支持方法的重载哦(Overloaded)。

如果不是静态方法,实例方法可不可以调用呢?按照作者的介绍也是可以的。

早期我对 Java Web 的理解

J2EE 世界充斥着许多概念,如 MVC、Service、DAO 等等,而且这些许多都是“似是而非”的名词。如果不对这些概念进行厘清,恐怕不能全然贯通、明晰整个框架。这就体现了概念其重要性。鄙人希望:一、概念虽然会比较”笼统“,——这是因为概念处于较高层的位置,有涵盖的作用,但应该尽量明晰和收窄定义的范围;二、从概念到某件事物,是”抽象“到”具象“的过程,会形成某个特定”名词“,既然”名词“是特指的,那么应该没有二义性,即没有歧义;三、概念最后能找到真正所对应的具体事物,可以在代码中反映出来的。凡事须顾名思义,有其名就当有其实;四、理想情况下,一个系统不应存在重复的代码或模块。如果赋予一个事物有一个概念或名词 A,A 具有排他性,不能再使用,但可以包含其所属的 B 事物。即,A 是 A,B 是 B。如果 A 包含 B,那么 A ≠ B。

需要指出的是,本文所讨论的定义对其他框架不一定适用,请不要周延,当前仅限于 Bigfoot 界定概念所用——这也是为了避免争议的提前声明,同时这样也比较简单,点到即止。

基础概念

分层是应对复杂性的必然手段。解决一个个各自的小问题,最终来解决大问题,“分而治之”。

程序三层结构,毋庸置疑。


与数据库打交道的三个方法

以上脑图参考自《三层究竟如何?》

我们比较推崇“半自动 SQL”的方法,既非直接写 SQL,也不是 ORM(也不熟悉 存储过程)。此方面的具体内容,参见前篇文章《浅浅地封装一层 JDBC》

一般 SSH 结构

虽然有经典 SSH 架构摆在面前,但我们并不拘泥于此,同样积极寻找适应项目变化,可重用,方便程序员的架构方法,以适应于“互联网程序架构”而非单单“企业级开发”的架构。

JavaEE 体系架构

JavaEE 体系架构采用传统的 MVC 设计模式,分为 Model、View、Controller 三层,其中:Model 即模型层,定义数据模型和业务逻辑。

为了将数据访问与业务逻辑分离,提高业务精度,降低代码之间的耦合,模型层又细分为 DAO 层与 Service 业务层,DAO 全称为 Data Access Object(数据访问对象),将数据库访问代码封闭起来,MyBatis API 也在此封装,不再出现在其他层或向其他层暴露;业务层是整个系统最核心也最具价值的一层,该层对应用程序的业务逻辑进行封装,务求关注客户需求,在业务处理过程中会访问原始数据或产生新数据,或者需要持久化数据,DAO 层提供的 DAO 类能很好地帮助业务层完成数据处理,业务层本身则侧重于对客户需求的理解和业务规则的适应,自然也包括大部分的计算。

总体说来,DAO 不处理业务逻辑,只做与存取数据有关的获取原始数据或持久化数据等操作,为业务层提供辅助。

View 即视图层,为最终用户提供一个友好的交互界面,用户可以查看请求结果,也可以通过表单等交互手段实现数据录入。

Controller 层即控制器,他是 Model 与 View的桥梁,将二者很好的衔接,通过 View 接收用户数据,Controller 将数据传输给Model,Model 对数据进行处理;或者 Model 读取数据后,Controller 将数据传递给 View,View 向用户展示数据。一来一往,Controller 成了 Model 与 View 之间的快乐使者。具体来说,Controller 负责数据验证,跳转逻辑,赋值/取值。这里会出现 Request/Response 对象——但将 Request/Response 对象放到其他层就不合适了,举个反例,如果在 Service 层出现 Request/Response 对象那么有必要进行重构修正了。

  • 从调用关系上看,左为高层,右为低层,下为高层,上为低层,高层可以调用低层,但低层不能调用高层,层与层之间的调用是单向的。
  • 从数据传输上看,数据可以从视图层传输到 DAO 进而保存到数据库,也可以从数据库中读取数据进行处理或者显示,所以数据的传输是双向的。
  • 从技术实现上看,视图层使用 HTML/JSP 组件实现,控制器使用 Servlet 或 Action 组件实现,模型层使用 JavaBean 组件或 EJB 技术实现。

MyBatis 封装在 DAO 层,负责数据访问操作;Spring MVC 充当控制器角色,对用户数据进行合法性检验和类型转换,为视图层提供标签简化页面显示,提供国际化支持等等;Spring是应用程序的管家,DAO、Service(业务)、Action 等对象由 Spring 创建并维护各对象之间关系,同时提供声明式事务管理,简化事务编程。

MVC 结构

可维护的结构



MVC 是个大领纲,不同的框架对 MVC 的理解和实践都不尽相同,有时候甚至很难一一对号入座,也有许多衍生分支的版本。实际上,MVC 是一种模式,模式不是公式,所以除了必要的条件限定之外,就没有一定的条条框框。

注意,前面说到的三层架构 ≠ MVC。

除了经典的 JSP + Bean + Servlet 架构外,还有一种更为简单的 JSP + Bean 模式。两者区别在于处理的主控部分不同。前者利用 Servlet 作为主控部分;后者利用 JSP 作为主控部分,将用户的请求、Bean 和事件响应有效的连接起来。

我比较倾向于 JSP + Bean 模式。该模式工作原理是:当 HTTP 发出请求时,JSP 接收请求并访问 Bean,当需要访问数据库或者服务器时,则通过  Bean 做相应处理。Bean 将处理的结果返回 JSP,JSP 生成动态 html 将结果传送到浏览器并显示,用户得到交互结果。JSP 作为视图,同时也有部分控制器的功能, Bean 组件作为模型和控制器组件。

这样的好处是首先不用配置 Servlet,一个 JSP 即是 Servlet(请求路径多起来维护麻烦),其次是 JSP 以显示为中心,它为 Web 前端开发提供了更方便的开发。再者是仍然可以做到显示和内容分离,显示和业务逻辑开发可以分开同时进行,实际上并不会在 JSP 嵌入大量 Java 代码,而且显得更简单。

必须提出的是,纯 service 接口的话应该使用 Bean + Servlet 的模式,那是完全排除表示层的考虑。


前端分层,围绕 HTML、CSS、JS 三大模块来处理。


模板技术我主张使用 Tag Files。有关 Tag Files 的更多教程,参见本博客《JSP Tag Files 技术总结》

项目选型

经过反复使用和衡量,决定采用下面的组件。分有前端和后端的(点击图片放大)。


前端堆栈我的方案如下:



Bigfoot 简介

“大脚 Bigfoot”是一款基于 JEE 平台研发的 Web 框架,继承了 Java 平台的高效、安全、稳定、跨平台等诸多优势,但却摒弃了传统 SSH 企业级架构所带来的庞大和臃肿,汲取了 PHP 的简洁和方便,非常适合互联网中小型网站的应用。

Bigfoot 是真正的开源、真正的免费,其代码直观、简洁,功能方面简单实用。该系统没有去做审核流程、复杂权限和日志等企业级的功能。对于这些功能,中小型互联网项目或许不是首要考虑;当前版本力求简单和通俗易懂的代码,也就是作为基础框架而考虑的。同时大脚也注重扩展性——更复杂的功能,可以留待二次开发。

个人认为 Java 在互联网应用之所以不及 PHP 那么受欢迎,其中一个主要是因为技术人员过分追求复杂的技术架构和为概念应用而应用(怕别人说技术不专业);搞得草根都不敢去用 Java 去了;于是这样的结果是严重阻碍了 Java 在互联网的应用和推广——而 PHP 在互联网的成功在于:简单和务实(PHP 的织梦成功正是这个原因)。我们的理念:Keep it simple, stupid,做一款简单实用的开源 Web。

迈普 CMS(MyPro Content Manage System)是以 Bigfoot 基础框架为依托的网站管理系统,具有懂 HTML 就能建站的优点,提供最便利、合理的使用方式。前端模板完全开放,可让用户随心所欲的自定义显示内容和显示方式。

“大脚 Bigfoot”整体特性:

  1. 免费、简单、开源
  2. 代码行数少,概念清晰,避免过渡设计
  3. 力求高聚合、低耦合
  4. 全栈式方案,包括前端控件和服务端接口,无缝对接
  5. 基于 JVM 的混合语言编程 = Java + JavaScript(服务端 Rhino)
  6. 基于 Java 1.7,积极采用 1.7 新语法,如 autoClose、多项异常抛出
  7. 特别适合从前端过来的开发人员,提供服务端 JS 环境
  8. 完备的文档、代码注释,并提供 JUnit 单元测试
  9. 谨慎采用第三方库,当前免 JAR 依赖(除数据库驱动外)。提倡“够用就好、就地取材”,例如,日志采用 JDK 自带的 Logger、JSON 转换让 JDK 自带的 Rhino 转换、数据连接池采用 Tomcat 自带的 Pool、页面标签就用 TagFiles/SimpleTag 甚至就是连 <%=……Java Code %> 都可以、使用 JSON 或 Map 作为通用的、交换的数据结构。

控制层特性:

  1. 回归简单性,结合灵活的 MVC 思想,强调前端、后端相分离,前端 = JavaBean + JSP;后端 JavaBean + Servlet。
  2. 基于 JSONTree 无序树的无限极分类,结构清晰,可维护性强。
  3. 提倡面向接口编程,实现了一个小型的 IOC 依赖注射和 AOP。
  4. 支持 JSON API 输出纯数据,与安卓、iOS、AJAX 甚至广义的客户端等等的无缝对接。

表示层特性:

  1. JSP 实际很强大完全可以做到类似 PHP 的页面优先的理念(互联网项目 UI 开发占了大量时间)——因此我们的数据绑定方式是 JSP 引入 JavaBean,而非 Servlet 控制。
  2. 有自己的前端库 Bigfoot.js(HTML5/CSS3/JavaScript),基于 LESS.js 预编译 CSS 器和 Node.js 的构建系统。
  3. 基于 JSP Tag Files 的模板继承机制,可复用性强。
  4. 模板语言基于 EL 表达式 和 SimpleTag。
  5. 后端管理界面可选使用 Ext JS。

数据层特性:

  1. 没有使用 ORM,提倡使用带变量的 SQL,提供简单的 SQL 封装手段和 DAO。
  2. 采用 Map 为输入、输出载体,如表单转换为 Map 再生成 SQL 语句;JDBC 返回数据采用 Map 为记录载体。
  3. 与 JS 引擎 Rhino 无缝对接,用 JS 定义一些方法,脚本语言 JS 在处理 JSON、字符串和正则表达式有极大的便利性和优势。
  4. 抛弃 Java POJO,改用 JS 定义实体,目的是为适合前后台所使用
  5. 使用 Tomcat 自带的数据库连接池 JDBC Pool。

最后,欢迎各位使用 Bigfoot!

Bigfoot 源码在

第一版,已废弃:http://code.taobao.org/p/bigfoot/src/

第二版,已废弃:http://code.taobao.org/p/bigfoot_v2/src/,请用 SVN 检出:http://code.taobao.org/svn/bigfoot_v2/。

第三版,基于 Spring + Spring MVC + MyBatis:http://code.taobao.org/p/bigfoot_v2/src/java_v3/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sp42a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值