1.为什么要用Lucene,而不用直接从数据库里搜索记录?
主要是考虑到几个因素:(1)性能问题,Lucene是基于文件索引的搜索机制,性能要比数据库里检索更快,特别是数据量大的时候两者区别比较明显。数据 库用Select检索时,默认在执行SQL语句时,会对表锁定,直到查询完成;(2)目前很多网站,都已经将页面静态化,这种情况下,直接用生成的文件编 制索引,再利用Lucene来检索,可以不用查询数据库,减轻了数据库的压力;(3)Lucene可以更方便的进行分词,支持多个关键字检查等操作,在实 现上要比SQL方便;(4)直接基于文件系统的检索,不会有SQL注入风险
2.创建索引
基本上有二种思路,适用于不同的情况
(1)如果网站本身就是静态化的,可以直接读取静态Html文件,来创建索引。注意:如果要实现特定标签的搜索(比如要按产品价格,产品编号,产品摘要, 发布时间等精确搜索产品信息),在读取文件内容时,需要利用正则表达式对Html文件进行匹配分析,得到各个标签的值,再创建Field,加入 Document,最后调用IndexWriter的相应方法创建索引
(2)也可以直接从数据库里查询各标签的值,再按(1)的方法,生成Field–>Document–>加入IndexWriter
3.索引的维护
显然,不可能每次查询都全部将索引生成一次,这里的索引维护主要是索引更新和索引删除,也有两种思路:
(1)找个访问比较少的时段,比如每天晚上0点,做一个C/S程序放在服务器上,用定时器或计划任务全部重新生成索引
(2)更合理有效的方式,是当信息发生修改或删除时,索引维护程序能得到通知,仅更新特定信息的索引就可以了。这里建议用消息队列机制,网站上有信息发生 增,删,改时,将唯一标识值,发送到消息队列,然后索引维护程序监听消息队列,一有消息了,马上根据唯一标识,到数据库里取出修改的信息(或读取修改过的 Html文件),更新指定索引即可
4.分词问题
国内有一些公开的分词组件,可以直接利用,当然有一些是商业化的
[Lucene]DotLucene:37行代码实现全文搜索
DotLucene是一个强有力的开源全文搜索引擎,它是从Apache的Lucene(java)项目移植到.Net(C#)上的。
DotLucene的效率非常高,并且还具有对搜索结果评级、高光、搜索非结构数据以及本地化等特点。它还和Lucene的索引兼容,因此你可以在不同的平台间迁移而不会丢失任何索引数据。
本文介绍了如何通过简洁的代码来使用DotLucene完成全文搜索功能。
本文翻译自CodeProject上 Dan Letecky 的 DotLucene: Full-Text Search for Your Intranet or Website using 37 Lines of Code 一文,文章版权为原作者所有。
译者:Samuel Chen

DotLucene: 优秀的全文搜索引擎
有可能用37行代码写一个全文搜索么? 恩,我正准备使点小技巧用DotLucene来完成这个麻烦的工作. DotLucene 是一个Jakarta Lucene搜索引擎的移植项目,该项目由 George Aroush et al 维护。下面是它的一些特性:
- 它能被用在 ASP.NET、WinForms 或者 console 应用;
- 非常高效的性能;
- 搜索结果评级;
- 搜索结果中查询关键字高光 ;
- 搜索结构化和非结构化数据;
- Metadata 搜索 (时间查询、搜索指定域/字段…)
- 索引大小大约是索引文本的30%;
- 并且能存储所有编入索引的文档 Can store also full indexed documents
- 纯.Net托管代码,单个执行文件 (244 kB)
- 非常友好的许可 (Apache Software License 2.0)
- 本地化 (支持 巴西语、捷克语、中文、荷兰语、英语、法语、日语、韩语和俄语)
- 可扩展 (源代码已包含)
注意
不要过于在意代码行数。我将用不超过37行代码给你演示他的核心功能,但是要做成一个真正实用的应用,你还需要花更多的时间…
演示项目
这里,我们将做一个简单的项目演示怎么去做到如下几点:
- 索引在指定目录(包括子目录)中找到的Html文件
- 用一个ASP.NET应用程序来搜索索引
- 搜索结果中高亮显示查询的单词
DotLucene还具有更多的潜力。在实际的应用中你大概想这么去做:
- 当目录中怎就新文档时添加到索引,而不用重新编译整个索引
- 包含各种文件类型。DotLuncene能够索引任何能转换成纯文本的文件类型
为什么不使用微软索引服务(Microsoft Indexing Server)?
如果你喜欢用索引服务,没问题。然而,使用DotLucene会有更多好处:
- DotLucene 是一个100%托管代码的单执行文件,不需要任何依赖
- 它能被使用到一个共享主机。如果事先准备好索引,你可以不需要磁盘的写权限
- 使用它,你可以从任何源((数据库、网站…)索引任何类型数据(电子邮件、XML、HTML文件…)。那是因为你需要提供纯文本给索引器(Indexer),载入和解析取决于你
- 允许你选择要包含在索引中的指定属性("字段"),从而你可以使用这些字段来搜索(例如,作者、日期、关键字等)
- 它是一个开源软件
- 它易于扩展
第1行:建立索引
下面的代码从存盘存储建立一个新的索引,directory是存储索引的目录路径参数。
IndexWriter writer = new IndexWriter(directory, new StandardAnalyzer(), true);
这个例子中我们总是重新创建索引(In this example we always create the index from scratch),但这不是必须的,你也可以打开一个已有的索引并添加文档进去。你还可以通过删除然后添加它们的新版本来更新现存的文档(译注:这里应该 是指对象的创建)
第2 – 12行:添加文档
我们为每一个HTML文档添加两个字段到索引:
- "text" 字段,容纳HTML文件的文本内容(去除了标记),文本数据本身并不会存储在索引中
- "path" 字段,容纳文件路径,它将会被(索引并)完整的存入索引中
public void AddHtmlDocument(string path)
{
Document doc = new Document();
string rawText;
using (StreamReader sr = new StreamReader(path, System.Text.Encoding.Default))
{
rawText = parseHtml(sr.ReadToEnd());
}
doc.Add(Field.UnStored("text", rawText));
doc.Add(Field.Keyword("path", path));
writer.AddDocument(doc);
}
第13 – 14行:优化并保存索引
添加完文档后,你需要关闭索引器。使用优化将会提高搜索性能。
writer.Optimize();
writer.Close();
第15行:打开索引搜索
在做任何搜索之前,你需要打开索引。directory参数是存储索引的目录路径。
IndexSearcher searcher = new IndexSearcher(directory);
第16 – 27行:搜索
现在,我们解析查询了("text"是默认搜索字段)
Query query = QueryParser.Parse(q, "text", new StandardAnalyzer()); Hits hits = searcher.Search(query);
变量hits是搜索结果文档的集合,我们将通过它来将结果存储到DataTable
DataTable dt = new DataTable();
dt.Columns.Add("path", typeof(string));
dt.Columns.Add("sample", typeof(string));
for (int i = 0; i < hits.Length(); i++)
{
// get the document from index
Document doc = hits.Doc(i);
// get the document filename
// we can't get the text from the index because we didn't store it there
DataRow row = dt.NewRow();
row["path"] = doc.Get("path");
dt.Rows.Add(row);
}
第28 – 37行:高亮Lines 28 – 37: Query Highlighting
我们先创建一个高亮器对象highlighter,并将使用加黑(bold)字体来高亮显示(<B>查询词</B>)。
QueryHighlightExtractor highlighter = new
QueryHighlightExtractor(query, new StandardAnalyzer(), "<B>", "</B>");
通过对结果遍历,我们将载入原文中最相似的部分。
for (int i = 0; i < hits.Length(); i++)
{
// ...
string plainText;
using (StreamReader sr = new StreamReader(doc.Get("filename"),
System.Text.Encoding.Default))
{
plainText = parseHtml(sr.ReadToEnd());
}
row["sample"] = highlighter.GetBestFragments(plainText, 80, 2, "...");
// ...
}
资源
[Lucene]Lucene.Net系列一 ---simple example
What’s Lucene
Lucene是一个信息检索的函数库(Library),利用它你可以为你的应用加上索引和搜索的功能.
Lucene的使用者不需要深入了解有关全文检索的知识,仅仅学会使用库中的一个类,你就为你的应用实现全文检索的功能.
不过千万别以为Lucene是一个象google那样的搜索引擎,Lucene甚至不是一个应用程序,它仅仅是一个工具,一个Library.你也 可以把它理解为一个将索引,搜索功能封装的很好的一套简单易用的API.利用这套API你可以做很多有关搜索的事情,而且很方便.
What Can Lucene Do
Lucene可以对任何的数据做索引和搜索. Lucene不管数据源是什么格式,只要它能被转化为文字的形式,就可以被Lucene所分析利用.也就是说不管是MS word, Html ,pdf还是其他什么形式的文件只要你可以从中抽取出文字形式的内容就可以被Lucene所用.你就可以用Lucene对它们进行索引以及搜索.
How To Use Lucene — A Simple Example
示例介绍:
为作为输入参数的文件夹下的所有txt类型的文件做索引,做好的索引文件放入index文件夹.
然后在索引的基础上对文件进行全文搜索.
1. 建立索引
IndexWriter是对索引进行写操作的一个类,利用它可以创建一个索引对象然后往其中添加文件.需要注意它并不是唯一可以修改索引的类.在索引建好后利用其他类还可以对其进行修改.
构造函数第一个参数是建立的索引所要放的文件夹的名字.第二个参数是一个分析对象,主要用于从文本中抽取那些需要建立索引的内容,把不需要参与建索 引的文本内容去掉.比如去掉一些a the之类的常用词,还有决定是否大小写敏感.不同的选项通过指定不同的分析对象控制.第三个参数用于确定是否覆盖原有索引的.
第二步就是利用这个writer往索引中添加文件.具体后面再说.
第三步进行优化.
第四步关闭writer.
下面具体看看第二步:
主要就是两个函数一个用于处理文件夹(不是为文件夹建立索引),一个用于真正为文件建立索引.
因此主要集中看一下IndexFile这个方法.首先建立Document对象,然后为Document对象添加一些属性Field.你可以把Document对象看成是虚拟文件,将来将从此获取信息.而Field则看成是描述此虚拟文件的元数据(metadata).
其中Field包括四个类型:
|
Keywork |
该类型的数据将不被分析,而会被索引并保存保存在索引中. |
| UnIndexed | 该类型的数据不会被分析也不会被索引,但是会保存在索引. |
| UnStored | 和UnIndexed刚好相反,被分析被索引,但是不被保存. |
| Text | 和UnStrored类似.如果值的类型为string还会被保存.如果值的类型为Reader就不会被保存和UnStored一样. |
最后将每一个Document添加到索引当中.
需要注意的是索引不仅可以建立在文件系统上,也可以建立在内存中.
例如
IndexWriter writer = new IndexWriter("index", new StandardAnalyzer(), true);
在第一个参数不是指定文件夹的名字而是使用Directory对象,并使用它的子类RAMDirectory,就可以将索引建立在内存当中.
2. 对索引进行搜索
第一步利用IndexSearcher打开索引文件用于后面搜索,其中的参数是索引文件的路径.
第二步使用QueryParser将可读性较好的查询语句(比如查询的词lucene ,以及一些高级方式lucene AND .net)转化为Lucene内部使用的查询对象.
第三步执行搜索.并将结果返回到hits集合.需要注意的是Lucene并不是一次将所有的结果放入hits中而是采取一次放一部分的方式.出于空间考虑.
至此,本文演示了如何从一个文件夹下的所有txt文件中查找特定的词。并围绕该个实例介绍了lucene.net的索引的建立以及如何针对索引进行搜索.最后给出源代码供大家学习.
[Lucene]Lucene教程站
介绍Lucene知识比较全面的一个站
推荐:http://blog.tianya.cn/blogger/view_blog.asp?BlogID=114714&CategoryID=110243&idWriter=0&Key=0
具体教程:
[转]Lucene 中文分词的 highlight 显示
Lucene–基于Java的全文搜索引擎简介[转]
[lucene]关于对xml的lucene索引
[Lucene]用Lucene建立索引及查询示例
[Lucene]为自己的系统搞个全文搜索
为自己的系统搞个全文搜索
在本文我又提到lucene了,在java业界,提到全文检索,几乎没有什么人不知道它。
用google搜索一下,满世界都是有关资料。具有代表性的就是车东的“基于Java的全
文索引引擎Lucene简介”,我要写的也就只有最简单的三板斧,再加上支持中文的
ChineseAnalyzer以及按照时间排序的搜索结果排序方法。这些都可以在其他地方找
到相关资料,我只是把他们提出来,作为lucence应用中经常遇到的麻烦解决办法。
去年MSN上面有个朋友跟我提到希望用lucene构建个网站的全文检索,我当时就觉得
很简单,直说没问题没问题,不过他提到一个要求就是搜索结果要安装时间排序,
我查阅了些资料,发现lucene并不提供用户自定义排序方式,而只能按照自己相关
性算法排序。后来我在车东的weblucene项目找到了IndexOrderSearcher。解决了结
果排序常规需求。IndexOrderSearcher跟一般IndexSearch使用差不多,仅仅在构建
对象的时候多加一个参数IndexOrderSearcher.ORDER_BY_DOCID_DESC
IndexOrderSearcher indexsearcher =
new IndexOrderSearcher("/home/lucenetest/index",IndexOrderSearcher.ORDER_BY_DOCID_DESC);
新版本的lucene还提供了一个MultiFieldQueryParser,可以同时检索多个字段,以前
QueryParser比较麻烦。
private static ChineseAnalyzer chineseAnalyzer = new ChineseAnalyzer();
public Hits search(String queryText)
{
if (queryText == null)
{
return null;
}
Query query;
try
{
query = MultiFieldQueryParser.parse(queryText, new String[]{"title"},chineseAnalyzer);
return indexsearcher.search(query);
}
catch(Exception e)
{
return null;
}
}
下面是构建索引,定时从数据库取出数据索引,做完记录完成时间,我是把时间写入一个txt文件。
package com.test.search;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.*;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import java.io.*;
import java.SQL.*;
import java.util.Date;
import com.test.db.*;
import com.test.utility.*;
/**
* Title: SearchIndexer
* Description: 全文索引
* Copyright: Copyright (c) 2001
* Company: test
* @author Sean
* @version 1.0
*/
public class SearchIndexer
{
private String indexPath = null;
protected Analyzer analyzer = new ChineseAnalyzer();
public SearchIndexer(String s)
{
this.indexPath = s;
}
/**
* 索引某日期以前的所有文档
* @param fromdate
* @return
*/
public final void updateIndex(String fromdate)
{
Connection conn = DbUtil.getCon();
IndexWriter indexWriter = null;
try
{
indexWriter = getWriter(false);
//索引发布系统内部文件
PreparedStatement pstm = conn.prepareStatement(
"select title,body,creationtime from document
where creationtime > '" + fromdate +
"' order by creationtime");
ResultSet rs = pstm.executeQuery();
while (rs.next())
{
String creationtime = rs.getString("creationtime");
String title = rs.getString("title");
String body = rs.getString("body");
if (title == null || body == null)
{
continue;
}
try
{
addDocsToIndex(title,body, creationtime,indexWriter);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
indexWriter.optimize();
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
indexWriter.close();
conn.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/**
* 检查索引文件是否存在
* @param s
* @return 索引是否存在
*/
private boolean indexExists(String s)
{
File file = new File(s + File.separator + "segments");
return file.exists();
}
/**
* 增加一组索引
* @param title
* @param body
* @param creationtime
* @param indexwriter
* @return
*/
private final void addNewsToIndex(String docid, String url,String title, String body,
String ptime, IndexWriter indexwriter) throws IOException
{
if (indexwriter == null)
{
return;
}
else
{
try
{
Document document = new Document();
document.add(Field.Text("title", title));
document.add(Field.Text("body", body));
document.add(new Field("creationtime", creationtime, true, true, false));
indexwriter.addDocument(document);
}
catch (Exception ex)
{
ex.printStackTrace();
}
return;
}
}
/**
* 取得IndexWriter
* @param flag 是否新建索引
* @return IndexWriter
*/
private IndexWriter getWriter(boolean flag) throws IOException
{
String s = indexPath;
if (s == null)
{
throw new IOException("索引文件路径设置错误.");
}
indexPath = s + File.separator + "search";
IndexWriter indexwriter = null;
if (flag)
{
try
{
indexwriter = new IndexWriter(indexPath, analyzer, true);
}
catch (Exception exception)
{
System.err.println("ERROR: Failed to create a new index writer.");
exception.printStackTrace();
}
}
else
{
if (indexExists(indexPath))
{
try
{
indexwriter = new IndexWriter(indexPath, analyzer, false);
}
catch (Exception exception1)
{
System.err.println("ERROR: Failed to open an index writer.");
exception1.printStackTrace();
}
}
else
{
try {
indexwriter = new IndexWriter(indexPath, analyzer, true);
}
catch (Exception exception2)
{
System.err.println("ERROR: Failed to create a new index writer.");
exception2.printStackTrace();
}
}
}
return indexwriter;
}
public static void main(String[] args)
{
String lastUpdate = "/home/lucenetest/lastUpdate.txt";
SearchIndexer searchIndexer = new SearchIndexer("/home/lucenetest/index");
//取出上次更新时间
String str = Util.readTxtFile(lastUpdate);
if(str==null || str.length()==0)
{
str = new java.util.Date().toString();
}
searchIndexer.updateIndex(str);
//写入当前时间
Util.writeTxtFile(lastUpdate,new java.util.Date(),false);
}
}
写个cmd或者sh在相应操作系统下面定时执行SearchIndexer就可以了
[SQLServer]SQL Server2005全文索引
Microsoft SQL Server 2005 引入了新的 Transact-SQL 数据定义语言 (DDL) 语句,用来创建、实现和管理全文目录和索引。以下是新的全文搜索 DDL 语句的列表。
Create FULLTEXT CATALOG (Transact-SQL)
使用此语句可以为数据库创建全文目录。
Create FULLTEXT INDEX (Transact-SQL)
使用此语句可以针对数据库某个表的一列或多列创建全文索引。
Alter FULLTEXT CATALOG (Transact-SQL)
使用此语句可以更改全文目录的属性。
Alter FULLTEXT INDEX (Transact-SQL)
使用此语句可以更改全文索引的属性。
Drop FULLTEXT CATALOG (Transact-SQL)
使用此语句可以删除全文目录。
Drop FULLTEXT INDEX (Transact-SQL)
使用此语句可以从指定的表中删除全文索引。
———————————————————————————-
而以下是老旧的sql2000的方法:
———————————————————————————-
一个完整的SQL SERVER数据库全文索引的示例。(以pubs数据库为例)
首先,介绍利用系统存储过程创建全文索引的具体步骤:
1) 启动数据库的全文处理功能 (sp_fulltext_database)
2) 建立全文目录 (sp_fulltext_catalog)
3) 在全文目录中注册需要全文索引的表 (sp_fulltext_table)
4) 指出表中需要全文索引的列名 (sp_fulltext_column)
5) 为表创建全文索引 (sp_fulltext_table)
6) 填充全文目录 (sp_fulltext_catalog)
———********示例********————-
以对pubs数据库的title和notes列建立全文索引,之后使用索引查询title列或notes列中包含有datebase 或computer字符串的图书名称:
在这之前,需要安装Microsoft Search服务,启动SQL server全文搜索服务
user pubs –打开数据库
go
–检查数据库pubs是否支持全文索引,如果不支持
–则使用sp_fulltext_database 打开该功能
if(select databaseproperty('pubs','isfulltextenabled'))=0
execute sp_fulltext_database 'enable'
–建立全文目录FT_PUBS
execute sp_fulltext_catalog 'FT_pubs','create'
–为title表建立全文索引数据元
execute sp_fulltext_table 'title','create','FT_pubs','UPKCL_titleidind'
–设置全文索引列名
execute sp_fulltext_column 'title','title','add'
execute sp_fulltext_column 'title','notes','add'
–建立全文索引
–activate,是激活表的全文检索能力,也就是在全文目录中注册该表
execute sp_fulltext_table 'title','activate'
–填充全文索引目录
execute sp_fulltext_catalog 'FT_pubs','start_full'
go
–检查全文目录填充情况
While fulltextcatalogproperty('FT_pubs','populateStatus') <>0
begin
–如果全文目录正处于填充状态,则等待30秒后再检测一次
waitfor delay '0:0:30'
end
–全文目录填充完成后,即可使用全文目录检索
select title
form
where CONTAINS(title,'database')
or CONTAINS(title,'computer')
or CONTAINS(notes,'database')
or CONTAINS(notes,'database')
'————–以下介绍一下全文操作类的系统存储过程
过程名称:sp_fulltext_service
执行权限:serveradmin或系统管理员
作 用:设置全文搜索属性
过程名称:sp_fulltext_catalog
执行权限:db_owner及更高角色成员
作 用:创建和删除一个全文目录,启动或停止一个全文目录的索引操作
过程名称:sp_fulltext_database
执行权限:db_owner角色成员
作 用:初始化全文索引或删除数据库中所有全文目录
过程名称:sp_fulltext_table
执行权限:db_ddladnmin或db_owner角色成员
作 用:将一个表标识为全文索引表或非全文索引表
过程名称:sp_fulltext_column
执行权限:db_ddladnmin角色成员
作 用:指出一个全文索引表中的那些列假如或退出全文索引
[设计]如何设计通用的网站模板
现在网络上已经到处可以看到使用模板开发出来的网站。使用模板开发网站有很多好处,最主要的就是模板与程序完全脱离,用户可以根据规定好的标签任意开发模 板,导入到模板引擎里就能正常运行。所以美工人员跟程序编写人员彻底的独立了。提高了开发网站的效率,程序的重用性发挥的淋漓尽致。
智能建站系统、速成网站、自助建站系统、只会打字就能做网站,等等广告字眼我们已经不再陌生了,所有的这些无非都是围绕着模板做文章。也正是因为 这样的系统越来越普及,对于要求不高的企业或者个人用户,拥有一个完全属于自己的网站,用现成的模板要比找网络公司定制省钱的多。性价比要高的多,所以目 前中小型网络公司的生存问题堪忧。
提供模板做论坛的discuz公司,各位站长应该都很熟悉,但是做企业网站、独立购物网系统,国内做的比较好的几家公司,想必大家可能不太熟悉:ShopEx 、 携购网店系统(ShopXG) 、HiShop 、 狼烟网络(mynet.cn) 等等,大家有机会可以去他们的官网看看各自的优势。
下面我们来详细讲解下如何开发网站模板。
涉及到模板的部分我们可以分成以下几块:自定义标签、模板文件、数据控制项、模板引擎
1. 自定义标签 自定义标签是模板文件与模板引擎之间交互的基础,也可以说是协议。 目前网络上普遍的标签样式为:{$****} {#*****#},这样的表示方法,主要是为了区分html等脚本标签。 标签的内容区可以设置多种属性。比如len=100 表示数据长度不超过100个字节。 标签变量根据不同的类型,我们可以把名称规定为如下方式:
{$var_**} 变量标签,表示这个标签的数据来源是某一个字段的值
{$const_**} 常量标签,表示这个标签是一个常量数据,比如,当前的日期等
{$temp_small} 小模板数据。(什么叫小模板,我们在后面详细讲解)
{$page_**} 分页数据。例如首页,上页,下页等翻页的代码部分。等等。
举例:{$var_news_title len=30} 表示显示新闻的标题,如果新闻标题的字数超过 30个字,那么截取。
2.模板文件
模板文件就是由美工人员开发的脚本代码,里面不涉及到任何程序。由于数据经常会涉及到一个循环显示的问题,所以我们把模板文件又分成:大模板、小模板。
模板文件一般都是普通的html文件,源代码里包含了事先约定好的自定义标签,
图标说明每个模块的共性:

图1:新闻列表 图2:产品列表
大家看上面两个模块,一个是新闻列表,一个是产品列表。无论从数据类型还是展现方式上乍一看截然不同。
但是大家仔细的看一下,很容易看出来他们其实有很多共同的特点–他们都是有大模板(模块的外框部分)、小模板(模块的数据循环部分)组成。另外,大家可以去找个网站分解下看看。是不是都可以把他们分解成不同的模块,然后每个模块又可以分成大模板、小模板组成。
我们以上图中新闻列表来给大家讲解下:
大模板文件就是整个外框部分。基本html如下面所示:
<div class=”newslist”>
<h>携购网店 – 不可多得的创业好项目</h>
<ul>代理商加盟携购之后能得到什么?!</ul>
<div>{$temp_small}</div>
</div>
从上面可以看出,大模板文件里并没有涉及到数据部分,只有一个小模板标签{$temp_small} ,当模板引擎解析到这个标签的时候,将对应的小模板文件解析后,用最终生成的html数据将该标签替换掉。
接下来,我们来看一下小模板的组成:
这里特别需要注意下,当模板引擎在解析小模板的时候,是把小模板的数据当作一个循环体,说明白些:比如有10条新闻,那么模板引擎将循环10次小模板数据,将具体的新闻内容分别去替换小模板里的标签,然后组合成一个最终的html.
小模板的脚本部分:
<ul clas=”small_item”>
<li>{$var_news_title len=100}</li>
<li>{$var_news_add_time}</li>
</ul>
当然,需要分页的时候,还需要做分页模板,解析引擎会解析分页模板后,将查询到的当前数据替换掉对应的分页变量标签,最后,替换掉大模板中的分页模板标签。
分页的脚本部分举例:
<a href="{$var_link_firstpage_link}" id="modulelist_linkup_first">首页</a>
<a href="{$var_link_prevpage_link}" id="modulelist_linkup_prev">上一页</a>
{$var_link_pageteam} <a href="{$var_link_nextpage_link}" id="modulelist_linkup_next">下一页</a>
<a href="{$var_link_lastpage_link}" id="modulelist_linkup_last">末页</a>总数:{$var_link_totalnum} 每页条数:{$var_link_perpagecnt}
总页数:{$var_link_totalpage}当前页码:{$var_link_curpagenum}/{$var_link_totalpage}
最后从结构上我们再总结下模板的组成关系:

3.数据控制部分
该部分是要将哪些数据展示在模板数据项的核心。主要包括以下几部分:
a. 查询条件 ,从数据库里要查出哪些数据。
b. 排序类型, 将查询得到的数据,通过何种方式进行排序展示。
c. 当前页码, 跟每页显示条数配合使用,
d. 每页显示条数。
e. 是否忽略URL地址里传过来的参数,这个项非常重要,因为像分页和查询,他们都需要从url将参数传过来,而有些定死的数据又不希望受到url参数的影响,所以该项在控制数据显示方面尤为重要。
f. 接受url的参数列表。等等.
有了数据控制部分,才能让相同类型的模块展示不同的数据。
4. 模板引擎
我们知道模板文件是静态的html脚本页面,它并不具有业务操作能力,单纯的模板没有任何存在的意义。需要模板引擎通过数据控制将获取到的数据按照模板文件规定的样式展示出来,
模板引擎的好坏,直接影响到整个程序的性能,模板要跟数据库打交道,由于模板文件有非常多的数据冗余,而且,设计不合理的模板,同个页面可能需要多次相同的数据库查询操作,如果模板引擎不能很好的区分出来。那么对数据库的压力也是非常大的。
如果大家对开发模板网站有兴趣,强烈推荐去用下携购公司开发的VTEditor可视化网站模板开发系统。官方网站:http://www.xiegoo.com/ .是目前唯一真正实现可视化模板编辑的系统。
[Google]搜索引擎 创意 shell
搜索引擎 创意 shell
主要功能:shell版的搜索引擎
自由言论:在web上用用shell也是一件挺有意思的事情,蛮有一种复古的感觉。感谢google提供这种shell检索的方式(help查看可用命令)。
页面截图:

[C#]虚拟主机上实现二级别域名解析(泛解析) (asp.net)
前两天写了一篇立主机无限二级域名解释的方式,不过由于服务器出了点问题,自己比较忙,这篇就拖了点时间才写出来!
现在实现无限二级域名解释的方式,如重写url的组件也相当多!实现方式也不少!实现方式也不难。
独立主机的实现方法最简单的一个可以参考:http://www.cnblogs.com/flyboy/archive/2009/01/06/1369932.html
不过不幸的是所有这些都要求主机支持域名泛解析,一旦拿到虚拟主机上,一切都枉然!
我也是在自己机器上做好后拿到虚拟主机上发现完全作废!不过也不是没办法!
下面就讲讲如何实现虚拟主机上实现二级别域名解析(泛解析) (ASP.NET)吧!
1、首先,在域名解析里,要把*.iloveyou.io 隐含转向指向你网站的某个转门用来判断的页面,注意,必须是隐含!我们假设为 http://www.iloveyou.io/wr.aspx
2、在http://www.iloveyou.io/wr.aspx 页面取的来路的路径!
protected void Page_Init(object sender, EventArgs e)
{
string path = Request.UrlReferrer.AbsoluteUri.ToLower();
。。。
}
这里取得的不是当前路径,而是来路路径,也就是转向前url的路径了!
取得后就进行你需要的处理! 用上一节的例子来讲,把 http://liangsan.iloveyou.io 解析到 http://www.iloveyou.io/love/?toName=liangsan 这个页面。
3、 用 Response.Redirect(newurl);来实现跳转~!
protected void Page_Init(object sender, EventArgs e)
{
string path = Request.UrlReferrer.AbsoluteUri.ToLower();//得到的如path =http://liangsan.iloveyou.io/
。。。
string newurl=…//如 http://www.iloveyou.io/love/?toName=liangsan
Response.Redirect(newurl);
}
具体的例子可以上一个爱情表白的网站看下: http://www.iloveyou.io
缺点,不过这个方法有个缺点就是,百度收录页面看不到二级域名页面的内容,不利搜索引擎!
不过因为我没有自己独立主机,又要实现,用户可以申请 “心上人名字.iloveyou.io"的域名做为表白使用,只能放弃搜索引擎了!
不知道朋友你有没什么更好的解决方法,有的话请告知小弟!谢谢!
以上就是本人所知道和已经实现的虚拟主机上实现二级别域名解析(泛解析) (ASP.NET),如有不足请指正!谢谢!
[Tool]ASP.NET程序调试经常要用的辅助工具
在进行ASP.NET调试的时候,我们经常需要借助一些外部工具来辅助我们。俗话说,工欲善其事 必先利其器。可别小看了这些工具,它是你解决复杂问题的必备利器。比较常用的有这些:
HTTP抓包工具: Microsoft Network Monitor,Fiddler2,HttpWatcher 等,主要用来查看HTTP消息的header,以及body。
代码查看器: Reflector,利用反编译来查看assembly里的代码。通过这个工具,我们可以很轻易的看到.NET Framework的一些功能是怎么实现的。
文件监视器: Process Monitor,可以用来监视系统的哪些文件正在被修改,注册表中有什么改动等等,功能非常强大。
数据库工具:SQL Sever Profiler,可以用来查看SQL Server正在执行哪些脚本。对于和SQL Server通信的程序的调试,它是非常实用的。
其实还有很多好用的工具,但是如果能熟练使用这几个工具了,大部分的问题都能轻易解决了。下次将会介绍一下IIS 7中调试ASP.NET程序的一些实用的方法。
Mikel