.NET模板引擎 EFPlatform.CodeGenerator (代码生成器 静态页生成 生成HTML 模板)

这个东东是去年我看着ASP:标记突发奇想花4天时间设计编写的类库, 原名叫 HtmlGenerator, 最近发现PHP和JAVA有很多类似的项目, 但是都设计的很渣(不同意的表打我@_@), 于是把 HtmlGenerator 重构了一下, 改叫 CodeGenerator. 配合我的数据库迁移工具和数据库实体类生成品..... 好像跑题了 -____-

CodeGenerator 的特点:
1. 标记简结实用, 所有网页美工都能在一分钟内掌握. 而且不与HTML标准冲突, 模板页可用任何WYSIWYG工具编辑, 和编辑普通HTML网完全相同.
2. 标记只与表示层相关, 不包括任何业务逻辑, 丝毫不影响你应用多层结构.
3. 标记到后台被解析成了生成器对象, 完全面向对象, 不像绝大多数生成器要死嗑字符串.
4. 生成器对象使用DataSource属性取得数据, DataSource可以为  简单值类型(如 int, DateTIme), 也可以为简单数组(如 decimal[], string[]), 还可以为ADO.NET数据集(如DataTable), 甚至单个对象实体或对象集合或列表(如 SomeClassCollection, List<SomeClass>), 所有数据源类型通吃! 哈哈, 比ASP.NET带的数据控件支持的类型还多.
5. 标记的Name直接与数据源的列名ColumnName或属性名PropertyName, 好处不言而喻了吧.
6. 说到这里好了, 留一手先. 呵呵


演示程序下载地址: http://files.cnblogs.com/ericfine/Demo.rar
EFPlatform.CodeGenerator 源代码下载地址: http://files.cnblogs.com/ericfine/EFPlatform.CodeGenerator.rar (过时了)
EFPlatform.TemplateEngine 源代码下载地址: http://files.cnblogs.com/ericfine/EFPlatform.TemplateEngine.rar (其实就是CodeGenerator的优化版:))

应用项目:
http://portray.mz99.com/
http://music.mz99.com/
http://joke.mz99.com/
http://www.mcuol.com/

应用流程:




Default.aspx.cs:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using EFPlatform.TemplateEngine;

public partial class _Default : Page
{
    
private string outputPath;
    
private string categoryFileName;
    
private string productFileName;
    
private static DbProviderFactory dbFactory;
    
private DbConnection connection;

    
protected void Page_Load(object sender, EventArgs e)
    
{
        outputPath 
= Server.MapPath("./");
        categoryFileName 
= string.Format(@"{0}\Template\Category.html", outputPath);
        productFileName 
= string.Format(@"{0}\Template\Product.html", outputPath);
        
string currentConnection = ConfigurationManager.AppSettings["Connection"];
        ConnectionStringSettings css 
= ConfigurationManager.ConnectionStrings[currentConnection];
        
this.GetConnection(css);
    }


    
private void GenerateCategory()
    
{
        
string template = Helper.ReadTextFile(categoryFileName);
        Generator gen 
= new Generator(template);
        gen.ParseTemplate();
        Region rgnTitle 
= gen.GetRegion("Title");
        Region rgnCategory 
= gen.GetRegion("Category");
        Region rgnProducts 
= gen.GetRegion("Products");
        Region rgnNavigator 
= gen.GetRegion("Navigator");

        
if(rgnTitle == null || rgnCategory == null || rgnProducts == null || rgnNavigator == null)
        
{
            Response.Write(
"Missing region.");
            
return;
        }


        
int categoryId;
        
string outputFileName;
        DataView dvCategory 
= this.GetCategoryTable().DefaultView;
        Pager pgrCategory 
= new Pager(1, dvCategory.Count);

        
for(int i = 0; i < pgrCategory.PageCount; i++)
        
{
            rgnTitle.DataSource 
= (string)dvCategory[i]["CategoryName"];        //Use a string as data source
            rgnCategory.DataSource = dvCategory[i];        //Use a DataRowView object as data source
            pgrCategory.CurrentPage = i + 1;
            rgnNavigator.DataSource 
= pgrCategory;        //Use a Pager object as data source
            categoryId = (int)dvCategory[i]["CategoryID"];
            rgnProducts.DataSource 
= this.GetProductTable(categoryId);        //Use a DataTable object as data souce
            outputFileName = string.Format(@"{0}\Html\Category{1}.html", outputPath, categoryId);
            Helper.WriteTextFile(outputFileName, gen.Generate());
        }

    }


    
private void GenerateProduct()
    
{
        
string template = Helper.ReadTextFile(productFileName);
        Generator gen 
= new Generator(template);
        gen.ParseTemplate();
        Region rgnTitle 
= gen.GetRegion("Title");
        Region rgnProduct 
= gen.GetRegion("Product");
        Region rgnNavigator 
= gen.GetRegion("Navigator");

        
if(rgnTitle == null || rgnProduct == null || rgnNavigator == null)
        
{
            Response.Write(
"Missing region.");
            
return;
        }


        
string outputFileName;
        List
<Product> productList = this.GetProductList();
        Pager pgrProduct 
= new Pager(1, productList.Count);

        
for(int i = 0; i < pgrProduct.PageCount; i++)
        
{
            rgnTitle.DataSource 
= productList[i].CategoryName;        //Use a string as data source
            rgnProduct.DataSource = productList[i];        //Use a Product object as data source
            pgrProduct.CurrentPage = i + 1;
            rgnNavigator.DataSource 
= pgrProduct;        //Use a Pager object as data source
            outputFileName = string.Format(@"{0}\Html\Product{1}.html", outputPath, productList[i].ProductID);
            Helper.WriteTextFile(outputFileName, gen.Generate());
        }

    }


    
DataSourcePreparing

    
protected void Button1_Click(object sender, EventArgs e)
    
{
        
this.GenerateCategory();
    }


    
protected void Button2_Click(object sender, EventArgs e)
    
{
        
this.GenerateProduct();
    }

}


