[C#]使用NVelocity自动生成Favorite收藏夹的导航页面

转载:http://www.cnblogs.com/wuhuacong/archive/2009/12/28/1634447.html

你是否碰到你的收藏夹凌乱不堪,或者很多收藏网页地址虽然分类,可是使用起来却感觉不太好,有没有想过把你的收藏夹内容自动生成一个网页的导航页面生成类似Hao123(http://www.hao123.com/),或者番茄花园导航(http://www.tomatolei.com/)一样的网页,用来迅速导航到自己的网址呢?

即使使用场景有争议,不过我们也来关注一下这种自动生成页面的技术吧,说不定可以使用在合适的环境下,如下面我测试了两个类别的收藏夹 Favorite目录下,其中“搜索引擎”和“新闻网络”两个目录是我的测试收藏夹分类,Icon和Images是我构造生成主页所需要的一些内容目录。 我们根据Index.htm来生成index.htm来作为导航的主页面。

由于我们不想改变收藏夹的IE快捷方式的内容,因此收藏夹里面的内容还是以IE快捷方式来保存,如下图所示。

其中IE快捷方式的内容如下所示,文件时采用INI格式进行保存的。

[DEFAULT]
BASEURL=http://g.cn
[InternetShortcut]
URL=http://g.cn

其中的Default中的BaseURL是域名地址,InternetShortcut中的URL是具体的网页地址,基本上这些内容就可以构造成一个IE快捷方式了。

整体运行的效果如下图所示。其中内容可以动态生成,由于采用了NVelocity引擎来生成内容,速度非常快,和你直接浏览一个html页面的速度相差无几。

 

下面我们来具体介绍下如何实现这个页面的自动生成吧。

单击Home主页的时候,我们就自动生成一个页面,生成代码如下所示。

代码

        /// <summary>
        
/// 导航到主页面
        
/// </summary>
        public void GoHome()
        {
            
string tempFile = "Favorite/index.txt";
            
try
            {
                HelperClassAdapter helper 
= new HelperClassAdapter(tempFile);
                helper.Execute();
                
//MessageUtil.ShowTips("生成成功");

                
bool found = false;
                
foreach (IDockContent content in this.dockPanel.Documents)
                {
                    MainIE form 
= content as MainIE;
                    
if (form != null && form.extendedWebBrowser1.DocumentTitle == "收藏夹导航")
                    {
                        found 
= true;
                        form.Activate();
                        
break;
                    }
                }
                
if (!found)
                {
                    
this._currentUrl = "my:home";
                    AddMainIE();
                }
            }
            
catch (Exception ex)
            {
                LogHelper.Error(ex);
                MessageUtil.ShowTips(ex.Message);
            }
        }

 

这里其实主要的就是生成代码的类HelperClassAdapter,这个类通过获得模版文件,通过NeVelocity引擎把指定格式的内容附加到模版文件中,然后输出文件即可。

代码

    public class HelperClassAdapter : AbstractAdapter
    {
        
public HelperClassAdapter(string templateFile)
            : 
base(templateFile)
        {
        }
        
public override void Execute()
        {
            
string startPath = Path.Combine(Application.StartupPath, "Favorite");
            
if (!Directory.Exists(startPath))
            {
                Directory.CreateDirectory(startPath);
            }                        
            
//遍历目录和文件,根据文件模版输出到文件中

            
#region 根据目录放置的字典
            Dictionary
<string, List<FavoriteInfo>> fileDict = new Dictionary<string, List<FavoriteInfo>>();
            
string[] dirArray = Directory.GetDirectories(startPath);
            
foreach (string dir in dirArray)
            {
                
string dirName = new DirectoryInfo(dir).Name;
                
if (dirName.ToLower() == "icon" || dirName.ToLower() == "images"//系统图标跳过
                    continue;
                
string[] fileArray = Directory.GetFiles(dir);
                List
<FavoriteInfo> fileList = new List<FavoriteInfo>();
                FavoriteInfo info 
= null;
                
foreach (string file in fileArray)
                {
                    
if (!string.IsNullOrEmpty(file))
                    {
                        info 
= new FavoriteInfo();
                        info.Category 
= dirName;
                        info.Title 
= new FileInfo(file).Name.Replace(".url""");
                        INIFileUtil iniUtil 
= new INIFileUtil(file);
                        info.Url 
= iniUtil.IniReadValue("InternetShortcut""URL");
                        fileList.Add(info);
                    }
                }
                
if (!fileDict.ContainsKey(dir))
                {
                    fileDict.Add(dir, fileList);
                }
            } 
            
#endregion
            
//设置输出文件名称和页面变量,然后输出文件
            this.FileNameOfOutput = Path.Combine(Application.StartupPath, "Favorite/index.htm");
            context.Put(
"FileDict", fileDict); 
            OutputFile();
        }
    }

 

 

其中模版文件index.txt文件很简单,部分关键代码如下所示,其中主要关注有$开始的运算符和变量,这些代码是实现对象到页面内容的转换的。 其中#foreach($FavoriteList in ${FileDict.Values})是遍历里面的对象,进行循环处理的,语法也很简单。

代码

<DIV id=content>
  
<!–/ sidebar–><!–/ board–>
<div class=box id=coolsites>
      
<h2 align="center" class="style2">收藏夹导航<class="" id=cslayout title=居中对齐/左对齐>居中对齐/左对齐</a></h2>
      
<div id=list>
#foreach($FavoriteList in ${FileDict.Values})
        
<dl>
#set($count = 0)
#foreach($FavoriteInfo in $FavoriteList)
#if($count==0)
          
<dt><href="#">[ ${FavoriteInfo.Category.ToString()} ]</a>
#end
#set($count = $count + 1)
          
<dd><href="${FavoriteInfo.Url.ToString()}">${FavoriteInfo.Title.ToString()}</a>
#end
        
</dd></dl>
#end
      
</div>
    
</div>
  
</div>

 

 另外FavoriteInfo是一些基本属性的实体类,代码很简单:

代码

    public class FavoriteInfo
    {
        
private string m_category;//目录分类名称
        private string m_title;//网页标题
        private string m_url;//网页链接

        
/// <summary>
        
/// 目录分类名称
        
/// </summary>
        public string Category
        {
            
get { return m_category; }
            
set { m_category = value; }
        }
        
/// <summary>
        
/// 网页标题
        
/// </summary>
        public string Title
        {
            
get { return m_title; }
            
set { m_title = value; }
        }
        
/// <summary>
        
/// 网页链接
        
/// </summary>
        public string Url
        {
            
get { return m_url; }
            
set { m_url = value; }
        }
    }

 

 HelperClassAdapter的基类如下所示,主要是定义一些公共的属性变量及操作,方便被继承成各种类型的子类。

代码

    public abstract class AbstractAdapter : IAdapter
    {
        
#region 保护成员变量
        
protected VelocityContext context;
        
protected Template template;
        
protected string templateFile;
        
protected const string NVELOCITY_PROPERTY = "nvelocity.properties";
        
#endregion
        
#region 成员变量及公共属性
        
private string fileExtension = ".htm"//输出的文件后缀名,如".cs"。
        private string directoryOfOutput = "Articles"//输出文件的文件夹名称
        private string fileNameOfOutput; //输出的文件名称

        
/// <summary>
        
/// 输出文件的文件夹名称, 如"Entity","Common"等
        
/// </summary>
        public string DirectoryOfOutput
        {
            
set { directoryOfOutput = value; }
            
get { return directoryOfOutput; }
        }
        
/// <summary>
        
/// 输出的文件名称. 如果想输出的文件为 "A.cs", 那么文件名为"A".
        
/// 默认的文件名称为模板文件的名称,没有后缀名.
        
/// </summary>
        public string FileNameOfOutput
        {
            
set { fileNameOfOutput = value; }
            
get { return fileNameOfOutput; }
        }
        
/// <summary>
        
/// 输出的文件后缀名,如".cs"。
        
/// </summary>
        public string FileExtension
        {
            
get { return fileExtension; }
            
set { fileExtension = value; }
        }
        
#endregion
        
/// <summary>
        
/// 根据参数初始化基类的Adapter
        
/// </summary>
        
/// <param name="templateFile">模板文件名称</param>
        public AbstractAdapter(string templateFile)
        {
            
#region 判断输入的参数是否有效
            
if (templateFile == null)
            {
                
const string error = "Invalid parameter of templateFile.";
                LogHelper.Error(error);
                
throw new ArgumentException(error, "templateFile");
            }
            
#endregion
            
this.templateFile = templateFile;
          
            InitTemplateEngine(); 
//初始化模板引擎

            fileNameOfOutput 
= GetFileNameFromTemplate(templateFile); // 默认情况下, 输出的文件名称为模板名称           
            directoryOfOutput = "Articles"// 默认情况下,放到Common目录下面
        }
        
/// <summary>
        
/// 创建输出到文件中的方法
        
/// </summary>
        public virtual void Execute()
        {
        }
        
/// <summary>
        
///根据模板创建输出的文件
        
/// </summary>
        public virtual void OutputFile()
        {
            
if (template != null)
            {
                
string filePath = Path.GetDirectoryName(this.fileNameOfOutput);
                DirectoryInfo dir 
= new DirectoryInfo(filePath);
                
if (!dir.Exists)
                {
                    dir.Create();
                }
                LogHelper.Debug(
string.Format("Class file output path:{0}"this.fileNameOfOutput));
                
using (StreamWriter writer = new StreamWriter(this.fileNameOfOutput, false))
                {
                    template.Merge(context, writer);
                }
            }
        }
        
/// <summary>
        
/// 根据模板创建代码输出到字符串流中
        
/// </summary>
        
/// <returns>根据模板生成的代码</returns>
        public virtual string OutputString()
        {
            
string code = string.Empty;
            
if (template != null)
            {
                
using (StringWriter writer = new StringWriter())
                {
                    template.Merge(context, writer);
                    code 
=  writer.GetStringBuilder().ToString();
                }
            }
            
return code;
        }
        
/// <summary>
        
/// 初始化NVelocity模板引擎并加载程序的配置信息e
        
/// </summary>
        protected void InitTemplateEngine()
        {
            Velocity.Init(NVELOCITY_PROPERTY);
            
//Velocity.Init();
            
// Make a context object and populate with the data.  This is where the Velocity engine 
            
// gets the data to resolve the references (ex. $foreignList) in the template
            context = new VelocityContext();
            
try
            {
                template 
= Velocity.GetTemplate(templateFile);
            }
            
catch (ResourceNotFoundException re)
            {
                
string error = string.Format("Cannot find template " + templateFile);
                LogHelper.Error(error);
                
throw new Exception(error, re);
            }
            
catch (ParseErrorException pee)
            {
                
string error = string.Format("Syntax error in template " + templateFile + ":" + pee.StackTrace);
                LogHelper.Error(error);
                
throw new Exception(error, pee);
            }
        }
        
#region 辅助方法
        
/// <summary>
        
/// 从模板文件名称获取输出文件名的方法
        
/// </summary>
        
/// <param name="templateFileName">带后缀名的模板文件名</param>
        
/// <returns>输出的文件名(无后缀名)</returns>
        private string GetFileNameFromTemplate(string templateFileName)
        {
            
int sindex1 = templateFileName.LastIndexOf('/');
            
int sindex2 = templateFileName.LastIndexOf('\\');
            
int sindex = (sindex1 > sindex2) ? sindex1 : sindex2;
            
int eindex = templateFileName.IndexOf('.');
            
if (sindex < eindex)
            {
                
return templateFileName.Substring(sindex + 1, eindex  sindex  1);
            }
            
else
            {
                
return templateFileName.Substring(sindex);
            }
        }
        
#endregion
    }

 

    public interface IAdapter
    {
        
/// <summary>
        
/// 创建输出到文件中的方法
        
/// </summary>
        void Execute();
    }

 

 另外,读取INI文件,需要的辅助类代码INIFileUtil如下所示。

代码

    public class INIFileUtil
    {
        
public string path;
        
public INIFileUtil(string INIPath)
        {
            path 
= INIPath;
        }
        [DllImport(
"kernel32")]
        
private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);
        [DllImport(
"kernel32")]
        
private static extern int GetPrivateProfileString(string section,string key,string def, StringBuilder retVal,int size,string filePath);
    
        [DllImport(
"kernel32")]
        
private static extern int GetPrivateProfileString(string section, string key, string defVal, Byte[] retVal, int size, string filePath);
        
/// <summary>
        
/// 写INI文件
        
/// </summary>
        
/// <param name="Section"></param>
        
/// <param name="Key"></param>
        
/// <param name="Value"></param>
        public void IniWriteValue(string Section,string Key,string Value)
        {
            WritePrivateProfileString(Section,Key,Value,
this.path);
        }
        
/// <summary>
        
/// 读取INI文件
        
/// </summary>
        
/// <param name="Section"></param>
        
/// <param name="Key"></param>
        
/// <returns></returns>
        public string IniReadValue(string Section,string Key)
        {
            StringBuilder temp 
= new StringBuilder(255);
            
int i = GetPrivateProfileString(Section,Key,"",temp, 255this.path);
            
return temp.ToString();
        }
        
public byte[] IniReadValues(string section, string key)
        {
            
byte[] temp = new byte[255];
            
int i = GetPrivateProfileString(section, key, "", temp, 255this.path);
            
return temp;
        }
        
/// <summary>
        
/// 删除ini文件下所有段落
        
/// </summary>
        public void ClearAllSection()
        {
            IniWriteValue(
null,null,null);
        }
        
/// <summary>
        
/// 删除ini文件下personal段落下的所有键
        
/// </summary>
        
/// <param name="Section"></param>
        public void ClearSection(string Section)
        {
            IniWriteValue(Section,
null,null);
        }
    }

 

主要研究技术:代码生成工具、Visio二次开发
    
    转载请注明出处:
撰写人:伍华聪  http:
//www.iqidi.com 
 

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

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

支付宝扫一扫打赏

微信扫一扫打赏