一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)
前言
这次开发的博客主要功能或特点:
第一:可以兼容各终端,特别是手机端。
第二:到时会用到大量html5,炫啊。
第三:导入博客园的精华文章,并做分类。(不要封我)
第四:做个插件,任何网站上的技术文章都可以转发收藏 到本博客。
所以打算写个系类:《一步步搭建自己的博客》
- 一步步开发自己的博客 .NET版(1、页面布局、blog迁移、数据加载)
- 一步步开发自己的博客 .NET版(2、评论功能)
- 一步步开发自己的博客 .NET版(3、注册登录功能)
- 一步步开发自己的博客 .NET版(4、文章发布功能)
- 一步步开发自己的博客 .NET版(5、搜索功能)
- 一步步开发自己的博客 .NET版(6、手机端的兼容)
演示地址:http://haojima.net/ 群内共享源码:469075305

今天来分析下 嗨-博客 中的搜索功能。搜索功能在个人网站里面要有这么个东西,但又不是特别重要。所以我们需要有,可以不用太深入了解,毕竟我们不是专门做搜索这块的。
所以,我打算把搜索分两块。一块是,用Lucene.Net实现站内搜索。一块是利用第三方搜索引擎来 实现站内搜索。
Lucene.Net简介
Lucene.net是Lucene的.net移植版本,是一个开源的全文检索引擎开发包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎。开发人员可以基于Lucene.net实现全文检索的功能。Lucene.net是Apache软件基金会赞助的开源项目,基于Apache License协议。Lucene.net并不是一个爬行搜索引擎,也不会自动地索引内容。我们得先将要索引的文档中的文本抽取出来,然后再将其加到Lucene.net索引中。标准的步骤是先初始化一个Analyzer、打开一个IndexWriter、然后再将文档一个接一个地加进去。一旦完成这些步骤,索引就可以在关闭前得到优化,同时所做的改变也会生效。这个过程可能比开发者习惯的方式更加手工化一些,但却在数据的索引上给予你更多的灵活性,而且其效率也很高。(来源百度百科)
Lucene帮助类
其实 在之前 我也是接触到过Lucene.net,那也是自己 做的个小玩意(博客备份小工具3) 瞎折腾的。但是 这次打算迁移到这个系统中,不知怎么的 报错了。可能是这次用的是 .net 4.5。Lucene这东西太高深,我也没打算深究。于是 在网上收索了一把,资料还挺多的。《lucene.net 3.0.3、结合盘古分词进行搜索的小例子(分页功能)》 我随意看了下,这里有个 帮助类 挺不错的,也还符合 我这样想要的效果。这里来分析下这个帮助类。
1.首先创建索引。
IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
Document doc = new Document();
doc.Add(new Field(name, value, Field.Store.YES, Field.Index.NOT_ANALYZED));
writer.AddDocument(doc);
这里的
directory_luce 是索引创建路径
analyzer 分析器
value 是对应 存入索引额名字和值
2.从索引里面搜索
string[] fileds = { "title", "content" };//查询字段
QueryParser parser = null;
parser = new MultiFieldQueryParser(version, fileds, analyzer);//多个字段查询
Query query = parser.Parse(keyword);
int n = ;
IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示只读
TopDocs docs = searcher.Search(query, (Filter)null, n);
if (docs == null || docs.TotalHits == )
{
return null;
}
else
{
List<SearchResult> list = new List<SearchResult>();
int counter = ;
foreach (ScoreDoc sd in docs.ScoreDocs)//遍历搜索到的结果
{
try
{
Document doc = searcher.Doc(sd.Doc);
int id = int.Parse(doc.Get("id"));
string title = doc.Get("title");
string content = doc.Get("content");
string blogTag = doc.Get("blogTag");
string url = doc.Get("url");
int flag = int.Parse(doc.Get("flag"));
int clickQuantity = int.Parse(doc.Get("clickQuantity"));
string createdate = doc.Get("createdate");
PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new PanGu.Segment());
highlighter.FragmentSize = ;
content = highlighter.GetBestFragment(keyword, content);
string titlehighlight = highlighter.GetBestFragment(keyword, title);
if (titlehighlight != "") title = titlehighlight;
list.Add(new SearchResult(title, content, url, blogTag, id, clickQuantity, flag));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
counter++;
}
return list;
3.完整代码
public class PanGuLuceneHelper
{
private PanGuLuceneHelper() { } #region 单一实例
private static PanGuLuceneHelper _instance = null;
/// <summary>
/// 单一实例
/// </summary>
public static PanGuLuceneHelper instance
{
get
{
if (_instance == null) _instance = new PanGuLuceneHelper();
return _instance;
}
}
#endregion #region 00一些属性和参数
#region Lucene.Net的目录-参数
private Lucene.Net.Store.Directory _directory_luce = null;
/// <summary>
/// Lucene.Net的目录-参数
/// </summary>
public Lucene.Net.Store.Directory directory_luce
{
get
{
if (_directory_luce == null) _directory_luce = Lucene.Net.Store.FSDirectory.Open(directory);
return _directory_luce;
}
}
#endregion #region 索引在硬盘上的目录
private System.IO.DirectoryInfo _directory = null;
/// <summary>
/// 索引在硬盘上的目录
/// </summary>
public System.IO.DirectoryInfo directory
{
get
{
if (_directory == null)
{
string dirPath = AppDomain.CurrentDomain.BaseDirectory + "SearchIndex";
if (System.IO.Directory.Exists(dirPath) == false) _directory = System.IO.Directory.CreateDirectory(dirPath);
else _directory = new System.IO.DirectoryInfo(dirPath);
}
return _directory;
}
}
#endregion #region 分析器
private Analyzer _analyzer = null;
/// <summary>
/// 分析器
/// </summary>
public Analyzer analyzer
{
get
{
{
_analyzer = new Lucene.Net.Analysis.PanGu.PanGuAnalyzer();//
}
return _analyzer;
}
}
#endregion #region 版本号枚举类
private static Lucene.Net.Util.Version _version = Lucene.Net.Util.Version.LUCENE_30;
/// <summary>
/// 版本号枚举类
/// </summary>
public Lucene.Net.Util.Version version
{
get
{
return _version;
}
}
#endregion
#endregion #region 01创建索引
/// <summary>
/// 创建索引(先删 后更新)
/// </summary>
/// <param name="datalist"></param>
/// <returns></returns>
public bool CreateIndex(List<SearchResult> datalist)
{
IndexWriter writer = null;
try
{
writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);//false表示追加(true表示删除之前的重新写入)
}
catch
{
writer = new IndexWriter(directory_luce, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);//false表示追加(true表示删除之前的重新写入)
}
foreach (SearchResult data in datalist)
{
writer.DeleteDocuments(new Term("id", data.id.ToString()));//新增前 删除 不然会有重复数据
CreateIndex(writer, data);
}
writer.Optimize();
writer.Dispose();
return true;
}
public bool CreateIndex(SearchResult data)
{
List<SearchResult> datalist = new List<SearchResult>();
datalist.Add(data);
return CreateIndex(datalist);
} public bool CreateIndex(IndexWriter writer, SearchResult data)
{
try
{ if (data == null) return false;
Document doc = new Document();
Type type = data.GetType();//assembly.GetType("Reflect_test.PurchaseOrderHeadManageModel", true, true); //命名空间名称 + 类名 //创建类的实例
//object obj = Activator.CreateInstance(type, true);
//获取公共属性
PropertyInfo[] Propertys = type.GetProperties();
for (int i = ; i < Propertys.Length; i++)
{
//Propertys[i].SetValue(Propertys[i], i, null); //设置值
PropertyInfo pi = Propertys[i];
string name = pi.Name;
object objval = pi.GetValue(data, null);
string value = objval == null ? "" : objval.ToString(); //值
if (name == "id" || name == "flag")//id在写入索引时必是不分词,否则是模糊搜索和删除,会出现混乱
{
doc.Add(new Field(name, value, Field.Store.YES, Field.Index.NOT_ANALYZED));//id不分词
}
else
{
doc.Add(new Field(name, value, Field.Store.YES, Field.Index.ANALYZED));
}
}
writer.AddDocument(doc);
}
catch (System.IO.FileNotFoundException fnfe)
{
throw fnfe;
}
return true;
}
#endregion #region 02在title和content字段中查询数据
/// <summary>
/// 在title和content字段中查询数据
/// </summary>
/// <param name="keyword"></param>
/// <returns></returns>
public List<SearchResult> Search(string keyword)
{
string[] fileds = { "title", "content" };//查询字段
QueryParser parser = null;
parser = new MultiFieldQueryParser(version, fileds, analyzer);//多个字段查询
Query query = parser.Parse(keyword);
int n = ;
IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示只读
TopDocs docs = searcher.Search(query, (Filter)null, n);
if (docs == null || docs.TotalHits == )
{
return null;
}
else
{
List<SearchResult> list = new List<SearchResult>();
int counter = ;
foreach (ScoreDoc sd in docs.ScoreDocs)//遍历搜索到的结果
{
try
{
Document doc = searcher.Doc(sd.Doc);
int id = int.Parse(doc.Get("id"));
string title = doc.Get("title");
string content = doc.Get("content");
string blogTag = doc.Get("blogTag");
string url = doc.Get("url");
int flag = int.Parse(doc.Get("flag"));
int clickQuantity = int.Parse(doc.Get("clickQuantity")); string createdate = doc.Get("createdate");
PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new PanGu.Segment());
highlighter.FragmentSize = ;
content = highlighter.GetBestFragment(keyword, content);
string titlehighlight = highlighter.GetBestFragment(keyword, title);
if (titlehighlight != "") title = titlehighlight; list.Add(new SearchResult(title, content, url, blogTag, id, clickQuantity, flag));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
counter++;
}
return list;
}
//st.Stop();
//Response.Write("查询时间:" + st.ElapsedMilliseconds + " 毫秒<br/>"); }
#endregion #region 03在不同的分类下再根据title和content字段中查询数据(分页)
/// <summary>
/// 在不同的类型下再根据title和content字段中查询数据(分页)
/// </summary>
/// <param name="_flag">分类,传空值查询全部</param>
/// <param name="keyword"></param>
/// <param name="PageIndex"></param>
/// <param name="PageSize"></param>
/// <param name="TotalCount"></param>
/// <returns></returns>
public List<SearchResult> Search(string _flag, string keyword, int PageIndex, int PageSize)
{
if (PageIndex < ) PageIndex = ;
Stopwatch st = Stopwatch.StartNew();
st.Start();
BooleanQuery bq = new BooleanQuery();
if (_flag != "")
{
QueryParser qpflag = new QueryParser(version, "flag", analyzer);
Query qflag = qpflag.Parse(_flag);
bq.Add(qflag, Occur.MUST);//与运算
}
if (keyword != "")
{
string[] fileds = { "blogTag", "title", "content" };//查询字段
QueryParser parser = null;// new QueryParser(version, field, analyzer);//一个字段查询
parser = new MultiFieldQueryParser(version, fileds, analyzer);//多个字段查询
Query queryKeyword = parser.Parse(keyword);
bq.Add(queryKeyword, Occur.MUST);//与运算
} TopScoreDocCollector collector = TopScoreDocCollector.Create(PageIndex * PageSize, false);
IndexSearcher searcher = new IndexSearcher(directory_luce, true);//true-表示只读
searcher.Search(bq, collector); if (collector == null || collector.TotalHits == )
{
//TotalCount = 0;
return null;
}
else
{
int start = PageSize * (PageIndex - );
//结束数
int limit = PageSize;
ScoreDoc[] hits = collector.TopDocs(start, limit).ScoreDocs;
List<SearchResult> list = new List<SearchResult>();
int counter = ;
//TotalCount = collector.TotalHits;
st.Stop();
//st.ElapsedMilliseconds;//毫秒
foreach (ScoreDoc sd in hits)//遍历搜索到的结果
{
try
{
Document doc = searcher.Doc(sd.Doc);
int id = int.Parse(doc.Get("id"));
string title = doc.Get("title");
string content = doc.Get("content");
string blogTag = doc.Get("blogTag");
string url = doc.Get("url");
int flag = int.Parse(doc.Get("flag"));
int clickQuantity = int.Parse(doc.Get("clickQuantity"));
content = Highlight(keyword, content);
//string titlehighlight = Highlight(keyword, title);
//if (titlehighlight != "") title = titlehighlight;
list.Add(new SearchResult(title, content, url, blogTag, id, clickQuantity, flag));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
counter++;
}
return list;
}
}
#endregion #region 把content按照keywords进行高亮
/// <summary>
/// 把content按照keywords进行高亮
/// </summary>
/// <param name="keywords"></param>
/// <param name="content"></param>
/// <returns></returns>
private static string Highlight(string keywords, string content)
{
SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<strong>", "</strong>");
Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new Segment());
highlighter.FragmentSize = ;
return highlighter.GetBestFragment(keywords, content);
}
#endregion #region 04删除索引
#region 删除索引数据(根据id)
/// <summary>
/// 删除索引数据(根据id)
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool Delete(string id)
{
bool IsSuccess = false;
Term term = new Term("id", id);
IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
writer.DeleteDocuments(term); // writer.DeleteDocuments(term)或者writer.DeleteDocuments(query);
writer.Commit();
IsSuccess = writer.HasDeletions();
writer.Dispose();
return IsSuccess;
}
#endregion #region 删除全部索引数据
/// <summary>
/// 删除全部索引数据
/// </summary>
/// <returns></returns>
public bool DeleteAll()
{
bool IsSuccess = true;
try
{
IndexWriter writer = new IndexWriter(directory_luce, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
writer.DeleteAll();
writer.Commit();
IsSuccess = writer.HasDeletions();
writer.Dispose();
}
catch
{
IsSuccess = false;
}
return IsSuccess;
}
#endregion
#endregion #region 分词测试
/// <summary>
/// 分词测试
/// </summary>
/// <param name="keyword"></param>
/// <returns></returns>
public string Token(string keyword)
{
string ret = "";
System.IO.StringReader reader = new System.IO.StringReader(keyword);
Lucene.Net.Analysis.TokenStream ts = analyzer.TokenStream(keyword, reader);
bool hasNext = ts.IncrementToken();
Lucene.Net.Analysis.Tokenattributes.ITermAttribute ita;
while (hasNext)
{
ita = ts.GetAttribute<Lucene.Net.Analysis.Tokenattributes.ITermAttribute>();
ret += ita.Term + "|";
hasNext = ts.IncrementToken();
}
ts.CloneAttributes();
reader.Close();
analyzer.Close();
return ret;
}
#endregion }
public class SearchResult
{
public SearchResult() { } public SearchResult(string title, string content, string url, string blogTag, int id, int clickQuantity, int flag)
{
this.blogTag = blogTag;
this.clickQuantity = clickQuantity;
this.content = content;
this.id = id;
this.url = url;
this.title = title;
this.flag = flag;
}
/// <summary>
/// 标题
/// </summary>
public string title { get; set; }
/// <summary>
/// 正文内容
/// </summary>
public string content { get; set; }
/// <summary>
/// url地址
/// </summary>
public string url { get; set; }
/// <summary>
/// tag标签
/// </summary>
public string blogTag { get; set; }
/// <summary>
/// 唯一id
/// </summary>
public int id { get; set; }
/// <summary>
/// 点击量
/// </summary>
public int clickQuantity { get; set; }
/// <summary>
/// 标记(用户)
/// </summary>
public int flag { get; set; }
}
必应站内搜索
1.为什么要用必应搜索?
因为我们现在做的主要功能是博客系统,搜索只是其中的一小块环节。而 我对这搜索并不了解,所以就用第三方搜索,省事嘛。
2.为什么不用别的三方收索呢?
百度?不用说了,咱们程序员都懂的。谷歌?我倒是想用,可生在天朝,也是没得办法。选来选去 还是选了必应。
3.怎么来使用第三方的站内搜索?
格式如下:http://cn.bing.com/search?q=关键字+site:网站地址
例如:http://cn.bing.com/search?q=博客+site:blog.haojima.net
效果图:
嘿嘿,如此之简单。既然都已经看到效果了,那么 我们可以干些什么呢?
我打算 直接把结果 显示在我的 站内搜索结果。为什么 不直接跳转到这个页面显示 搜索结果?因为 这个页面有广告什么的,不能按照我自己的方式显示。我直接把结果放我的搜索页面 可以和 我上面用Lucene.net的搜索结果一起显示,这样岂不是 显得更专业。
,不知道的 还以为 是我自己怎么弄出来的。那么 我们怎么解析 搜到的结果呢?我这里推荐下 Jumony 之前我一直是用 HtmlAgilityPack ,现在为什么不用了,因为有了更好的。HtmlAgilityPack 缺点是 要去xpath,然 如果页面存在js动态改变文档结构的话,我们直接F12 复制出来的 xpath是不准的。那么有人 会说 HtmlAgilityPack 我已经用习惯了,不想 重新学习Jumony 。这里我告诉你错了,根本就需要重新学习,如果你会jquery 的话。常用功能语法基本一样,还支持拉姆达表达式,爽的一逼。
我们来看看 怎么使用Jumony 解析 解锁结果吧。
var document = jumony.LoadDocument(url);
var list = document.Find("#b_results .b_algo").ToList().Select(t => t.ToString()).ToList();
两行代码搞定,还直接转成了list集合。在页面循环加载就ok了。
站内下的某个用户内搜索
我个人觉得 这是个蛮实用的功能,我们有时候 写了博客(很多时候我们写博客就是把自己怕会忘记的知识点 整理记录),而后期找不到。那么通过这个功能 可以很好的解决我们的问题。我们不想全站搜索,只搜索自己的内容就可以了。
页面还是用全站的搜索页面,我们直接在搜索关键词上做手脚就可以了。比如,我们想搜索 zhaopei 用户下的内容,那么我们可以要搜索的关键字前面加上 blog:zhaopei 那么完整的搜索关键字就成了 blog:zhaopei 关键字
那么 我们要做的就是 在用户页面 搜索 就在关键字 前面加上 blog:用户名 我们在搜索 页面解析的时候 需要做的就是 分解关键字 blog:用户名 关键字 先用空格 分割 然后如果中间有 空格的话 ,然后判断 前面五个字符是不是 blog: 然后截取 到用户名和 关键字。
我们下面具体看看 在Lucene.net 和 必应搜索里面是怎么做的。
1.Lucene.net
#region 加载 Lucene.net 的搜索结果
/// <summary>
/// 加载 Lucene.net 的搜索结果
/// </summary>
/// <returns></returns>
public ActionResult ShowLuceneResult()
{
if (!Request.QueryString.AllKeys.Contains("key"))
return null;
string key = Request.QueryString["key"]; var zhankey = key.Split(' ');//分割关键字
var blogName = string.Empty;
if (zhankey.Length >= )
{
var str = zhankey[].Trim();
if (str.Length > && str.Substring(, ) == "blog:")
blogName = str.Substring();//取得用户名
} string userid = Request.QueryString.AllKeys.Contains("userid") ? Request.QueryString["userid"] : ""; //这里判断是否 用户名不为空 然后取得用户对应的 用户ID (因为 我在做Lucene 是用用户id 来标记的)
if (!string.IsNullOrEmpty(blogName))
{
key = key.Substring(key.IndexOf(' '));
var userinfo = CacheData.GetAllUserInfo().Where(t => t.UserName == blogName).FirstOrDefault();
if (null != userinfo)
userid = userinfo.Id.ToString();
} string pIndex = Request.QueryString.AllKeys.Contains("p") ? Request.QueryString["p"] : "";
int PageIndex = ;
int.TryParse(pIndex, out PageIndex); int PageSize = ;
var searchlist = PanGuLuceneHelper.instance.Search(userid, key, PageIndex, PageSize);
return PartialView(searchlist);
}
#endregion
2. 必应搜索
#region 加载 bing 的搜索结果
/// <summary>
/// 加载 bing 的搜索结果
/// </summary>
/// <returns></returns>
public ActionResult ShowBingResult()
{
if (!Request.QueryString.AllKeys.Contains("key"))
return null;
string key = Request.QueryString["key"];//搜索关键字
JumonyParser jumony = new JumonyParser();
//http://cn.bing.com/search?q=AJAX+site%3ablog.haojima.net&first=11&FORM=PERE
string pIndex = Request.QueryString.AllKeys.Contains("p") ? Request.QueryString["p"] : "";
int PageIndex = ;
int.TryParse(pIndex, out PageIndex);
PageIndex--; //如:blog:JeffreyZhao 博客
var zhankey = key.Split(' ');//先用空格分割
var blogName = string.Empty;
if (zhankey.Length >= )
{
var str = zhankey[].Trim();
if (str.Length > && str.Substring(, ) == "blog:")
blogName = "/" + str.Substring();//这里取得 用户名
}
if (!string.IsNullOrEmpty(blogName))
key = key.Substring(key.IndexOf(' ')); //如:
var url = "http://cn.bing.com/search?q=" + key + "+site:" + siteUrl + blogName + "&first=" + PageIndex + "1&FORM=PERE";
var document = jumony.LoadDocument(url);
var list = document.Find("#b_results .b_algo").ToList().Select(t => t.ToString()).ToList(); var listli = document.Find("li.b_pag nav ul li");
if (PageIndex > && listli.Count() == )
return null; if (listli.Count() > )
{
var text = document.Find("li.b_pag nav ul li").Last().InnerText();
int npage = -;
if (text == "下一页")
{
if (listli.Count() > )
{
var num = listli.ToList()[listli.Count() - ].InnerText();
int.TryParse(num, out npage);
}
}
else
int.TryParse(text, out npage);
if (npage <= PageIndex)
list = null;
} return PartialView(list);
}
#endregion
看看 我们的搜索结果的效果图吧。

总结
首先 搜索是必不可少的功能,但又不是主要功能。那么我们可以直接用lucene.net 来做搜索,然后用必应搜索做备用。但是 用必应 有个弊端。就是 如果我们 的文章页面 被用户自己删除了,而 必应已经收录了,那么 我们在搜索结果页面 点击 可能就是404 或 500 了。当然 我们自己的 lucene.net 也会有这个 问题,我们可以在用户删除 文章的时候 也删除 对应的那天搜索索引就好了。
演示地址:http://blog.haojima.net/Search/Index?key=blog:zhaopei 博客&p=1
如果您对本篇文章感兴趣,那就麻烦您点个赞,您的鼓励将是我的动力。 当然您还可以加入QQ群:
讨论。
如果您有更好的处理方式,希望不要吝啬赐教。
一步步开发自己的博客 .NET版系列:http://www.cnblogs.com/zhaopei/tag/Hi-Blogs/
本文链接:http://www.cnblogs.com/zhaopei/p/4783986.html
一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)的更多相关文章
- 一步步开发自己的博客 .NET版(1、基本显示)
前言 我们每个猿都有一个搭建自己独立博客的梦,我也不例外.以前想 现在想 以后也想.之所以一直迟迟没有着手,是因为难以跨出第一步.每次心里想着,等我以后技术好了再说,然后就没有然后了.以前用过word ...
- 一步步开发自己的博客 .NET版(3、注册登录功能)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
- 一步步开发自己的博客 .NET版(4、文章发布功能)百度编辑器
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做个插件,任何网站上的技术 ...
- 一步步开发自己的博客 .NET版 剧终篇(6、响应式布局 和 自定义样式)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
- 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)
Web.config的读取 对于Web.config的读取大家都很属性了.平时我们用得比较多的就是appSettings节点下配置.如: 我们对应的代码是: = ConfigurationManage ...
- 一步步开发自己的博客 .NET版(10、前端对话框和消息框的实现)
关于前端对话框.消息框的优秀插件多不胜数.造轮子是为了更好的使用轮子,并不是说自己造的轮子肯定好.所以,这个博客系统基本上都是自己实现的,包括日志记录.响应式布局.评论功能等等一些本可以使用插件的.好 ...
- 一步步开发自己的博客 .NET版(9、从model first替换成code first 问题记录)
为什么要改用code first 用过code first的基本上都不会再想用回model first或是db first(谁用谁知道).不要问我为什么不一开始就直接使用code first,因为那个 ...
- ASP.NET 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)
原文:http://www.cnblogs.com/zhaopei/p/5677053.html
- 一步步搭建自己的博客 .NET版(2、评论功能)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
随机推荐
- 01.SQLServer性能优化之----强大的文件组----分盘存储
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 文章内容皆自己的理解,如有不足之处欢迎指正~谢谢 前天有学弟问逆天:“逆天,有没有一种方 ...
- servlet文件下载
创建web工程servlet,新建DownloadServlet.java package com.xmyself.servlet; import java.io.File; import java. ...
- 最新 去掉 Chrome 新标签页的8个缩略图
chrome的新标签页的8个缩略图实在让人不爽,网上找了一些去掉这个略缩图的方法,其中很多已经失效.不过其中一个插件虽然按照原来的方法已经不能用了,但是稍微变通一下仍然是可以用的(本方法于2017.1 ...
- TSQL Identity 用法全解
Identity是标识值,在SQL Server中,有ID列,ID属性,ID值,ID列的值等术语. Identity属性是指在创建Table时,为列指定的Identity属性,其语法是:column_ ...
- js获取给定月份的N个月后的日期
1.在讲js获取给定月份的N个月后的日期之前,小颖先给大家讲下getFullYear().getYear()的区别. ①getYear() var d = new Date() console.log ...
- ASP.NET Core的路由[1]:注册URL模式与HttpHandler的映射关系
ASP.NET Core的路由是通过一个类型为RouterMiddleware的中间件来实现的.如果我们将最终处理HTTP请求的组件称为HttpHandler,那么RouterMiddleware中间 ...
- pt-ioprofile
pt-ioprofile是用来观察特定进程的IO信息的. 该脚本是用shell写的,有两方面的作用: pt-ioprofile does two things: ) ) is not performe ...
- JQuery中的siblings()是什么意思
jQuery siblings() 方法返回被选元素的所有同胞元素,并且可以使用可选参数来过滤对同胞元素的搜索. 实例演示:点击某个li标签后将其设置为红色,而其所有同胞元素去除红色样式. 1.创建H ...
- SAP CRM 显示消息/在消息中进行导航
向用户展示消息,在任何软件中都是十分重要的. 在SAP CRM WEB UI中展示消息,不是一项很难的任务,只需要创建消息并在之后调用方法来显示它 消息类和消息号: 我在SE91中创建了如下的消息类和 ...
- BZOJ 1103: [POI2007]大都市meg [DFS序 树状数组]
1103: [POI2007]大都市meg Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2221 Solved: 1179[Submit][Sta ...