Web.config:

<?xml version="1.0"?>
<configuration>
    
<system.web>
        
<compilation debug="true" />
        
<authentication mode="Windows" />
        
<customErrors mode="Off" defaultRedirect="GenericErrorPage.htm">
            
<error statusCode="403" redirect="NoAccess.htm" />
            
<error statusCode="404" redirect="FileNotFound.htm" />
        
</customErrors>
    
</system.web>
    
<connectionStrings>
        
<add name="Access" providerName="System.Data.OleDb" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb"/>
        
<add name="SqlExpress" providerName="System.Data.SqlClient" connectionString="Data Source=.\SQLExpress;Integrated Security=True;User Instance=True;Database=Northwind;AttachDBFilename=|DataDirectory|Northwind.mdf"/>
    
</connectionStrings>
    
<appSettings>
        
<add key="Connection" value="Access"/>
    
</appSettings>
</configuration>








 

posted @ 2007-06-30 20:57 Eric Fine 阅读(8133) 评论(65)  编辑 收藏 网摘 所属分类: Components & Controls

  回复  引用    
#1楼2007-06-30 21:28 | 小鬼[未注册用户]
见不到你的具体类的代码,不知道你是怎么实现替换的,如果是一个个地replace的话,性能不会太好。我最近也在做同一类型的东东,但感觉需要加强编译原理的学习才能做得更好,哈。不知道你有没有这方面的资料呢?
  回复  引用    
#2楼2007-06-30 21:29 | 小鬼[未注册用户]
原来有代码可以下载,不好意思,我看看去先。
  回复  引用  查看    
#3楼[楼主]2007-06-30 21:57 | Eric Fine      
汗.......再发上来就反映了....呵呵
我设计的这个类主要是标记精简,数据填充非常方便,模板可以让网页设计师直接设计,不需要开发人员二次加工.

  回复  引用  查看    
#4楼2007-06-30 22:22 | Brush      
不错,收藏一下。
  回复  引用  查看    
#5楼2007-06-30 22:33 | 海纳百川      
手头的项目要用到类似功能,收藏参考一下。谢了!
  回复  引用    
#6楼2007-07-01 00:02 | teana[未注册用户]
建议提供个示例程序。
  回复  引用  查看    
#7楼[楼主]2007-07-01 00:39 | Eric Fine      
  回复  引用  查看    
#8楼2007-07-01 03:54 | wdx2008      
很好!收下了,最近正在搞这个
  回复  引用  查看    
#9楼2007-07-01 10:01 | 随风流月      
呵呵。不知是否 Replace?不过对于我这种程序员美工,暂且不用了。
  回复  引用  查看    
#10楼2007-07-01 10:15 | 代码乱了      
@Eric Fine
是否提供default.aspx的下载,或者是整个的完整demo的下载啊
好回去研究下

  回复  引用    
#11楼2007-07-01 13:06 | 一情[未注册用户]
能不能把源程序公布出来呢?
  回复  引用    
#12楼2007-07-01 13:41 | helloajax[未注册用户]
支持开源!
  回复  引用  查看    
