设为首页收藏本站订阅更新

无忧脚本

 找回密码
 加入无忧

QQ登录

只需一步,快速开始

搜索
查看: 10420|回复: 9

绝对原创MVC模式ASP框架

[复制链接]
发表于 2009-4-16 01:11:11 | 显示全部楼层 |阅读模式
常常自问,ASP框架模式(MVC)实现就那么难吗?众多.NET,PHP,Java框架摆在你的面前,你还有必要研究ASP框架么?没错,随着Web技术不断发展,什么SNS,WEB2.0应用系统应运而生,换位思考一下,为何我们不使用这些个理念来完善或者说来挖掘出ASP自身更大的潜力呢?他们能办到的为何ASP不能办到呢?是因为ASP语言本身的局限性一直阻碍着我们,还是因为我们没有一个更好的设计模式?应该什么都不是!我在这里可以很负责的说,ASP一定能够做到而且还应该做得非常的好!

框架说明:
1.框架还没有完全开发好,只是完善了部分功能,不过我在这里会不定期的更新直至整个框架的完成。
2.框架统一采用Javascript脚本语言开发,因为本人还是不习惯VBScript的语法,实在抱歉。
3.框架采用MVC模式,动态生成缓存文件以供系统调用。
语法说明:
1.不再使用关键字var来定义变量了,而是采用$来直接定义变量,比如$sitename,因为实在太喜欢PHP中的$符合了,够简洁。
2.常量采用全大写的格式,比如$_SGLOBAL
好了,暂时就这些,以后如有其它约定还会在这里补充的。
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对象
FSO = Server.CreateObject('Scripting.FileSystemObject');

$_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;
        }
        parse_template($tpl);//解析输出到模板
        
        
}

%>

最关键的是模板解析文件./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+(.+?)\s*\}\-\-\>/ig, evaltags);
        
        //开始处理
        //变量
        $template = $template.replace(/\<\!\-\-\{(.+?)\}\-\-\>/ig, '$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]*)/ig, "$1['$2']");
        $template = $template.replace(/\{(\$[a-zA-Z0-9_\[\]\'\"\$\.\x7f-\xff]+)\}/ig, '\<\%=$1\%\>');
        $template = $template.replace(/((\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)/, addquote);
        $template = $template.replace(/\<\%\=\<\%\=((\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)\%\>\%\>/ig, addquote);
        
        //逻辑
               
        //替换
        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() {
        $str = '\<\%='+arguments[1]+'\%\>';
        return $str.replace(/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/ig, "['$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(/\<\%\=(.+?)\%\>/i, 'Response.Write($1);');
        return $expr+$statement;
}

//读取模板
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']}</h1>

<!--{eval Response.Write("hello1");}-->
<!--{eval Response.Write("hello2");}-->
<!--{eval Response.Write("hello3");}-->
<!--{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就是模板了。我们可以打开该模板查看一下到底是些什么代码:
<!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']%></h1>

<% Response.Write("hello1"); %>
<% Response.Write("hello2"); %>
<% Response.Write("hello3"); %>

<% Response.Write("这个是sub.htm子模板"); %>

</BODY>
</HTML>
很好,我们已经成功把模板中的数据转换成ASP的代码了。以后的实现思路是这样的,系统在加载时会先读取缓存文件,如果缓存文件不存在就重新解析一下模板而后生成,从而避免每次都要解析生成模板,但前提是你的模板文件没有做过任何修改,如若不然,那只有删除缓存文件重新生成了,时间仓促,可能有些地方有疏漏或错误,但是这个思路和实现的模式能否给大家对ASP的未来带来一丝希望将拭目以待。
 楼主| 发表于 2009-4-17 16:23:08 | 显示全部楼层
请问在这里如何才能编辑帖子呢?
发表于 2009-4-21 13:07:59 | 显示全部楼层
来支持一下ASP
发表于 2009-4-21 13:11:53 | 显示全部楼层
原帖由 [I]jlmqq[/I] 于 2009-4-17 16:23 发表
请问在这里如何才能编辑帖子呢?

你发的帖子右下角有“ 编辑  引用  报告 回复 ”的
 楼主| 发表于 2009-4-21 20:24:01 | 显示全部楼层
提示审核后的贴子是无法编辑的。
发表于 2009-4-23 00:57:45 | 显示全部楼层
楼主的想法不错,期待早日实现能看到demo
发表于 2009-5-31 23:53:47 | 显示全部楼层
最新搞的一个网站,也是采用这个模式开发的

http://www.0000114.com  高手们,指点一二
 楼主| 发表于 2009-6-9 02:46:38 | 显示全部楼层
还是不能编辑啊,提示信息:对不起,管理员设置了需要对发帖进行审核,您没有权力编辑已通过审核的帖子,请返回。
发表于 2012-11-15 13:26:41 | 显示全部楼层
支持 asp!
发表于 2012-11-22 19:48:38 | 显示全部楼层
你厉害我就来看看 那部戏
您需要登录后才可以回帖 登录 | 加入无忧

本版积分规则

小黑屋|手机版|Archiver|无忧脚本 ( 苏ICP备05080427号 )|值班电话:027-62300445   鄂公网安备 42011102000433号

GMT+8, 2017-11-23 19:07 , Processed in 0.101163 second(s), 8 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表