当前位置: 代码迷 >> ASP >> 原创MVC方式ASP框架-Javascript版本
  详细解决方案

原创MVC方式ASP框架-Javascript版本

热度:504   发布时间:2012-11-23 22:54:33.0
原创MVC模式ASP框架-Javascript版本
框架说明:
1.框架还没有完全开发好,完善了模板解析的主要功能,不过我在这里会不定期的更新直至整个框架的完成。
2.框架统一采用Javascript脚本语言开发,因为本人还是不习惯VBScript,实在抱歉。
3.框架采用MVC模式,动态生成缓存文件以供系统调用。
4.框架借鉴了PHP框架实现思路。
语法说明:
1.不再使用关键字var来定义变量了,而是采用$来直接定义变量,比如$sitename,目的是和客户端有所区分。
2.常量采用全大写的格式,比如$_SGLOBAL
3.系统频繁采用静态对象,比如$_SGLOBAL,$_SC,$_SCONFIG...目的是模拟PHP的关联数组,个人感觉它非常好用且结构清晰。
好了,暂时就这些,以后如有其它约定还会在这里补充的。

MVC系统一定有它的框架结构,我的框架结构如下:
./
  admin - 后台管理目录
  data - 系统缓存,数据库备份目录
       /tpl_cache 模板生成的缓存都在这里了
  image - 图像目录
  source - 核心文件目录
  template - 模板目录
             /default 系统默认模板都在这里了(这个是必须要有的目录)
                        /image 模板相关的图像目录
             /blue 自定义模板目录(自己都可以随意定义,可能还有好多其他的模板目录)
             /...(其它的一些自定义模板目录就不一一举例了,具体格式可以参照default模板)
common.asp 网站公共文件
config.asp 网站配置文件
index.asp 网站入口文件
好,框架结构定下来了,不会有大的变动,只会有很细微的变动,也会在这里随时更新的。

下面我先把完成的一些代码贴出来。
common.asp - 网站公共文件
<%@LANGUAGE="JAVASCRIPT" CODEPAGE="936"%>
<%
IN_RICHMOND = true;
X_VER = '1.0';
X_RELEASE = '20090401';

FSO = Server.CreateObject('Scripting.FileSystemObject');
XMLHTTP = Server.CreateObject("Microsoft.XMLHTTP");
STREAM = Server.CreateObject("ADODB.STREAM");

$_SGLOBAL = {

};

%>
<!--#include file = './config.asp'-->
<!--#include file = './source/function_common.asp'-->
<!--#include file = './source/function_template.asp'-->
<!--#include file = './source/class_database.asp'-->
<!--#include file = './source/class_data_grid.asp'-->
<%

//这里添加更多代码

%>
大家可以看到,首先是定义了网站的一些常量,其次包含了一些核心文件,比如公共函数库、模板、数据库、分页,后续可能还会加入更多这样的类库。

config.asp - 网站配置文件
<%
/**
* page build by Richmond 09-04-06
*/

//配置参数
$_SC = {
        dbhost: '(local)',//服务器地址
        dbuser: 'Richmond',//用户
        dbpw: '******',//密码
        dbname: 'database'//数据库
        //...
};

$_SCONFIG = {
        template: 'default'
        //...
};

%>
配置文件就是定义静态对象来存储了。

./source/function_common.asp 网站公共函数库(后续会不断的更新)
<%
/**
* page build by Richmond 09-04-06
*/

//测字符串实际长度
String.prototype.tlength = function(){
        $arr = this.match(/[^\x00-\xff]/ig);
        return this.length + ($arr == null ? 0 : $arr.length);
}

//字符串左取
String.prototype.left = function($num, $mode){
        if(!/\d+/.test($num)) return(this);
        $str = this.substr(0, $num);
        if(!$mode) return $str;
        $n = $str.tlength()-$str.length;
        $num -= parseInt($n/2);
        return this.substr(0, $num);
}

//字符串右取
String.prototype.right = function($num, $mode){
        if(!/\d+/.test($num)) return(this);
        $str = this.substr(this.length-$num);
        if(!$mode) return $str;
        $n = $str.tlength()-$str.length;
        $num -= parseInt($n/2);
        return this.substr(this.length-$num);
}