#13楼2007-07-01 13:46 | Tiny      
建议大家一起搞个生成静态页面的建站系统出来。asp,php的都有了,就.net还落后,有意象的可以联系我
  回复  引用  查看    
#14楼2007-07-01 14:22 | 拾荒时代      
好代码
  回复  引用  查看    
#15楼[楼主]2007-07-01 15:22 | Eric Fine      
@布尔
说话要负责任的哦 ^_^

  回复  引用  查看    
#16楼[楼主]2007-07-01 15:38 | Eric Fine      
已经把DLL下载换成项目源代码下载了, 方便不会用Reflector的新丁们研究:)
  回复  引用    
#17楼2007-07-01 17:19 | 匿名人士23568[未注册用户]
推荐使用StringTemplate或TemplateEngine ,这两个都是开源的非常优秀的模板引擎,俺特别喜欢后者。
  回复  引用    
#18楼2007-07-01 18:54 | 一情[未注册用户]
能不能解释一下,说的详细一下点儿
  回复  引用    
#19楼2007-07-02 08:45 | bosswin[未注册用户]
非常不错,开发CMS和BLOG很有用。
  回复  引用  查看    
#20楼2007-07-02 10:42 | 天梦      
呵呵,正在你的网站http://music.mz99.com/听歌呢" target="_new">http://music.mz99.com/听歌呢
  回复  引用  查看    
#21楼[楼主]2007-07-02 12:08 | Eric Fine      
@罗庆伟
模板页和结果页在演示地址里有啊

  回复  引用  查看    
#22楼2007-07-02 20:24 | 吾跃乾坤      
兄台,可否将你的 “数据库迁移工具和数据库实体类生成品” 也共享一下
  回复  引用    
#24楼2007-07-26 10:38 | neo[未注册用户]
把源码全部放出来吧?……哈哈
大家如果都用你的,来验证你所做的,再那么一反馈,自己能学到好多东西呢……

  回复  引用    
#26楼2007-08-18 01:22 | ten[未注册用户]
你生成的实例.不得到title中的内容.

就是绑定单个string的时间有点问题.
能不能在改进下啊.

  回复  引用    
#27楼2007-08-19 01:08 | 小鬼[未注册用户]
因为工作需要,我也实现了一个,不过因为现在所做的代码都不能公布出来的,所以没办法和你一起探讨了.
  回复  引用  查看    
#28楼[楼主]2007-08-21 08:38 | Eric Fine      
@ten
这个BUG在 优化版本 EFPlatform.TemplateEngine 里解决了

  回复  引用    
#29楼2007-08-21 14:05 | stonezhu[未注册用户]
@Eric Fine
你好,非常高兴能看到您这篇文章,
现在正好急需用,希望您能给一个DEMO,看了你DEMO的演示,不是很懂,希望能给个完整的DEMO提供下载,或者email给我,谢谢
我的email: zrc000@gmail.com

  回复  引用    
#30楼2007-09-06 17:25 | 嘟嘟[未注册用户]
Pager pgrCategory = new Pager(1, dvCategory.Count);

for(int i = 0; i < pgrCategory.PageCount; i++)
{
rgnTitle.DataSource = (string)dvCategory[i]["CategoryName"]; //Use a string as data source
rgnCategory.DataSource = dvCategory[i]; //Use a DataRowView object as data source
pgrCategory.CurrentPage = i + 1;
rgnNavigator.DataSource = pgrCategory; //Use a Pager object as data source
categoryId = (int)dvCategory[i]["CategoryID"];
rgnProducts.DataSource = this.GetProductTable(categoryId); //Use a DataTable object as data souce
outputFileName = string.Format(@"{0}\Html\Category{1}.html", outputPath, categoryId);
Helper.WriteTextFile(outputFileName, gen.Generate());
}


我想每个页面绑定20条数据,这边好象不能实现,无论怎样,都只能绑定一条数据而已,要怎么办?

  回复  引用    
#31楼2007-09-06 18:14 | 嘟嘟[未注册用户]
用sql2005新特性 row_number()解决这个问题了。。谢谢
  回复  引用    
#32楼2007-09-12 16:46 | wdjk[未注册用户]
这几天我也正在研究这个,看看对我有没有帮助,感谢Eric Fine
  回复  引用    
#33楼2007-09-12 16:57 | 小小水晶[未注册用户]
看了一遍,但有疑问
比如我在制作模板时,要在首页某一位置调用指定的某一类型商品10件显示,这时怎么解决呢?
示例只是最简单的一种情况啊
如何像其它模板生成那样,在标记里就包含了要调用的类别名称,数量,这样就可以了,在这是如何解决这个问题的呢?

  回复  引用  查看    
