通过MVC模式将Web视图和逻辑代码分离

本文为原创,如需转载,请注明作者和出处,谢谢!


   
MVC模式(Model-View-Controller)常被用在Web程序中。如Struts框架就是一个基于MVC模式的Web框架。所谓MVC模式,就是将视图(也就是客户端代码,包括html、javascript等)和模型(和数据库及业务逻辑相关的Java代码)分开。并通过控制器将两者联系起来。这样做的好处可以使客户端开发人员和服务端开发人员的工作尽量分开,以使他们之间的干扰降到最低。

    虽然象Struts这样的框架可以很好地Model和View分离。但是对于客户端的代码,仍然存在着一定的视图和逻辑混合的现象。如下面的代码所示:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script type="text/javascript" >
        function fun1(obj) {  }
        function fun2() { }
        </script>        
    </head>
    <body>
        <input type="button" value="按钮1 " onclick="fun1(this)"/>
        <input type="button" value="按钮2 " onclick="fun2()"/>
         
    </body> 
</html>

    从上面的代码可以看出,html代码和javascript代码都混在了同一个html文件中。在一般情况下,客户端的界面是由美工设计的,而对于javascript代码,美工一般是不参与实现的。这些代码一般也应属于业务逻辑代码的一部分,虽然它们都在客户端运行,但可能也会处理一定的业务逻辑,如验证数据的正确性。尤其在AJAX应用中,在客户端还会通过http协议从服务端获取数据。这样就和业务逻辑绑定得更紧了。因此,如果将用于描述界面的html和用于处理业务逻辑的javascript(渲染界面的javascript除外)混在一起,非常不利于团队中负责这两方面的人员进行协调。

    最好的可能就是将这些javascript代码从html代码中分离。也许有很多人马上就会想到,将这些javascript放到.js文件中,然后使用<script>标签引用一下就ok了。代码如下:

fun.js文件

function fun1(obj) { ... }

function fun2() {... }


index.html文件

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="fun.js">
</script>
    </head>
    <body>
        <input type="button" value="按钮1 " onclick="fun1(this)"/>
        <input type="button" value="按钮2 " onclick="fun2()"/>
         
    </body> 
</html>

    虽然上面的代码从某种程度上达到了视图和逻辑分离的效果。但仍然有着一定的联系。我们可以看到,两个<input>标签的onclick事件不还是引用着fun1和fun2函数吗!其实美工人员是不关心这两个函数到底是做什么的,甚至并不需要知道它们的存在。那么是否有更高的方法呢?答案当然是肯定的,就是通过动态的方式指定onclick事件,而这一切美工人员是完全没有感觉的。

    我们在文章的开头提到了MVC模式。其实在客户端也存在着一个MVC体系结构。我们可以将视图(V)看成是描述界面的html、css和javascript代码,而模型(M)可以看成是处理业务逻辑的javascript代码,而控制器(C)就是将这两类代码连接起来的代码(一般也是javascript代码)。

    在本文中给出了一个小例子来演示一下如何通过动态的方法将V和M分离。这个例子是通过<div>实现的10个小方块,点击其中的某一个,会将相应的数字追加到下方的文本框架中,并且加入了一些用javascript实现的效果,如以一定间隔随机更新方块和数字的颜色,直接在文本框中输入数字后,相应的文本框和数字的颜色也会随机发生变化。界面效果如图1所示。

                                         图1

    下面先来实现View。先看看如下的代码:

 numberKeys.html

  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  <html>
      <head>
          <title></title>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <link  rel="stylesheet"  type="text/css" href="my.css"/>
          <script type="text/javascript" src="addevents.js">
          </script>

      </head>
      <body>
          <input id ="changeColor" type="button" value="开始变换颜色" />
          <br/><br/>

          <div id ="nubmerKeys" class="numberKeys"  >    

          </div> 
          <br/><br/>
          <br/><br/>
          <input id="numbers" type="text" size="80"/>

      </body> 
  </html>    

    从上面的代码可以看出,除了一些html代码外,没有任何和业务逻辑有关的javascript代码。但使用<script>引用了一个叫addevents.js的文件。在这个文件中将为这个程序添加相应的逻辑代码,也就是说,这个文件相当于MVC中的M和C。

    动作装载事件是通过window的onload事件完成的,代码如下:

window.onload = onLoad;  // 为onload指定事件函数

function onLoad()
{
    var text = document.getElementById("numbers");
    if(text)
    {      
        text.onkeyup = onKeyup;  // 为文本框指定onkeyup事件
    }
    var button = document.getElementById("changeColor");
    if(button)
    {
        button.onclick = stopAndStartTimer;  // 为按钮指定onclick事件
    }  
    addButton();  // 用于在<div>中加入10个<div>标签作为小方块,并指定onclick事件
}

    下面先来看一下addButton函数是如何实现的,代码如下:

function addButton()
{
    var div = getNumberKeysDiv();  // 获得id为nubmerKeys的<div>标签

    try
    {
        if(div)
        {
            // 删除<div>中的所有子元素
            for(var i = div.childNodes.length - 1; i >= 0; i--)
            {
                try
                {   
                    div.removeChild(div.childNodes[i]);
                }
                catch(e)
                {                    
                }            
            } 
            // 为<div>标签加10个子<div>标签
            for(var i = 0; i < 10; i++) 
            {
                var button = document.createElement("div"); 
            
                button.className = "button";        
                button.style.left = i * 61 + "px";
                button.style.backgroundColor = getRandomColor();
                button.style.border="solid 1px";
                button.style.textAlign = "center";
                button.style.lineHeight = "50px";      
                button.style.color = getRandomColor(); 
                        
                button.onclick = buttonOnClick;
            
                div.appendChild(button);               
                button.innerHTML  ="<b>" +i + "</b>";                
            }            
        }
    } 
    catch(e)
    { 
    }            
}

    addButton函数的基本实现原理是先将<div>中的所有元素删除,再向其中加入10个<div>标签。在addButton函数中有几个关键的函数需要讲解一下。

getNumberKeysDiv函数

    这个函数用于获得叫numberKeys的<div>标签,实现代码如下:

function getNumberKeysDiv()
{
    var divs = document.getElementsByTagName("div");
    
    if(divs)
    {
        for(var i = 0; i < divs.length; i++)
        {
            var div = divs[i];
            
            if(div.className.toString().indexOf("numberKeys", 0) > -1)
            {  
                return div;                
            }
        }
    }
}

    这个函数并不是直接通过<div>的id找到这个<div>,而是通过<div>的class属性,这样可能更灵活,因为如果通过id找<div>,就必须要求美工必须将这个<div>命名为numberKeys,而如果通过查找包含numberKeys的class属性的<div>会对美工的限制更少。因为,只有这个<div>才会使用css中的numberKeys。

getRandomColor方法

这个方法获得了一个随机的演示,返回了字符串类型,格式#FFFFFF。实现代码如下:

function getRandomArbitary(min, max)
{    
    return Math.round(Math.random() * (max - min) + min);
}
function getRandomColor()
{
    var red = getRandomArbitary(0, 255).toString(16);    
    var green = getRandomArbitary(0, 255).toString(16);
    var blue = getRandomArbitary(0, 255).toString(16);
    if(red.length == 1) red = "0" + red;
    if(green.length == 1) green = "0" + green;
    if(blue.length == 1) blue = "0" + blue;
    
    return "#" + red.toString(16) + green.toString(16) + blue.toString(16);
}

    getRandomColor通过getRandomArbitary函数获得了三个十进制的随机数(0-255),并将其转换为16进制,并返回最终结果。

buttonOnClick函数

这个函数是<div>标签的onclick事件函数,实现代码如下:

function buttonOnClick()
{
    var text = document.getElementById("numbers");    
    if(typeof this.innerText == "#ff0000")
        text.value = text.value + this.textContent;    
    else 
        text.value = text.value + this.innerText;    
    this.style.backgroundColor = getRandomColor();              
    this.style.color =  getRandomColor(); 
    
}

    这个函数实现很简单,它的功能是将相应<div>标签中的数字追加到numbers文本框中。只是考虑了firefox和ie的不同。在firefox中,获得<div>中的文本要使用textContext,而在ie中要使用innerText。最后再将当前点击的<div>和数字的颜色再次变换。

    到现在为止,还有两个事件函数代码没有给出,这两个事件函数是onKeyup和stopAndStartTimer。

    onKeyup函数

    当numbers文本框输入一个字符后,发生这个事件,实现代码如下:

function onKeyup()
{
    var value = this.value;
    if(value.length == 0) return;
    var i = value.toString().substr(value.length - 1, 1); 
    if(isNaN(i) == false)
    {    
        var div = getNumberKeysDiv();    
        if(div)
        {
            var button = div.childNodes[i];
            button.style.backgroundColor = getRandomColor();              
            button.style.color =  getRandomColor(); 
         
        }
    }
}

    这个函数的实现代码也很简单。只是根据用户在文本框中输入的数字来找到相应的<div>标签,并再次随机变换<div>背景和数字的颜色。

stopAndStartTimer函数

这个函数是用来控制定时器的,如果启动定时器,浏览器会每隔3秒重新使<div>随机变化一次颜色。实现代码如下:

var time;

function stopAndStartTimer()
{
    if(this.value.toString().indexOf("停止",0) > -1)
    {
        this.value = "开始变换颜色";
        clearInterval(time);            
    }
    else
    {
        this.value = "停止变换颜色";
        time = setInterval(onLoad, 3000);
    }
}

    从上面给出的代码可以看出,在View层,除了<script>引用了一个javascript文件外,并未涉及任何和逻辑有关的代码。而设计界面的美工也并不知道开发人员会为<div>及其他的按钮和文本框添加什么动作。而美工要做的是调整和界面有关的东西,如颜色,位置,分割等。只要使用<script>引用了这个js文件,就可以很容易加入相应的动作,而要将这些动作去掉,删除或注释掉这个<script>标签即可。

    尤其要提一下<div>标签,美工在设计界面时可以向这个<div>标签添加任何子元素。而在加入addevents.js后,程序会自动将由美工向<div>标签中的加入的内容都删除,而加入由业务逻辑需要的元素。这样美工用来设计界面的元素就不会影响开发人员需要加入的和业务逻辑有关的元素了。

    根据上面的代码不难看出,numberKeys.html属于视图层,所有的事件函数属性模型层,而其他的javascript代码都属性控制器(Controller)。

国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

时间: 2024-09-30 20:23:44

通过MVC模式将Web视图和逻辑代码分离的相关文章

Apache Geronimo和Spring框架,第6部分:Spring MVC:使用Web视图技术

简介:本教程是系列教程(共六部分)的最后一部分,向您展示了如何利用 Spring 框架来使用 JavaServer Page(JSP).Velocity.Tile 和 PDF 导出功能.您将用 Model-View-Controller (MVC)中的 V 做试验,即 Spring MVC 中内置的各种 Web 视图.通过对 Spring MVC 所支持的各种视 图技术的全面介绍,您将看到在整个系列教程中构建的样例电话本应用程序中实现这些技术有多么轻松. 开始之前 本系列教程适合于需要了解 Sp

表示代码与逻辑代码分离

代码分离 <%@ Page Inherits="MyCodeBehind" Src="c2.vb" %> There is a nice section in the quickstart docs on this topic also. Click here to read up on it! Here is the code This example uses the following MS-SQL Server 7.0 database Stor

JSP使用Servlet作为控制器实现MVC模式实例详解_JSP编程

本文实例讲述了JSP使用Servlet作为控制器实现MVC模式的方法.分享给大家供大家参考.具体如下: 一.目标: ① 初步理解MVC模式: ② 掌握Servlet的编写: ③ 使用MVC模式完成登录功能. 二.主要内容: ① 分析JSP+JavaBean模式存在的问题,并介绍JSP+JavaBean+Servlet模式,以及和MVC模式的关系: ② 通过简单实例介绍Servlet的编写.配置和运行: ③ 采用Servlet完成登录功能的控制. 1. JSP+JavaBean这种模式存在的问题?

