话说上节听的很郁闷,讲的也郁闷,整个系列没有详细的Code,所以都有点懵。其实仔细看之前的几节应该还是能够理解整个思路的。 我在这里再整理一遍: 用户访问URL后 ->根据所有Page的URL规则(urlpattern)获取当前Page,然后再根据page的Template,Find出所有的Label(通过反射),然后遍历这些Label,把得到的数据的Html替换掉Label本身的标签代码。最后整个Template就是要生成的HTML了。
所以我们要明白Label是如何获取工作才能获取数据库的数据的。一个Label可以理解成一个控件,那么控件必然会支持一些属性(Parameter)和一些内容(Field)。 我们上节就是在讲怎么来解析parameter,因为有些特殊的parameter,所以设计的时候设计了parameter的基类,特殊的则是子类。
同样,field是具体的要展现在HTML代码中的字段,比如中的[field:Title/],这就是一个字段,我们的模版引擎的工作就是把他替换掉应该展现的标题,而如何才能工作?我们就得设计Field的整个逻辑。在替换循环的过程中使用field类。

但是,我今天不讲Field了,因为这样讲大家还是糊涂依旧。今天我们就来设计一个Article:List的初级版。我觉得或许从实例讲解大家更容易理解设计的理念。OK,那就开始设计一个Article.List,我们最熟悉的文章列表。
//简单的循环列表
{Article:List Top="10" CategoryId="5"}
<a href ="/details/[field:FileName/]" target="_blank">[field:Title/]</a>

{/Article:List}

想象一下Repeater,有个ItemTemplate,那么对于List这个Label来说,他的ItemTemplate显然就是Template属性。那么如果我们获取到数据源后直接foreach替换掉所有的field即可。代码大概如下:
        /// <summary>/// 获取要展示的HTML代码/// </summary>/// <returns></returns>public override string GetRenderHtml(){var html = TemplateString;foreach (var article in GetDataSource()){foreach (var field in Fields){html = html.Replace(field.Html, field.GetValue(article));}}return html;}

从上面的方法中,我们可以看到替换的机制是每一行数据都要执行一次所有字段的替换(所以之前有提过在构造嵌套的时候为了防止Field混乱要处理TemplateString),最后返回html。我们还能看到一些未知的方法和字段:GetDataSource(),Field.Html,Field.GetValue(),这些已经暴露了我们的Field设计的部分内容。我们先看GetDataSource()是什么?

        /// <summary>/// 获取Article列表/// </summary>/// <returns></returns>private IEnumerable<Article> GetDataSource(){ var parameter = new ArticleQueryParameter();//构造查询的参数return ArticleDataHelper.GetList(parameter);}/// <summary>/// 查询参数基类/// </summary>public class QueryParameter{public int PageSize { get; set; }public int PageIndex { get; set; }public int RecordCount { get; set; }public string SearchKey { get; set; }}/// <summary>/// 文章查询类/// </summary>public class ArticleQueryParameter{public QueryParameter PageParameter { get; set; }public DateTime PostTime { get; set; }public int CategoryId { get; set; }public int Top { get; set; }}/// <summary>/// 文章获取数据类/// </summary>public class ArticleDataHelper{public static IEnumerable<Article> GetList(ArticleQueryParameter parameter){return null;}}