#34楼[楼主]2007-09-13 09:07 | Eric Fine      
@小小水晶
数据显示出几条, 是由你在后台绑定时提供的数据源决定的.

  回复  引用    
#35楼2007-09-13 17:38 | 小小水晶[未注册用户]
我的意思是这样:
比如像动网新网动易等支持生成静态页面的系统,都是通过预定义相当多的标记和属性,这样程序一旦发布以后,其它人想制作新的模板,就可以完全不需要涉及到程序改动
而你目前发布的这个,是获取模板中的标记,再使用程序在后台绑定数据源,这样数据就被限定死了
而上面提到的这些文章发布系统静态化时,模板制作人员可以在模板中包含要调用的类别,数量等这样的属性,然后设定系统使用这个模板就可以了

请问这样的功能EFPlatform.TemplateEngine支持吗?我没有发现啊,不然摆脱不了改动程序,就没办法通用了
谢谢

  回复  引用    
#36楼2007-09-15 10:24 | zqz[未注册用户]
代码有问题!!
在GenerateProduct()方法中, 以下语句从
outputFileName = string.Format(@"{0}\Html\Product{1}.html", outputPath, productList[i].ProductID);
从ProductID获取值作为文件名一部分.
而在模板中,分页获取的数据是
<a href="product{FirstPage}.html">, FirstPage永远都是数字.

如果ProductID是非数字,则分页根据没办法指向生成的html文件.

总之一句话,分页指向的页面 不能和 生成的页面名字对应

  回复  引用  查看    
#37楼[楼主]2007-09-17 13:10 | Eric Fine      
--引用--------------------------------------------------
zqz: 代码有问题!!
在GenerateProduct()方法中, 以下语句从
outputFileName = string.Format(@&quot;{0}\Html\Product{1}.html&quot;, outputPath, productList[i].ProductID);
从ProductID获取值作为文件名一部分.
而在模板中,分页获取的数据是
&lt;a href=&quot;product{FirstPage}.html&quot;&gt;, FirstPage永远都是数字.

如果ProductID是非数字,则分页根据没办法指向生成的html文件.

总之一句话,分页指向的页面 不能和 生成的页面名字对应

--------------------------------------------------------

outputFileName = string.Format(@"{0}\Html\Product{1}.html", outputPath, productList[i].ProductID);
中的productList[i].ProductID换成 i+1.

  回复  引用    
#38楼2007-10-23 15:49 | stone_zhu[未注册用户]
TO:Eric Fine
我在使用你的EFPlatform.TemplateEngine时,根据你的demo有问题,
问题如下 :
------------------------------------------------------------
Region rgnTitle = gen.Regions["Title"];
Region rgnCategory = gen.Regions["Category"];
Region rgnProducts = gen.Regions["Products"];
Region rgnNavigator = gen.Regions["Navigator"];
------------------------------------------------------------
在EFPlatform.TemplateEngine已经不能用了,因为gen里面已经没有Regions了。
我应该怎么去用啊 ?
希望能有答复啊,急用 ,万分感谢!

  回复  引用  查看    
#39楼[楼主]2007-10-23 18:35 | Eric Fine      
@stone_zhu
请改用 GetRegion 方法

  回复  引用    
#40楼2008-02-19 09:13 | 咸鱼1111111[未注册用户]
有没有类似判断语句跟循环的用法哈。
  回复  引用    
#41楼2008-03-08 10:09 | DEMO help[未注册用户]
希望能给个完整的DEMO提供下载?或发到我邮箱:763727231@qq.com
  回复  引用    
#42楼2008-03-08 12:04 | DEMO help[未注册用户]
怎么所有的产品都放在一个Category Page页里呀?在哪里设置每页的数量?
  回复  引用    
#43楼2008-03-24 22:24 | JarryZzhong[未注册用户]
牛....X....喜欢!~!~
支持一下!~!~

  回复  引用    
#44楼2008-03-28 22:05 | plcnc2003[未注册用户]
我在学习你的这个模板感觉真不错,佩服啊,可不可以提供一下你的这个演示例子里面的代码让大家下载啊,那样看起来更容易明白点,先谢谢了
  回复  引用    
#45楼2008-04-17 15:07 | NET模板引擎[未注册用户]
演示用不了.................
  回复  引用    
#46楼2008-04-17 15:56 | NET模板引擎[未注册用户]
异常详细信息: System.ArgumentException: 类型“System.String”的对象无法转换为类型“System.Decimal”。

源错误:


行 134: if(pi != null)
行 135: {
行 136: pi.SetValue(model, dr[i], null);
行 137: }
行 138: }


源文件: F:\EFPlatform.TemplateEngine\Helper.cs 行: 136

请问怎么解决呀?

  回复  引用    
#47楼2008-04-17 16:21 | NET模板引擎[未注册用户]
能不能提供演示的源文件下载?拜托了
  回复  引用  查看    
#48楼[楼主]2008-04-23 19:51 | Eric Fine      
有问题可以EMAIL我~
  回复  引用  查看    
#49楼[楼主]2008-04-25 17:25 | Eric Fine      
  回复  引用    
#50楼2008-05-23 09:38 | 泡泡版主[未注册用户]
看到此代码很兴奋,一直想用一个在.net环境下的,总找不到,楼主能否把最新的DLL发到我邮箱yeahjob@163.com,谢谢
  回复  引用    
#51楼2008-05-23 10:06 | 泡泡版主[未注册用户]
请问下这模板类能实现下面这样分页显示数据吗?

~~~~~~~~~~显示的数据~~~~~~~~~~~~

1,2,3,4,5,6...>>
这样的分页吗?

  回复  引用    
#52楼2008-05-26 05:32 | 火星人~~~[未注册用户]
写的太绕,哎,逻辑上写的太绕了
  回复  引用    
#53楼2008-05-27 20:43 | sunqy[未注册用户]
能不能提供一个完整的实例给我?

<table>
<thead>
<tr>
<td>Key</td><td>Value</td>
</tr>
</thead>
<tbody>
<!--{#foreach /HttpContext/Request/Params/Item}-->
<tr>
<td>{=Key}</td><td>{=Value}</td>
</tr>
<!--{#end}-->
</tbody>
</table>

要解析这个东西,C#应该要怎么写啊?
我的邮箱:sunyunjs@126.com

  回复  引用    
#54楼2008-05-27 21:19 | sunqy[未注册用户]
老实讲,这个实例跟普通的替换没多大差别
我是想看一下如何解析类似:
<table>
<thead>
<tr>
<td>Key</td><td>Value</td>
</tr>
</thead>
<tbody>
<!--{#foreach /HttpContext/Request/Params/Item}-->
<tr>
<td>{=Key}</td><td>{=Value}</td>
</tr>
<!--{#end}-->
</tbody>
</table>

的调用方法的

  回复  引用    
#55楼2008-05-27 21:23 | sunqy[未注册用户]
LateBindingNavigator工具类应该引用什么组件?在网上找了很久都没有找出来啊
  回复  引用  查看    
#56楼[楼主]2008-06-01 22:25 | Eric Fine      
@泡泡版主
49楼放的就是最新的....其实是好久没更新过了, 整理了下再放出来而已

  回复  引用  查看    
#57楼[楼主]2008-06-01 22:29 | Eric Fine      
@sunqy
我这个东东的意图是分离界面和逻辑, 让网页美工去写JS已经是很不规范的情景了, 让他们再去学用别人自定义的模板语言就跑得更远了

  回复  引用    
#58楼2008-06-12 11:46 | HxBin[未注册用户]
我想问一下,使用你这个生成引擎时,生成单列表已没什么问题了,但如果一个页面要多不同分类的列表,要怎么做?能不能通过在模版里设置类别ID的?

  回复  引用    
#59楼2008-08-06 16:29 | rocky820420[未注册用户]
segments.Add(new Field(m.Value, name, len, format));

里面的len,如果变化了一次没有初始化回0,以后创建的field都会限制到5了吧?

博主看看吧!

  回复  引用    
#60楼2008-08-06 16:30 | rocky820420[未注册用户]
--引用--------------------------------------------------
rocky820420: segments.Add(new Field(m.Value, name, len, format));

里面的len,如果变化了一次没有初始化回0,以后创建的field都会限制到5了吧?

博主看看吧!
--------------------------------------------------------
不是5, 是第一次变化成的值!呵呵!

  回复  引用    
#61楼2008-08-11 16:19 | 大大[未注册用户]
那个Demo怎么下不了啊,兄弟急用,麻烦发一个我吧,谢谢啦
38487079@QQ.Com

  回复  引用  查看    
#62楼2008-11-18 11:33 | clefoo      
美工 根本不可能知道属性名是多少,所以这个也不是很通用。。
  回复  引用    
#63楼2009-04-09 14:05 | xin36933[未注册用户]
我也要个Demo,麻烦也发给我一个
383063879@qq.com
谢谢




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 801559




相关文章:

相关链接: