[转载]CMS系统模版引擎设计(1):基础类型

[转载]CMS系统模版引擎设计(1):基础类型 – 氣如蘭兮長不改,心若蘭兮終不移。 – 博客园.

写博文写 教程性质的内容,大家比较喜欢,具体的项目设计方案关注的人比较少,而且思路也不一定说的清楚,本身写博文就比较辛苦,作者再偷点懒,那基本上就是一篇废 文。尽管如此,我还是想写一下我做过的一个项目的模块设计——CMS的模版引擎。呵呵,叫成“引擎”就是夺人眼球而已。其实就是一个标签解释的过程模块。
做过网站 的朋友都对CMS很熟悉,有的朋友也接触过N多CMS系统,国内比较流行的有dedeCMS,phpCMS,帝国 CMS,KingCMS,PowerEasyCMS等等,他们都有个共同的特点,就是前台的实现是模版标签机制。标签的好处就是可以让非专业开发人员通过 特定的标签实现数据调用。一段标签表示一种数据的调用。那我的这个CMS也是干这事的,不过是用.NET实现的。实现思路也是自己琢磨出来的,如有雷同, 那真是太巧合了:)
从哪里开始讲呢?还是从业务开始吧!
当公司接 到一个网站的单子后,就要估算价格。估算价格一般都要问开发经理这个网站的开发周期和难度(方便忽悠好要价),开发经理也就是我们技术leader,他会 估算该网站大概需要多少页面,需要什么子模块,需要干多久(假如没有CMS的话)。呐,这里就有个重要的信息,就是需要多少页面和什么模块。
做一个网站我们肯定要考虑他的功能模块,也要考虑多少页面。
功能模块一般有 文章、图片(相册)、视频、投票、留言、评论、下载、单页、自定义表单等等。我们介绍模版,这些功能模块就不多提了。
页面的概 念便是需要多少去制作的Page.aspx。一般有首页(子站首页)、封面页(可以理解为栏目封面)、列表页、详情页、独立页(关于我们之类的),不同的 数据类型还不一定一致,比如新闻和下载都是不一样的页。而模版的话不可能是要制作人员创建aspx的,他们只会用模版。所以通过这些信息我们能想到需要设 计哪些类呢?
Page类、Template类、Label类,页面、模版和标签。
Label涉及到具体的标签系列,咱暂且不说,先看Template如何设计?
一个模版有何设计的?有的CMS系统就是直接读取静态文件,但是我说这样不好,我们要在代码里有他的具体类型才能更方便的处理。
代码

/// <summary>
/// 模版类
/// </summary>
public class Template
{
/// <summary>
/// 模版ID
/// </summary>
public Guid TemplateId { get; set; }
/// <summary>
/// 模版名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 模版内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 是否为部分视图
/// </summary>
public bool IsPartial { get; set; }
}

初步设计就是如此,增加了一个IsPartial属性,因为我们的模版或许会作为部分视图在其他模版里调用,就像UserControl一样。

那 么Page类的设计就略显复杂了。我们想访问一个Page起码要有访问路径吧,所以就要有一个UrlPattern属性,也就是访问规则,因为像详细页一 般只是参数的变化,所以URL不能写死,只能是一个规则。既然有规则,也会有一些参数,而且参数不一定是?name=value形式,可能是/value /value1形式,所以我们还得设计一个UrlPattern类。

代码

/// <summary>
/// Url访问规则
/// </summary>
public class UrlPattern
{
/// <summary>
/// 具体规则
/// </summary>
public string Pattern { get; set; }
/// <summary>
/// 正则引擎
/// </summary>
public Regex Regex { get; set; }
/// <summary>
/// 参数列表
/// </summary>
public string[] Parameters { get; set; }
/// <summary>
/// 获取某个参数的值
/// </summary>
/// <param name=”rawurl”>当前访问的URL</param>
/// <param name=”name”>参数名</param>
/// <returns></returns>
public string GetValue(string rawurl, string name)
{
throw new System.NotImplementedException();
}
}

是的,你没看错,我们要用正则表达式,这可能是对制作人员难度最大的部分。:)不过可以教他们初级的写法,可以应付绝大多数需求。

比如我写一个规则如下  /details/(?<articleid>\d+),这个表明参数名为articleid,访问规则就是 “/details/数字”

Page除了访问URL外还要有缓存的概念,不然我们如何提升性能,你说是不?!缓存可能还会用标签里去,因为如果Page不缓存只是缓存了某个标签,所以Label也要有缓存,那么我们是否需要设计一个缓存类呢?

代码

/// <summary>
/// Page/Template/Label的缓存
/// </summary>
public class Cache
{
/// <summary>
/// 缓存名
/// </summary>
public string Key { get; set; }
/// <summary>
/// 缓存秒数
/// </summary>
public int CacheSeconds { get; set; }
/// <summary>
/// 获取缓存数据
/// </summary>
/// <returns></returns>
public object GetData()
{
throw new System.NotImplementedException();
}
/// <summary>
/// 移除缓存
/// </summary>
public void Remove()
{
throw new System.NotImplementedException();
}
/// <summary>
/// 更新缓存
/// </summary>
/// <param name=”data”></param>
public void SetData(object data)
{
throw new System.NotImplementedException();
}
}

那么Page类还应该有什么?Labels!是的,我们不可能每次都去解释模版来获取所有的Label,而是Page被缓存后我们只需要访问他的LabelCollection即可。那么我们来看下Page的设计雏形吧。

代码

/// <summary>
/// Page类
/// </summary>
public class Page
{
/// <summary>
/// ID
/// </summary>
public Guid PageId { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 关键字
/// </summary>
public string Keywords { get; set; }
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 模版
/// </summary>
public Template Template { get; set; }
/// <summary>
/// 访问路径规则
/// </summary>
public UrlPattern UrlPattern { get; set; }
/// <summary>
/// 标签
/// </summary>
public Label[] Labels { get; set; }
/// <summary>
/// 缓存
/// </summary>
public Cache Cache { get; set; }
/// <summary>
/// 显示HTML代码
/// </summary>
public void Render()
{
throw new System.NotImplementedException();
}
}

不错哦,袄哟,不错哦。

其实对于大型的站点,子站的概念是不可缺少的。或者我们的CMS需要支持多站点,那么还需要一个Site类。

代码

/// <summary>
/// 站点
/// </summary>
public class Site
{
/// <summary>
/// 站点ID
/// </summary>
public Guid SiteId { get; set; }
/// <summary>
/// 站点名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 站点备注
/// </summary>
public string Note { get; set; }
/// <summary>
/// 站点域名
/// </summary>
public string[] Domains { get; set; }
/// <summary>
/// 站点状态
/// </summary>
public Status Status { get; set; }
/// <summary>
/// 站点的页面
/// </summary>
public Page[] Pages { get; set; }
}

站点一般包含多个可访问的域名,所以有个Domains。当然站点包含N个Page。

好啦,初步的设计就到这了,下节我们讲怎么让这些类运作起来。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