其实就是获取ArticleList的数据源,具体的实现方式大家可能都不一样,但Article.List最终需要这么一个数据获取的方法,然而这个方法都需要接受一些查询条件的参数,这些参数都来自Parameters!!现在我们来填充GetDataSource()的参数构造部分。

      private IEnumerable<Article> GetDataSource(){var parameter = new ArticleQueryParameter();//构造查询的参数parameter.CategoryId = Parameters["CategoryId"].ConvertToInt(0);parameter.Top = Parameters["Top"].ConvertToInt(Parameters["PageSize"].ConvertToInt(0));var pageIndex = Parameters["PageIndex"].ConvertToInt(1);if (pageIndex > 1){parameter.PageParameter = new QueryParameter{PageIndex = pageIndex,PageSize = parameter.Top};}return ArticleDataHelper.GetList(parameter);}

Parameters是Label的ParameterCollection,他可以通过索引直接访问具体的parameter。ConvertTo<T>(T defaultValue)是可以将parameter的value转成T类型。 这就是Parameter所用到的地方之一。另外可以看到Field具体Html属性和GetValue方法,而且GetValue接受了当前Article实体作为参数(不接受参数的话,我们怎么得到某个字段的值呢:)。

整个List流程应该比较清楚了吧,获取数据源,然后循环数据,每行再去替换所有的Field,最后把拼接好的HTML返回。当然这是List,如果是其他的标签可能就是另外一个处理办法。比如System.Include标签,他的工作就是嵌入一个用户控件(PartialTemplate),那么他的处理逻辑和List就完全不一样(他是先根据templateid参数的值获取template,然后再把自己所有的Parameters传递给这个template里的所有标签,最后再把这个template替换后的结果作为自己的结果返回,他没有循环)。所以我们的具体控件逻辑都是大相径庭的,但最终都是要返回替换后的HTML,但所有的List却都是差别多的,无非就是不同的数据源进行循环。所以对于List我们应该进行抽象,把公共部分提取出来,尽量让每个具体的Label更明确职责。如何抽象呢? 那就看看有没有可提取的公共部分。

所有的List都可能会有分页,所以ListBase应该有PageParameter,所有的List都会去循环DataSoruce,所以ListBase默认实现了DataSource循环,但是增加了一个方法那就是GetDataSource。这个方法是抽象的,所有的List必须实现。

    /// <summary>/// 循环标签基类/// </summary>public abstract class ListBase : Label{public QueryParameter PageParameter { get; set; }public abstract IEnumerable<dynamic> GetDataSource();public override string GetRenderHtml(){var dataSource = GetDataSource();if (dataSource == null) return string.Empty;var html = TemplateString;foreach (var dataItem in dataSource){foreach (var field in Fields){field.Data = dataItem;html = html.Replace(field.Html, field.GetValue());}}return html;}}

foreach里我也做了点细微的调整,就是把Field的GetValue的参数拿掉了,换成了成员,这样更明白些。你可能会有一些疑点:

为什么设计为抽象而不是虚方法或接口?

所有子类的实现方法都不一致,没有可提取部分,所以虚函数没有意义,如果单独抽象成接口,则所有子类必须继承此接口,因为GetRenderHtml和该方法紧密结合,foreach里需要显式转换为接口才能调用,完全没有意义。

为什么是GetDataSource方法,而不是公开一个DataSource成员? 如果需要Set呢?还要增加一个SetDataSource?

其实这个我考虑过,很少有Set的情况,因为标签都是自动生成的没有外部去干扰(Set),但不能否认以后完全没有,如果设为成员,则必须有一个可get的地方,要么是abstract,那样也会把set abstract,要么就在Init里给set先,那也得有一个抽象的set方法。所以考虑现状还是使用一个方法最为合适。

另外一点就是为什么用了dynamic,而不是T。

首先不能是T,如果是T,则GetRenderHtml调用时也需要指明T,则整个ListBase就要变成泛型类ListBase<T>,除非base不执行GetDataSource调用。为什么不能用ListBase<T>?因为有些GetDataSource会用linq返回匿名类型集合,子类无法确定返回的具体类型名称,所以就不能继承ListBase<T>。但我们可以用dynamic,动态类型,到真正执行时可以确定T就行,这个不用我们操心,然而object显然略逊一筹了。

这样一来,Article的List只需要实现GetDataSource就行了。

这只是最简单的List雏形,假如说我还需要像Repeater控件那样,有headtemplate itemtemplate foottemplate altertemplate spacetemplate怎么办?

这个就需要定义子标签类了。这里我就不多说了,其实很简单,就是再定义几个Label,他们又各自的获取Html的方法,我们最后组合起来就行。自需要注意List的Template和Field已经没了,都属于子标签了。而且像交替执行的(Item和Alter)需要再循环里给他们隔行赋值。下面是我以前写的代码,虽然比较难看,不太OO,但能说明实现的逻辑:

代码

今天就讲到这了,不知道还有朋友有兴趣没有,目前还没有演示,或许某天我会放出个demo源码。 下次讲Field的设计吧,这也算是最后一个设计了。

转载于:https://www.cnblogs.com/mad/archive/2010/11/14/1875913.html

CMS系统模板引擎设计(5):Label应用初探相关推荐

  1. CMS系统模版引擎设计(3):Label基类的设计

    上节讲了页面的整个生产流程,大家都期待第三篇,也就是生产的核心内容--Label的替换.说实话,我很有压力啊:)一个人一个实现思路,所以...可能你不能接受. 我的标签分为2种,一种是配置变量标签(就 ...

  2. php smarty 原理,php模板原理PHP模板引擎smarty模板原理浅谈

    mvc是开发中的一个伟大的思想,使得开发代码有了更加清晰的层次,让代码分为了三层各施其职.无论是对代码的编写以及后期的阅读和维护,都提供了很大的便利. 我们在php开发中,视图层view是不允许有ph ...

  3. cms概述 。比较shopex和ecshop区别 。smarty模板引擎的入门

    cms概述 为了找到一个合适的cms网站系统,我花了一番功夫搜索了多种cms,包括我用过的和没用过的,知道的和不知道的,当然,必须是开源的.免费的.生成静态页面的.到各自的官方网站,查看了有关资料,下 ...

  4. CMS模板引擎:XHtmlAction

    前言: 先说说大伙关心的工作上的事,在上家公司任了一个多月的技术经理后,和公司中止了合作关系. 主要原因在于一开始的待遇没谈的太清楚: 1:没有合同,没有公积金,连社保也没交. 2:工资的30%变成了 ...

  5. JavaWeb 项目 --- 博客系统(基于模板引擎)

    文章目录 1. 创建 maven 项目 2. 设计数据库 3. 封装数据库的操作代码 3.1 创建 DBUtil 类 3.2 创建类 Blog (代表一篇博客) 3.3 创建类 User (代表一个用 ...

  6. CMS系统中自定义模板标签、脚本的实现

    探讨问题的同胞们可以加QQ群:315309006 不少人对CMS很好奇,觉得CMS系统中为什么会出现各种不一样的标签,诸如<foreach *>.#if,有一些是#getArticle(& ...

  7. 计算机中复合模板在哪,冷冲模CAD系统中装配模板的设计与复合算法研究-计算机软件专业论文.docx...

    冷冲模CAD系统中装配模板 冷冲模CAD系统中装配模板 的设计与复合算法研究 摘要 文章首先综述了国内外模具CAD/CAM技术的发展概况.指出了模具设计 过程的规范化.设计方法的算法化及数据结构的合理 ...

  8. 【修复版】仿我爱看电影网站模板/海洋CMS影视系统模板

    仿我爱看电影网站模板,海洋CMS影视系统模板.海洋CMS我爱看电影网站模板,这款为修复版, 原版有许多小BUG,搞了大半天,能修复的都修复了,基本没有任何问题了. 已测试下面为测试图,大家可以看看. ...

  9. B2C电子商务系统研发——促销引擎设计(一)

    颜超敏的电子商务博客 随笔分类 -B2C电子商务系统研发 B2C电子商务系统研发--促销引擎设计(一)(Promotion Engine) 2012-10-29 22:40 by 颜超敏, 1281 ...

最新文章

  1. Metasploit AFP爆破模块afp_login
  2. LeetCode 98验证二叉搜素树(中序遍历)99恢复二叉搜索树
  3. Python的操作符重载
  4. 关于IOS开发知识的总结
  5. Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway.
  6. 【原】P2P应用的探究
  7. static关键字(修饰函数、局部变量、全局变量)
  8. leetcode486. 预测赢家(dp)
  9. eclipse oracle驱动位置,【求助】eclipse导入了Oracle的驱动包连不上Oracle
  10. redis 分页_Redis排行榜的设计与实现
  11. 【SQL 提示 之二】index_ss Index Skip Hint
  12. opencv的学习与人脸情绪识别项目(一)
  13. 大学有必要考华为认证吗?
  14. 云端转型突破临界点,金蝶云加速企业云服务落地
  15. 纽约州立石溪分校计算机科学排名,美国纽约州立大学石溪分校排名~值得一看~...
  16. SCP批量拷贝指定文件
  17. 技术分享 | 误删表以及表中数据,该如何恢复?
  18. 微信小程序第三方框架
  19. 第四章 MCS-51单片机汇编语言程序设计
  20. 两张独立显卡连接两个显示器如何配置

热门文章

  1. android复位机器人图片_Universal-Image-Loader 图片异步加载类库还不熟?
  2. java获取页面点击次数_java计算鼠标点击次数的题,急求!
  3. python把模块装到文件夹中_把模块有关联的放在一个文件夹中 在python2中调用文件夹名会直接失败 在python3中调用会成功,但是调用不能成功的解决方案...
  4. vs mfc数据与控件绑定错了_ASP.NET Core Blazor Webassembly 之 数据绑定
  5. php数据访问层,对数据访问层第一种实现(Acc+SQL)的重构
  6. oracle文件系统挂载点,挂载和取消挂载 Oracle Solaris 文件系统
  7. centos7 mysql 5.5.27_centos7上安装mysql-5.7.27
  8. 信安精品课:第5章物理与环境安全技术精讲笔记
  9. 2017下半年网络规划设计师考试上午真题
  10. 开发成本谁更高:Android PK iOS