//字符串包含
String.prototype.get_count = function($str, $mode){
        return eval('this.match(/(' + $str + ')/g' + ($mode ? 'i' : '') + ').length');
}

//字符串去除两端空字符
String.prototype.trim = function(){
        return this.replace(/(^\s*)|(\s*$)/g,'');
}
String.prototype.ltrim = function(){
        return this.replace(/(^\s*)/g, '');
}
String.prototype.rtrim = function(){
        return this.replace(/(\s*$)/g, '');
}

function empty($obj) {
        return !(String($obj) != '' && String($obj) != 'undefined');
}

function is_array($obj) {
        return $obj.constructor == Array;
}

//判断字符串是否存在
function strexists($haystack, $needle) {
        return $haystack.indexOf($needle) != -1;
}

//判断文件是否存在
function file_exists($name) {
        if(FSO.FileExists(Server.MapPath($name))) {
                return true;
        } else {
                return false;
        }
        return false;
}

//判断目录是否存在
function folder_exists($path) {
        if(FSO.FolderExists(Server.MapPath($path))) {
                return true;
        } else {
                return false;
        }
        return false;
}

//读取文件内容
function sreadfile($name) {
        if(!file_exists($name)) {
                return false;//文件不存在
        } else {
                $result = FSO.OpenTextFile(Server.MapPath($name)).ReadAll();
                if($result == '') return false;//文件为空
                return $result;
        }
        return false;
}

//写入文件
function swritefile($filename, $writetext) {
        $op = FSO.OpenTextFile(Server.MapPath($filename), 2, true);
        if($op.Write($writetext)) {
                return true;
        } else {
                //这里可以是写入日志
                return false;
        }
}

//SQL ADDSLASHES
function saddslashes($string) {
       
}

//取消HTML代码
function shtmlspecialchars($string) {
        $unallowed = {
                '&': '&',
                '"': '"',
                '<': '<',
                '>': '>'
        };
        for($p in $unallowed){
                 $string = $string.replace(eval('/'+$p+'/g'), $unallowed[$p]);
        }
        return $string;
}

//数据库连接
function dbconnect() {
       
}

//获取到表名
function tname($name) {
       
}

//对话框
function showmessage() {
       
}

//判断提交是否正确
function submitcheck($val) {
       
}

//检查是否登录
function checklogin() {
       
}

