今天1.0版本已经有一个雏形了,以后会加入更多的东西。

先介绍下我的思路吧。

第一步、是velocity引擎,我使用一个取路径的类来寻找已经设计好的模版文档,将其中的模版标签替换,将其作为响应返回给浏览器。

代码:

/**CurrentappHelper.java*/
public static File getTemplatedir() {
		return new File(guessAppdir(), "view");
	}
/**VelocityEnginee.java**/
public class VelocityEnginee{
          public VelocityEnginee() {
		File templatedir = CurrentappHelper.getTemplatedir();
		System.out.println(templatedir);
		RuntimeSingleton.setProperty(
				RuntimeConstants.FILE_RESOURCE_LOADER_PATH, templatedir
						.getAbsolutePath());
		try {
			RuntimeSingleton.init();
		} catch (Exception e) {
			logger.error("Error", e);
		}
	}
VelocityContext context = new VelocityContext();
	/**
	 * 根据当前请求生成  模板数据内容,如果不生成会显示原数据
	 * 
	 * @param req
	 * @return
	 */
	public void putContext(String infoname,Object info) {		
		context.put(infoname, info);
	}
	/**
	 * 根据视图名生成响应后的页面
	 * @param viewname
	 * @param context
	 * @param writer
	 * @throws ParseErrorException 
	 * @throws ResourceNotFoundException 
	 * @throws Exception
	 */
	public void show(String viewname,PrintWriter writer) throws Exception {
	
			Template tp = RuntimeSingleton.getTemplate(viewname+".html", "gbk");
			tp.merge(context, writer);
	}
}

第二步、修改web.xml文件将其所有的sevlet路径都指向我自己定义的类。

<web-app>
        <servlet>
		<servlet-name>vatana</servlet-name>
		<servlet-class>com.inca.vatana.VatanaServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>vatana</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

第三步。建立自己的类VatanaSevlet类。类中调用VatanaController的call()作为控制器指定模型并取得一个字符串作为视图索引。

调用VelocityEnginee的show()方法呈现视图给浏览器。

public class VatanaServlet extends HttpServlet {
	Category logger = Category.getInstance(VatanaServlet.class);
	/**
	 * doGet=doPost 合并url的get和post请求
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doPost(req, resp);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.setContentType("text/html;charset=gbk");
		try {
			//调用模型
			 String viewname = VatanaController.getInstance().call(req);
			//呈现试图
			 VelocityEnginee.getInstance().show(viewname, resp.getWriter());
			
		} catch (Exception e) {
			//监控异常
			e.printStackTrace();
			try {
				//返回错误页面
				ErrorModel s = new ErrorModel(req, e);
				s.excute();
				VelocityEnginee.getInstance().show("error",resp.getWriter());
			} catch (Exception e1) {
				e1.printStackTrace();
			}	
		}
	}
}

第四步、控制器VatanaController。

/**
 * 控制器
 * @author vatana
 *
 */
public class VatanaController {
	Category logger = Category.getInstance(VatanaController.class);
	private static VatanaController ins;
	private VatanaController(){
		
	}
	public static VatanaController getInstance(){
		if(ins==null){
			ins = new VatanaController();
		}
		return ins;
	}
	
	public String call(HttpServletRequest req) throws Exception {		
		//取得请求的信息
		String actionClass = getActionClass(req);
		String actionURL = getActionUrl(req);
		String method = getMethod(req);
		// 指向类
		Class<?> cls = Class.forName("com.vatana.model."
				+ actionURL + "." + actionClass	);
		// 创建类参数
		Class<?> partypes[] = new Class[1];
		partypes[0] = HttpServletRequest.class;
		// 根据构造函数创建对象
		Constructor ct = cls.getConstructor(partypes);
		Object arglist[] = new Object[1];
		arglist[0] = req;		
		Object demo = ct.newInstance(arglist);			
		// 调用函数
		Method meth = cls.getMethod(method);
		// 取得返回值 将要跳转到哪个试图
		String viewname = (String) meth.invoke(demo);	
		return actionURL+"/"+viewname;
	}
	//取得方法名
	private String getMethod(HttpServletRequest req) {
		String method="excute";
		return method;
	}
	//取得动作名
	private String getActionClass(HttpServletRequest req) {
		String actionClass = "HelloWorld";
		
		return actionClass;
	}
	//取得动作路径
	private String getActionUrl(HttpServletRequest req) {
		String actionURL = "helloworld";
		
		return actionURL;
	}
	
}

可以看到该类并没有完成。其中URL分析部分还需完善。

其主要作用是分析url,变换成相应的动作指令,使用java的反射机制进行调用。这个思路来源于rails,在这里我想使用约定而不是xml配置文件。把一些东西限制定死了,可以集中人的注意力在处理逻辑上。

假如一个url是:http://localhost/vatana/action/method?param1=1&param2=2

那么作为控制器会自动寻找类Action的method方法,如果不写方法,默认为excute,username和password参数及其值,可以在params中找到。默认action是必须写的,如果不写,按照主页处理,将会定位到index页面,在这里我用的velocity模版的后缀是html.这样可以直接在浏览器中预览,方便设计。

第五步、一个模版类需要继承BaseModel类。然后创建一个自己的方法(或者重写excute方法)即可。

public abstract class ModelBase {
	protected HttpSession session;//取得session
	protected HashMap<String, String> params;//取得参数
	protected HttpServletRequest req;//当前的请求对象
	public ModelBase(HttpServletRequest req) {
		this.req = req;
		this.session = req.getSession();
		this.params = getParams(req);
	}
        /*默认的执行函数excute*/
	abstract public String excute();
        /**注册模版内容**/
	protected void register(String infoname, Object info) {
		VelocityEnginee.getInstance().putContext(infoname, info);
	}
	private HashMap<String, String> getParams(HttpServletRequest req) {
		HashMap<String, String> params	= new HashMap<String, String>();
		Enumeration<String> enname = req.getParameterNames();
		while (enname.hasMoreElements()) {
			String key = enname.nextElement();
			String value = req.getParameter(key);
			params.put(key, value);
		}
		return params;
	}

这样在继承类里就只需要重写excute类即可。在此,我有一点犹豫,excute方法是否应定义成抽象函数,

一个具体的模型类

public class HelloWorld extends ModelBase{
	public HelloWorld(HttpServletRequest req) {
		super(req);
	}
      /*重写excute方法*/
	@Override
	public String excute() {
                //一个操作员对象
		Operater user = new Operater();
		user.setUserid("1");
		user.setUsername("vatana");
                //注册对象到模版 
		register("user", user);
		return "index";
	}
}

注意上个类中的注册对象到模版,velocity是支持对自定义对象进行操作的。上面这个模型对应的视图模版可以这样写

<html>
<head>
	<meta http-equiv=Content-Type content="text/html;charset=gbk">
	<title>${user.username}</title>
</head>
<body> 
 你好 ${user.username},你的ID是 ${user.userid}!
</body>
</html>

 

最终呈现的结果会是

 

     你好 vatana,你的ID是1!

 

框架的大致流程就是这样子,使用vatana开发应用,只需要创建一个模版页,一个model类,就足够了。

当然这个框架还有很多需要扩充的地方,我认为url方面还有更多东西来做,url的创建,链接的管理,我打算用一个类管理超链接和form标签,这个类将会通过velocity模版展现在页面上,不需要开发人员每次都要遍历所有的模版去找要修改的内容。

这是第一版的代码,我在这里把model的包路径给定死了com.vatana.model,这是我自己用的一个路径,以后我打算做一个让此路径可以定制。但是每个项目只能做一次定制,我在这里把给模型类同名的package,这样不会导致所有的类型都集中在一个package下显的混乱。

 

为了方便开发,我打算写一段自动生成文件的程序,只需要一点点的配置,就可以得到我想要的一切--程序,视图模版。不需修改就能使用。

 

同时在这里做一下展望吧,在将来框架会更完善,集成jQuery,hibernate等更多的元素让每一个java程序员能够更敏捷开发web程序,