自己动手写web框架----1
本文可作为<<自己动手写struts–构建基于MVC的Web开发框架>>一书的读书笔记。
一个符合Model 2规范的web框架的架构图应该如下:
Controller层的Servlet就是一个全局的大管家,它判断各个请求由谁去处理。
而各个BusinessLogic就决定具体做什么。
通过上面的图,我们能看出来核心的组件就是那个servlet,它要处理所有的请求。
那么我们就先在web.xml里配置这个servlet:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>web.xml的示例</display-name>
<!--控制器-->
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>com.gd.action.GdServlet</servlet-class>
</servlet>
<!--拦截.do的请求-->
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
很简单,就是拦截所有.do的请求,交给com.gd.action.GdServlet来处理。
而我们的”大管家”至少要满足下面的格式要求。
package com.gd.action;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GdServlet extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = -5277297442646870070L;
public void init() throws ServletException {
}
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
doPost(req, res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
dodispatcher (req, res);
}
private void do_Dispatcher (HttpServletRequest req, HttpServletResponse res) {
}
public void destroy() {
}
}
咱们暂时先不考虑do_Dispatcher内部。这是最大的问题,咱们放到最后。
先解决周边问题:
1 假如,我们已经生成了对应的模型层,那么总得给传递模型层数据吧。数据来源于request,我们要是直接把request传递给某个具体的模型层,这就完全不符合Model 2规范了。因此最好的办法就是把request中的数据剥离出来形成一个对象,再把这个对象传递给具体的模型层。
这个对象是什么类型?request中的数据是以key-value的形式存储的,那就使用HashMap吧。
private Map<String, Object> fromRequestToMap(HttpServletRequest req){
try {
req.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Enumeration<String> e=req.getParameterNames();
Map<String, Object> infoIn=new HashMap<String, Object>();
while (e.hasMoreElements()) {
String paraName = (String) e.nextElement();
//为什么使用getParameterValues而不是getParameter?大家自己查资料
Object[] value=req.getParameterValues(paraName);
if (value==null) {
infoIn.put(paraName, "");
}else if(value.length==1) {
infoIn.put(paraName, value[0]);
}else {
infoIn.put(paraName, value);
}
}
return infoIn;
}
2 所有的模型层应该有个共同的接口,接收上面的infoIn,处理,然后返回数据。我们看看上面,也就能猜出返回的数据也应该是HashMap。
其接口应该是这样的:
public interface Action{
public Map<String,Object> execute(Map<String,Object> infoIn);
}
3 我们写一个最简单的逻辑模型层。
package com.gc.action;
import java.util.HashMap;
public class HelloWorldAction implements com.gd.action.Action{
/**该方法用来实现没有传入动作时要处理的内容
* @param infoIn
* @return HashMap
*/
private HashMap<String, Object> doInit(HashMap<String, Object> infoIn) {
HashMap<String, Object> infoOut = infoIn;
infoOut.put("msg", "HelloWorld");
return infoOut;
}
@Override
public HashMap<String, Object> doAction(HashMap<String, Object> infoIn) {
// TODO Auto-generated method stub
String action = (infoIn.get("action") == null) ? "" : (String)infoIn.get("action");
HashMap<String, Object> infoOut = new HashMap<String, Object>() ;
if (action.equals(""))
infoOut = this.doInit(infoIn);
else if (action.equals("show"))
//....
return infoOut;
}
}
假定这个action的功能就只是显示一个helloword。
4 具体的模型层已经有了,从控制层给模型层传递的参数类型也有了。下来就是关键的一步,也就是在控制层指定请求的模型。
假定我们我请求上面那个HelloWorldAction,最后的信息返回给index.jsp那么我们可以发出下面的请求地址:
http://localhost:8700/Struts2Demo/gc/dfd.do?logicName=HelloWorldAction&forwardJsp=index
那个dfd是个随机的字符串。
通过
String ss = req.getServletPath();
就可以获得/gc/dif.do这个字符串。
而我们的HelloWorldAction位于
package com.gc.action;
OK,反射。
Action action=null;
String servletPath=req.getServletPath();
String systemPath=servletPath.split("/")[1]; //systemPath 就是gc
String logicActionName=req.getParameter("logicName"); // logicActionName 就是HelloWorldAction
String actionPath=getActionPath(systemPath, logicActionName);
action=(Action) Class.forName(actionPath).newInstance();
Map<String, Object> infoOut=action.doAction(infoIn);
private String getActionPath(String systemPath,String actionName){
String actionPath="";
if (systemPath!=null)
actionPath="com."+systemPath+".action."+actionName;
return actionPath;
}
这样一来,我们就取得了要访问的action,并且让调用了其doAction方法。
下面的任务就返回给视图层了:
Map<String, Object> infoOut=action.doAction(infoIn);
infoOut.put("systemPath", systemPath);
req.setAttribute("infoOut", infoOut);
forwards(req, res);
private void forwards(HttpServletRequest req, HttpServletResponse res) {
// TODO Auto-generated method stub
Map<String, Object> infoOut=(Map<String, Object>) req.getAttribute("infoOut");
try {
req.getRequestDispatcher("/"+infoOut.get("systemPath")+"/jsp/"+
infoOut.get("forwardJsp")+".jsp").forward(req, res);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
再看视图层:
<%@ page contentType="text/html; charset=GBK" language="java" import="java.sql.*" errorPage="" %>
<%@ page import="java.sql.*,java.util.*,javax.servlet.*,
javax.servlet.http.*,java.text.*,java.math.*"%>
<%
HashMap infoOut = (request.getAttribute("infoOut") == null) ? new HashMap() : (HashMap)request.getAttribute("infoOut");
String msg = infoOut.get("msg") == null ? "" : (String)infoOut.get("msg");
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>采用新的框架实现HelloWorld输出</title>
<style type="text/css">
<!--
body {
background-color: #FFFFFD;
font-family: Verdana, "宋体";
font-size: 12px;
font-style: normal;
}
-->
</style>
</head>
<body leftmargin="0" topmargin="0">
<form name="form1" action="/myApp/do" method="post">
<H1><%=msg%><H1>
</form>
</body>
</html>
我们看看效果:
似乎还不错
再看看我的项目工程图:
这一节,我们很粗略地写了一个web框架,当然这个框架还很丑陋,就能显示个helloworld。我们在下一节在对他进行进一步的完善。
自己动手写web框架----1的更多相关文章
- 自己动手写web框架----2
在上一节,我们自己写的web框架,只能运行显示一个HelloWorld.现在我们对其进行一次加工,让他至少能运行一个登陆程序. 首先看login.jsp <%@ page contentType ...
- (新)自己动手写ORM框架(1)-增删查改的使用
之前写过一个系列文章自己动手写ORM框架,经过在多个项目的中的使用,对这套代码进行了许多改进,下面是使用方法: 新增学员信息代码预览: DBHelper db = DBHelper.getInstan ...
- 自己动手写Spring框架--IOC、MVC
对于一名Java开发人员,我相信没有人不知道 Spring 框架,而且也能够轻松就说出 Spring 的特性-- IOC.MVC.AOP.ORM(batis). 下面我想简单介绍一下我写的轻量级的 S ...
- 自己动手写Android框架-数据库框架
大家在工作中基本上都有使用到数据库框架 关系型:ORMLite,GreenDao 对象型:DB4O,Perst 这些数据库用起来都非常的简单,对于我们Android上来说这些数据库足够我们使用了,但是 ...
- 自己动手做Web框架—MVC+Front Controller
在我前面一篇博文<逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎>发表之后,很多人关心,脱离了之后怎么办?那么这可以说是它的续篇了. 同时,这也是eLiteWeb开源软件的一 ...
- 手写web框架之加载Controller,初始化框架
1,加载Controller 我们需要创建 一个ControllerHelper类,让它来处理下面的逻辑: 通过ClassHelper我们可以获取所有定义了Controller注解的 ...
- 手写web框架之实现依赖注入功能
我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...
- 自己动手写ORM框架
提起ORM框架,大家都很熟悉,网上流行的ORM框架有很多,其中出名的有一些,不出名的更是数不胜数. 下面是自己实现的一个简单的ORM框架,实现了常用的增删查改功能,供大家研究ORM实现原理. 功能描述 ...
- [置顶] 自己动手写Web容器之TomJetty之六:动态页面引入
传送门 ☞ 1.Web服务内功经脉 传送门 ☞ 2.让服务动起来 传送门 ☞ 3.掀起请求盖头来 传送门 ☞ 4.静态页面起步 传送门 ☞ 5.包装请求参数 在上一节,我们已经完成了TomJetty服 ...
随机推荐
- Android服务——Service
服务 Service 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件.服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行. 此外,组件可以绑定到服务,以与之进行 ...
- Android简易实战教程--第四十八话《Android - Timer、TimerTask和Handler实现倒计时》
之前本专栏文章中的小案例有写到:第三十九话<Chronometer实现倒计时> 以及使用异步实现倒计时:第三十三话< AsyncTask异步倒计时> 本篇文章 结合Timer. ...
- 拾遗与填坑《深度探索C++对象模型》3.2节
<深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...
- linux网络编程之一-----多播(组播)编程
什么是多播 组播(Multicast)是网络一种点对多(one to many)的通信方式,通过报文复制完成网络中一台server对应多台接收者的高效数据传 送.对其形象的比喻就是类似于广播电台和电视 ...
- Android简易实战教程--第四十四话《ScrollView和HorizontalScrollView简单使用》
一.ScrollView 由于手机屏幕的高度有限,当普通布局放不下现实和的内容时,ScrollView视图(滚动视图)就会派上用场,因为数据可以往下滚动显示. 二.HorizontalScrollVi ...
- ejabberd编译更新脚本
ejabberd编译更新脚本 (金庆的专栏 2016.8) 用rebar编译ejabberd源码,然后复制编译所得beam文件到ejabberd安装目录, 调用ejabberdctl热更新. call ...
- Java之继承深刻理解
1.关于私有成员变量 无论父类中的成员变量是私有的.共有的.还是其它类型的,子类都会拥有父类中的这些成员变量.但是父类中的私有成员变量,无法在子类中直接访问,必须通过从父类中继承得到的protecte ...
- Android缩放动画
Android缩放动画 核心方法 public void startAnimation(Animation animation) 执行动画,参数可以是各种动画的对象,Animation的多态,也可以是 ...
- leetcode 37. Sudoku Solver 36. Valid Sudoku 数独问题
三星机试也考了类似的题目,只不过是要针对给出的数独修改其中三个错误数字,总过10个测试用例只过了3个与世界500强无缘了 36. Valid Sudoku Determine if a Sudoku ...
- Centos中git的安装
CentOS的yum源中没有git,只能自己编译安装,现在记录下编译安装的内容,留给自己备忘. 确保已安装了依赖的包 yum install curl yum install curl-deve ...