整合Java6脚本、Groovy实现动态MVC模式

一个有弹性的和动态的开发环境正在受到前所未有的关注,甚至连脚本语言也显现出这方面的特性,这也正是我们所需要的,也就是说,我们永远需要建立易维护,并且可满足我们需求的应用程序.如果我们要想使用脚本语言参与进来,我们应该考虑一下Java SE 6所提供的一个新的脚本API:一个与语言无关的允许开发人员在Java代码中使用脚本语言的框架.使用这套新API,我们不仅可以利用脚本语言的特性,而且还能使用很多和Java相关器工具. 在本文中,我们提供了一个实例,这个实例将尽可能体现这套API的特性.并且使用

Swing程序最佳架构设计—以业务对象为中心的MVC模式(转)

  前言: 我打算写一系列关于Swing程序开发的文章.这是由于最近我在做一个Swing产品的开发.长期做JavaEE程序,让我有些麻木了.Swing是设计模式的典范,是一件优雅的艺术品,是一件超越时代的产品! 有机会作Swing软件的开发,让我非常有感觉! 呵呵,希望有机会能够用Java3D编写软件,那种感觉一定更棒! Java和Swing都是杰作.我这个人对别人一向很挑剔的,能够得到我由衷地赞誉,可想而知它们有多优秀了.奇怪的是,它们居然一直都无法占领桌面市场.有人说这是技术的原因.我认为这

《Spring MVC学习指南(第2版)》——第2章 模型2和MVC模式 2.1模型1介绍

第2章 模型2和MVC模式 Java Web应用开发中有两种设计模型,为了方便,分别称为模型1和模型2.模型1是以页面中心,适合于小应用开发.而模型2基于MVC模式,是Java Web应用的推荐架构(简单类型的应用除外). 本章将会讨论模型2,并展示4个不同示例应用.第一个应用是一个基本的模型2应用,采用Servlet作为控制器:第二个应用也是模型2应用,但采用了Filter作为控制器:第三个应用引入了验证控件来校验用户的输入:最后一个应用则采用了一个自研的依赖注入器.在实践中,应替换为Spri

MVC模式概述

    MVC是三个单词的缩写,分别为:模型(Model),视图(View)和控制Controller).MVC模式的目的就是实现Web系统的职能分工.      Model层实现系统中的业务逻辑,通常可以用JavaBean或EJB来实现.     View层用于与用户的交互,通常用JSP来实现.      Controller层是Model与View之间沟通的桥梁,它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作. MVC模式的

基于MVC模式的Struts框架概述

作者:yarshray   关键字: Java  J2EE  MVC  JSP  Servlet  MVC  Struts 内容简介:        MVC设计模式成为了目前十分流行的一种设计方法.它是一种软件的设计方法模式.并且被大量的开发和实践所证明.因此本文通过介绍Struts框架这种已经实现了MVC模式的软件构件框架了讨论该模式的优势和如何投入到软件开发中去.        本文内容注重理论和实践相结合,比较系统的从多层设计方式到分布式软件开发中所用到的技术,从而切入目前Sun公司退出的

基于MVC模式的Struts框架研究与应用

摘要: Struts框架具有组件的模块化,灵活性和重用性的优点,同时简化了基于MVC的web应用程序的开发.本文讨论了Struts框架实现MVC模式的原理与方法,给出了一个具体的应用实例. 分布式企业应用软件结构复杂.涉及多种技术,对设计开发人员提出了很高的要求.在此情况下,运用设计模式――可复用的设计方案进行软件的设计开发十分必要.MVC模式已被证明是一种成功的软件设计模式,本文主要讨论了一种实现MVC模式的应用框架――Struts,并通过一个实例展示了Struts框架实现MVC模式的方法.