//模板调用
function template($name) {
        if(strexists($name, '/')) {//自定义路径
                $tpl = $name;
        } else {//系统配置路径
                $tpl = 'template/'+$_SCONFIG['template']+'/' + $name;
        }
        $objfile = './data/tpl_cache/'+$tpl.replace(/\//g,'_')+'.asp';
        if(!file_exists($objfile)) {
                parse_template($tpl);//解析输出到模板
        }
        return $objfile;
}

%>

最关键的是模板解析文件./source/function_templace.asp,可以这么说,网上没有找到一个很合适的模板解析文件,只有实现思路,代码都写得非常乱,没有一个很好的体系,请看我的代码:
<%
/**
* page build by Richmond 09-04-06
*/

$_SGLOBAL['i'] = 0;
$_SGLOBAL['block_search'] = new Array();
$_SGLOBAL['block_replace'] = new Array();

function parse_template($tpl) {
   
        //包含模板
        $_SGLOBAL['sub_tpls'] = new Array($tpl);
       
        $tplfile = './'+$tpl+'.htm';
        $objfile = './data/tpl_cache/'+$tpl.replace(/\//g,'_')+'.asp';
       
        //read
        if(!file_exists($tplfile)) {
                $tplfile = $tplfile.replace('/'+$_SCONFIG['template']+'/', '/default/');
        }
        $template = sreadfile($tplfile);
        if(empty($template)) {
                Response.Write('Template file : '+tplfile+' Not found or have no access!');
                Response.End();
        }
       
        //模板
        $template = $template.replace(/\<\!\-\-\{template\s+([a-z0-9_\/]+)\}\-\-\>/ig, readtemplate);
        //处理子页面中的代码
        $template = $template.replace(/\<\!\-\-\{template\s+([a-z0-9_\/]+)\}\-\-\>/ig, readtemplate);
       
        //ASP代码
        $template = $template.replace(/\<\!\-\-\{eval\s+((?:.|\n)+?)\s*\}\-\-\>/ig, evaltags);
       
        //开始处理
        //变量
        $template = $template.replace(/\<\!\-\-\{((?:.|\n)+?)\}\-\-\>/g, '\{$1\}');
        $template = $template.replace(/([\n\r]+)\t+/g, '$1');
        $template = $template.replace(/(\$[a-zA-Z0-9_\[\]\'\"\$\x7f-\xff]+)\.([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/g, "$1['$2']");
        $template = $template.replace(/\{(\$[a-zA-Z0-9_\[\]\'\"\$\.\x7f-\xff]+)\}/g, '\<\%\=$1\%\>');
        $template = $template.replace(/((\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)/g, addquote);
        $template = $template.replace(/\<\%\=\<\%\=((\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)\%\>\%\>/g, addquote);
        //逻辑
        $template = $template.replace(/\{elseif\s+((?:.|\n)+?)\}/ig, stripvtags2);
        $template = $template.replace(/\{else\}/ig, '\<\% \} else \{ \%\>');
        //循环
        $template = $template.replace(/\{loop\s+(\S+)\}((?:.|\n)+?)\{\/loop\}/ig, stripvtags4);
        $template = $template.replace(/\{if\s+((?:.|\n)*?)\}((?:.|\n)+?)\{\/if\}/ig, stripvtags3);
        //常量
        $template = $template.replace(/\{([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/g, '\<\%\=$1\%\>');
       
        //替换
        if(!empty($_SGLOBAL['block_search'])) {
                for($i=1;$i<$_SGLOBAL['block_search'].length;$i++){
                        $template = $template.replace($_SGLOBAL['block_search'][$i], $_SGLOBAL['block_replace'][$i]);
                }
        }
       
        //换行
        $template = $template.replace(/ \?\>[\n\r]*\<\? /ig, ' ');
       
        //write
        if(!swritefile($objfile, $template)) {
        //Response.Write('File: '+objfile+' can not be write!');
        //Response.End();
        }
}

function addquote() {
        $var = '\<\%\='+arguments[1]+'\%\>';
        return $var.replace(/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/g, "['$1']");
}

function evaltags() {
        $_SGLOBAL['i']++;
        $search = '\<\!\-\-EVAL_TAG_'+$_SGLOBAL['i']+'\-\-\>';
        $_SGLOBAL['block_search'][$_SGLOBAL['i']] = $search;
        $_SGLOBAL['block_replace'][$_SGLOBAL['i']] = '\<\% '+stripvtags(arguments[1])+' \%\>';
        return $search;
}

function stripvtags($expr, $statement) {
        if(typeof $statement == 'undefined') $statement = '';
        $expr = $expr.replace(/\<\%\=(.+?)\%\>/g, '$1');
        return $expr+$statement;
}

function stripvtags2() {
        $expr = '\<\% \} else if('+arguments[1]+') \{ \%\>';
        return $expr.replace(/\<\%\=(.+?)\%\>/g, '$1');
}

function stripvtags3() {
        $expr = '\<\% if('+arguments[1]+') \{ \%\>'+arguments[2]+'\<\% \} \%\>';
        return $expr.replace(/\<\%\=(.+?)\%\>/g, '$1');
}

function stripvtags4() {
        $expr = '\<\% if(is_array('+arguments[1]+')) \{ for($i=0;i<$1.length;$i++) \{ \%\>'+arguments[2]+'\<\% \} \} \%\>';
        return $expr.replace(/\<\%\=(.+?)\%\>/g, '$1');
}

//读取模板
function readtemplate() {
        $name = arguments[1];
        $tpl = strexists($name,'/')?$name:'template/'+$_SCONFIG['template']+'/'+$name;
        $tplfile = './'+$tpl+'.htm';
        if(!file_exists($tplfile)) {
               $tplfile = $tplfile.replace('/'+$_SCONFIG['template']+'/', '/default/');
        }
        $content = sreadfile($tplfile);
        return $content;
}
%>

现在举个简单的例子来证明:
首先在./template/default/目录下建立两个.htm模板文件,一个名为index.htm,一个名为sub.htm。
index.htm代码是这样的:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
  <TITLE> New Document </TITLE>
  <META NAME="Generator" C>
  <META NAME="Author" C>
  <META NAME="Keywords" C>
  <META NAME="Description" C>
</HEAD>

<BODY>

<!--这是在模板中使用变量-->
<h1><!--{$_SCONFIG['sitename']}-->或者$_SCONFIG[sitename]</h1>

<!--这是在模板中使用asp代码-->
<!--{eval Response.Write("hello1");}-->
<!--{eval Response.Write("hello2");}-->
<!--{eval Response.Write("hello3");}-->

<!--这是在模板中使用逻辑语句-->
<!--{if $variable1}-->
输出变量1
<!--{elseif $variable2}-->
输出变量2
<!--{else}-->
输出默认变量
<!--{/if}-->

<!--这是在模板中使用循环语句-->
<!--{loop $my_array}-->
遍历数组成员
<!--{/loop}-->

<!--这是在模板中加载子模板-->
<!--{template sub}-->

</BODY>
</HTML>
注意看到上面<!--{template sub}-->了吗,它是调用子模板sub.htm,也就是说模板中再调用一次模板,这在使用包含公共文件时候非常有用的。

sub.htm的代码是这样的:
<!--{eval Response.Write("这个是sub.htm子模板");}-->

现在回到./index.asp页面中来,添加如下代码:
<!--#include file = 'common.asp'-->
<%
template('index');
%>
好,现在系统会在./data/tpl_cache目录下面生成一个缓存文件template_default_index.asp,这个文件名是有含义的,template表示模板,default表示模板的皮肤目录,index就是模板的源文件。可以打开./data/tpl_cache/template_default_index.asp缓存文件查看一下到底是些什么代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
  <TITLE> New Document </TITLE>
  <META NAME="Generator" C>
  <META NAME="Author" C>
  <META NAME="Keywords" C>
  <META NAME="Description" C>
</HEAD>

<BODY>

<!--这是在模板中使用变量-->
<h1><%=$_SCONFIG['sitename']%>或者<%=$_SCONFIG['sitename']%></h1>

<!--这是在模板中使用asp代码-->
<% Response.Write("hello1"); %>
<% Response.Write("hello2"); %>
<% Response.Write("hello3"); %>

<!--这是在模板中使用逻辑语句-->
<% if($variable1) { %>
输出变量1
<% } else if($variable2) { %>
输出变量2
<% } else { %>
输出默认变量
<% } %>

<!--这是在模板中使用循环语句-->
<% if(is_array($my_array)) { for($i=0;i<$1.length;$i++) { %>
遍历数组成员
<% } } %>

<!--这是在模板中加载子模板-->
<% Response.Write("这个是sub.htm子模板"); %>

</BODY>
</HTML>
很好,已经成功把模板中的数据解析成ASP的代码了。

现在遗留下来最后一个问题也是最重要的问题,那就是,大家知道ASP中include file是没有办法动态包含文件的,而生成的asp缓存文件怎样才能动态加载进来并能够解析后台文件中的变量函数,这个问题一直困扰着我没有一个很好的解决方案,网上的答案众说纷纭,FSO、XMLHTTP+STREAM、或者APPLICATION等技术手段实现,希望有不错方案的朋友能够多多指教,跨越最后一道坎坷。

我现在的基本思路是使用FSO逐行读取来判断HTML和ASP代码分别作出选择执行Response.Write();或eval();,但是如果在一行同时出现HTML和ASP混合代码就比较麻烦了,不知道大家还有没有更好的实现思路...

以后的实现思路是这样的,系统在加载时会先读取缓存文件,如果缓存文件不存在就重新解析一下模板而后生成,从而避免每次都要解析生成模板,但前提是你的模板文件没有做过任何修改,如若不然,那只有删除缓存文件重新生成了,时间仓促,可能有些地方有疏漏或错误,但是这个思路和实现的模式能否给大家对ASP的未来带来一丝希望将拭目以待。
  相关解决方案