自己动手写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。我们在下一节在对他进行进一步的完善。

时间: 2024-11-08 03:28:40

自己动手写web框架----1的相关文章

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

在上一节,我们自己写的web框架,只能运行显示一个HelloWorld.现在我们对其进行一次加工,让他至少能运行一个登陆程序. 首先看login.jsp <%@ page contentType="text/html; charset=UTF-8" language="java" import="java.sql.*" errorPage="" %> <%@ page import=" java.u

《自己动手写开源框架10》:Web界面快速开发实践

下面是一些常用的链接,供大家使用: GIT地址:https://git.oschina.net/tinyframework/tiny问题报告:https://git.oschina.net/tinyframework/tiny/issues更多内容,请看本人博客,不一样的内容,一样的精彩! 在展示过程的同时,会把相关的知识做一个充分的介绍 .一.寻找网站模板 要做网站,不能没有模板,自己不会做网页设计,咋办?问谷歌找百度呗,找了一阵,看到下面这个模板不错,就它了. http://www.toop

gsweb —— 自动动手用golang写WEB框架

最近个人项目需要用到WEB框架,考虑系统其它部分的配合首选开发语言是golang.首先go语言有很多现成WEB框架可用,例如:Beego:看了下Beego发现实现其实挺简单的,抱着学习的态度决定干一次重造轮子的事情.看看在没有任何其它WEB框架开发经验的前提下,只依据WEB应用的特征来重头设计WEB框架会是什么样子.这样的经历一定非常有趣,后续会在BLOG持续更新这个项目的进度以及一些设计上的思考:

《开源框架那点事儿20》:自己动手写前端框架

曾经发表过一篇文章:TinyAdmin前端展现框架.其在线演示路径为:http://www.tinygroup.org/tinyadmin/.应该说有很多人还是感觉兴趣的,可是因为这个是基于SmartAdmin框架改写的,尽管我们自己买了SmartAdmin的授权,可是广大用户假设要用的时候,就会有授权相关的问题,这会大大影响一些人的使用决策--尤其是会再发行的朋友. 再一个原因是SmartAdmin初看不是不错的.可是实际用起来.里面的问题比較多.对IE8基本上能够说是不兼容,尽管我们努力进行

自己动手写RPC框架到dubbo的服务动态注册,服务路由,负载均衡功能实现

RPC即远程过程调用,它的实现方式有很多,比如webservice等.框架调多了,烦了,没激情了,我们就该问自己,这些框架的作用到底是什么,来找回当初的激情. 一般来说,我们写的系统就是一个单机系统,一个web服务器一个数据库服务,但是当这单台服务器的处理能力受硬件成本的限制,是不能无限的提升处理性能的.这个时候我们使用RPC将原来的本地调用转变为调用远端的服务器上的方法,给系统的处理能力和吞吐量带来了提升. RPC的实现包括客户端和服务端,即服务的调用方和服务的提供方.服务调用方发送rpc请求

自己动手写javaEE框架-为jqgrid换换皮肤然后加到我的框架里

软件151 苏垚 今天让我倒腾半天的居然不是写我的javaEE框架,而是更换jqgrid的皮肤.我是相当的讨厌jqgrid的默认皮肤,它总让我想起一直想学而都没学过的EXTJS,看多了那种淡蓝色的皮肤太多了绝对视觉疲劳,所以这篇博文就从jqgrid换肤讲起吧,这个过程在网络上找到的资料比较少,因此我今天的博文还是很有实用价值的.不废话了,下面开始吧! 首先我们在浏览器地址栏里填入地址:http://www.trirand.com/blog/?page_id=6,这是jqgrid的下载界面,如下图

第一招:自己动手写HTTP框架介绍

我相信很多人都会质疑:网上已经有那么多开源的HTTP框架,android-async-http已经很成熟了,Stay你再来讲而且还收费有意义么. Stay在这里统一作答. HTTP作为所有app的必备功能,我觉得有必要来讲. 开源框架授之以鱼,我希望能做到授之以渔. 看看android-async-http里的issues,如果你也碰到变态需求,你是否会改,而不是等待作者帮你解. 每个人的理解能力不一样,可能看不懂源码,我希望把骨架拎出来,一个个讲解,让你弄懂它的设计思想. 可能就算你看懂了代码

自己动手写web服务器一(浏览器的访问信息)

要协议一个web服务器,需要了解http协议,下面我们来看一下当浏览器请求网张的时候向web服务器发送的数据,我使用的是ubuntu 中telent展现一个下过程. 我需要一个简单的网站来演示一下,我装了一个apache.来完成成这个过程.下面为过程展示. 其实,访问一个网站就是浏览器web服务器指定端口发送信息,然后,web服务器向浏览器发送网页的内容, 1.使用telnet连接网站 2.输入请求的页面. GET  /   HTTP/1.0 或者 GET /index.html  HTTP/1

转:自己动手写插件框架(3)

转自:http://www.devbean.net/2012/03/building-your-own-plugin-framework-3/ 编程语言的支持 在前面的章节中,我们已经了解到,如果你能够使用编译器令应用程序和插件的虚表匹配,那么就可以保持 C++ 虚表级别的兼容性:或者你可以使用 C 级别的兼容性,然后就能使用不用的编译器去构建系统,但其限制在于你只能编写纯 C 应用.这样的话,你就不能够使用前面我们在例子 IActor 中看到的那种优雅的 C++ 接口. 纯 C 实现 在纯 C