本文可作为<<自己动手写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的更多相关文章

  1. 自己动手写web框架----2

    在上一节,我们自己写的web框架,只能运行显示一个HelloWorld.现在我们对其进行一次加工,让他至少能运行一个登陆程序. 首先看login.jsp <%@ page contentType ...

  2. (新)自己动手写ORM框架(1)-增删查改的使用

    之前写过一个系列文章自己动手写ORM框架,经过在多个项目的中的使用,对这套代码进行了许多改进,下面是使用方法: 新增学员信息代码预览: DBHelper db = DBHelper.getInstan ...

  3. 自己动手写Spring框架--IOC、MVC

    对于一名Java开发人员,我相信没有人不知道 Spring 框架,而且也能够轻松就说出 Spring 的特性-- IOC.MVC.AOP.ORM(batis). 下面我想简单介绍一下我写的轻量级的 S ...

  4. 自己动手写Android框架-数据库框架

    大家在工作中基本上都有使用到数据库框架 关系型:ORMLite,GreenDao 对象型:DB4O,Perst 这些数据库用起来都非常的简单,对于我们Android上来说这些数据库足够我们使用了,但是 ...

  5. 自己动手做Web框架—MVC+Front Controller

    在我前面一篇博文<逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎>发表之后,很多人关心,脱离了之后怎么办?那么这可以说是它的续篇了. 同时,这也是eLiteWeb开源软件的一 ...

  6. 手写web框架之加载Controller,初始化框架

    1,加载Controller     我们需要创建 一个ControllerHelper类,让它来处理下面的逻辑:      通过ClassHelper我们可以获取所有定义了Controller注解的 ...

  7. 手写web框架之实现依赖注入功能

    我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...

  8. 自己动手写ORM框架

    提起ORM框架,大家都很熟悉,网上流行的ORM框架有很多,其中出名的有一些,不出名的更是数不胜数. 下面是自己实现的一个简单的ORM框架,实现了常用的增删查改功能,供大家研究ORM实现原理. 功能描述 ...

  9. [置顶] 自己动手写Web容器之TomJetty之六:动态页面引入

    传送门 ☞ 1.Web服务内功经脉 传送门 ☞ 2.让服务动起来 传送门 ☞ 3.掀起请求盖头来 传送门 ☞ 4.静态页面起步 传送门 ☞ 5.包装请求参数 在上一节,我们已经完成了TomJetty服 ...

随机推荐

  1. GDAL C#版本 "安全透明方法"问题解决方案

    之前写过一篇关于再C#中调用GDAL库出现OSGeo.GDAL.GdalPINVOKE"的类型初始值设定项引发异常的解决方案,博客地址见下: http://blog.csdn.net/lim ...

  2. 使用Kubernetes需要注意的一些问题(FAQ of k8s)

    本篇文章并不是介绍K8S 或者Docker的,而仅仅是使用过程中一些常见问题的汇总. 重启策略:http://kubernetes.io/docs/user-guide/pod-states/, 对于 ...

  3. Compass 更智能的搜索引擎(3)--高亮,排序,过滤以及各种搜索

    要想使得一个搜索系统更加的完美,查询精确度和页面显示算是其中比较重要的两个方面.今天,我们就来谈谈怎么使得我们的搜索系统更加的完美. 关于分词 下载地址 配置 关于高亮 关于排序 原理 冗余字段 使用 ...

  4. 使用Xpath定位元素(和元素定位相关的Xpath语法)

    本文主要讲述Xpath语法中,和元素定位相关的语法 第一种方法:通过绝对路径做定位(相信大家不会使用这种方式) By.xpath("html/body/div/form/input" ...

  5. Studio 一些使用

    1,配置: W:\android_tools\AndroidStudio2.1.3_SDK\android-studio-ide-141.2456560-windows\android-studio\ ...

  6. 使用 纯JQuery 进行 表单 验证

    对于JavaScript而言,进行表单数据的验证可谓是很有必要的,而且一般我们都会在网页上先进行一下表单验证,然后服务器端再次进行验证,来确保用户提交数据的准确性.下面就来分享一个JQuery实现的表 ...

  7. x264源代码简单分析:熵编码(Entropy Encoding)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  8. javascript之内置函数

    1.常规函数 (1)alert函数:显示一个警告对话框,包括一个OK按钮. (2)confirm函数:显示一个确认对话框,包括OK.Cancel按钮. (3)escape函数:将字符转换成Unicod ...

  9. iOS下JS与OC互相调用(四)--JavaScriptCore

    前面讲完拦截URL的方式实现JS与OC互相调用,终于到JavaScriptCore了.它是从iOS7开始加入的,用 Objective-C 把 WebKit 的 JavaScript 引擎封装了一下, ...

  10. Java中Excel导入功能实现、excel导入公共方法_POI -

    这是一个思路希望能帮助到大家:如果大家有更好的解决方法希望分享出来 公司导入是这样做的 每个到导入的地方 @Override public List<DataImportMessage> ...