MyException - 我的异常网
当前位置:我的异常网» ASP.NET » 一步步开发自各儿的博客(一)

一步步开发自各儿的博客(一)

www.MyException.Cn  网友分享于:2015-08-26  浏览:0次
一步步开发自己的博客(一)

前言   

      我们每个猿都有一个搭建自己独立博客的梦,我也不例外。以前想 现在想 以后也想。之所以一直迟迟没有着手,是因为难以跨出第一步。每次心里想着,等我以后技术好了再说,然后就没有然后了。以前用过wordpress,虽然插件很多,不过有时候想改改自己想要的效果很难,因为 我压根就不会php。也看过.net的一些开源博客,代码量多,看得头晕,没那个耐心。

      再说,别人的始终是别人的。得鱼不如得渔。与其花时间去研究php还不如自己写个.net版的。有人说博客园已经很好了啊,我承认确实,而且还可以后台定制自己想要的样式和js。不过始终还是不如自己开发的来得随心所欲。最重要自己开发还可以当作练手 对一个网站的各环节  做一次练习,用以发现自己的不足,并加以提升。那我以后的博客写哪里呢?当然还是会继续发博客园,谁叫这里人气旺呢。

    这次开发的博客主要功能或特点:
    第一:可以兼容各终端,特别是手机端。
    第二:到时会用到大量html5,炫啊。
    第三:导入博客园的精华文章,并做分类。(不要封我)
    第四:做个插件,任何网站上的技术文章都可以转发收藏 到本博客。

所以打算写个系类:《一步步搭建自己的博客》

一、一步步搭建自己的博客(1、页面布局、blog迁移、数据加载)

二、一步步搭建自己的博客(2、评论功能)

三、一步步搭建自己的博客(3、注册登录功能)

四、一步步搭建自己的博客(4、文章发布功能)

五、一步步搭建自己的博客(5、搜索功能)

关于域名和空间

      在以前我们学C#的想要搭一个免费的博客,要不只能用国外的免费空间要么在linux下用php。用起来都是各种坑,网速各种卡。然后,现在我们学C#的时代来了,这里要感谢阿里云(免费主机)。当然域名还是要自己买的。万网 和 新网 可以对比下  哪里便宜买哪里,都可以用。(注意:最好买 .com .net .cc .org 因为有些域名不能在阿里备案)。买好域名之后 然后就是备案了,备案也没什么复杂的,阿里自动备案。中间除了 找阿里 要一块免费的布 照个相 寄过去,就是等了,其他的什么也不用做。大概半个月的样子吧。建议  买域名的时候最好一次性买久一点,不然后期再续费要比第一次买贵。(如果您实在不想花这个钱,这个我最后给您支个招吧,你申请好免费的主机后,你把主机ip给我,我免费给你二级域名。谁叫我是活雷锋)

开发环境

      域名和主机都搞定以后,就开始选择开发环境了。我选的是 vs2013 mvc4 ef6.0 mssql   。

博客迁移

      然后就是博客迁移,之前也老想着搭建博客,可一直没有行动。这就是从0到1 的难。只要你走出了第一步 后面就 顺畅得多了。那么 我们搭博客 没有测试数据 总还是感觉没什么动力。所以,我就写了个程序,把我在博客园发表的文章扒过去。

      那么我们需要哪些数据呢?现在大概想到的有:博客正文、tag标签、文章分类、创建时间、博客标题

      好了,那我们就正式开始扒吧。(可以参考我以前的博客备份小工具3

      首先是从/mvc/blog/sidecolumn.aspx页面取得 文章分类。然后根据 每个类型 的链接 取得这个类型下的所有文章。然后在取正文的时候发现 文章所属tag标签和分类是异步的到页面的, http://www.cnblogs.com/mvc/blog/CategoriesTags.aspx?blogApp=用户名&postId=文章id。(也许博客园有api,我也没去看没去找。)

1.首先建一个实体数据模型

我这里采用的是 代码先行 CodeFirst 。这里要说明的是 tag标签和文章是多对多的关系,文章类型和文章也是多对多的关系。

2.然后根据模型生成数据库

       个人觉得这里非常爽,自动帮我建好了 主外键  和索引,免除了我们自己手动去在数据库里面建。

3.从博客园扒数据

       模型和数据库建好了,那么我们现在就开始迁移吧~下面是全部代码,其中有存数据库的部分可以自己改改。

/// <summary>
        /// 根据用户导入cnblog数据
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public string Import(string userName, string iszf = "false")
        {
            int blosNumber = 0;
            JavaScriptSerializer jss = new JavaScriptSerializer();
            string url = "http://www.cnblogs.com/" + userName + @"/mvc/blog/sidecolumn.aspx";
            HtmlAgilityPack.HtmlWeb htmlweb = new HtmlAgilityPack.HtmlWeb();
            var docment = htmlweb.Load(url);
            string userid = GetCnblogUserId(userName);
            var liS = docment.DocumentNode.SelectNodes("//*[@id='sidebar_categories']/div[1]/ul/li");
            foreach (var item in liS)
            {
                var tXPath = item.XPath;
                var href = item.SelectSingleNode(tXPath + "/a").Attributes["href"].Value;
                var blogtype = htmlweb.Load(href);
                //var entrylistItem = blogtype.DocumentNode.SelectNodes("//*[@id='mainContent']/div/div[2]/div[@class='entrylistItem']");
                var entrylistItem = blogtype.DocumentNode.SelectNodes("//div[@class='entrylistItem']");
                if (null == entrylistItem)//做兼容
                    entrylistItem = blogtype.DocumentNode.SelectNodes("//div[@class='post post-list-item']"); //    
                if (null == entrylistItem)
                {
                    continue;
                }
                foreach (var typeitem in entrylistItem)
                {
                    var typeitemXPath = typeitem.XPath;
                    var typeitemhrefObj = typeitem.SelectSingleNode(typeitemXPath + "/div/a");
                    if (null == typeitemhrefObj) //做兼容
                        typeitemhrefObj = typeitem.SelectSingleNode(typeitemXPath + "/h2/a");
                    var typeitemhref = typeitemhrefObj.Attributes["href"].Value;
                    if (IsAreBlog(typeitemhref))
                        continue;//说明这篇文章已经备份过了的
                    var bloghtml = htmlweb.Load(typeitemhref);
                    var blogcontextobj = bloghtml.DocumentNode.SelectSingleNode("//*[@id='cnblogs_post_body']");//.InnerHtml;
                    if (blogcontextobj == null) continue;//有可能是加密文章
                    var blogcontext = blogcontextobj.InnerHtml;
                    var blogtitle = bloghtml.DocumentNode.SelectSingleNode("//*[@id='cb_post_title_url']").InnerText;
                    var blogurl = bloghtml.DocumentNode.SelectSingleNode("//*[@id='cb_post_title_url']").Attributes["href"].Value;
                    var blogtypetagurl = "http://www.cnblogs.com/mvc/blog/CategoriesTags.aspx?blogApp=" + userName + "&blogId=" + userid + "    =" +
                        typeitemhref.Substring(typeitemhref.LastIndexOf('/') + 1, typeitemhref.LastIndexOf('.') - typeitemhref.LastIndexOf('/') - 1);
                    var blogtag = Blogs.Common.Helper.MyHtmlHelper.GetRequest(blogtypetagurl);
                    var jsonobj = jss.Deserialize<Dictionary<string, string>>(blogtag);
                    if (null == jsonobj)
                        continue;//如果没有 则返回  (这里只能去 数字.html  不能取那种自定义的url)
                    var tagSplit = jsonobj["Tags"].Split(',');
                    var blogtagid = new List<int>();
                    for (int i = 0; i < tagSplit.Length; i++)
                    {
                        if (tagSplit[i].Length >= 1 && tagSplit[i].LastIndexOf('<') >= 1)
                        {
                            var blogtagname = tagSplit[i].Substring(tagSplit[i].IndexOf('>') + 1, tagSplit[i].LastIndexOf('<') - tagSplit[i].IndexOf('>') - 1);
                            blogtagid.Add(this.GetTagId(blogtagname, userName));
                        }
                    }
                    var categoriesSplit = jsonobj["Categories"].Split(',');
                    var blogtypeid = new List<int>();
                    for (int i = 0; i < categoriesSplit.Length; i++)
                    {
                        if (categoriesSplit[i].Length >= 1 && categoriesSplit[i].LastIndexOf('<') >= 1)
                        {
                            var blogtypename = categoriesSplit[i].Substring(categoriesSplit[i].IndexOf('>') + 1, categoriesSplit[i].LastIndexOf('<') - categoriesSplit[i].IndexOf('>') - 1);
                            blogtypeid.Add(this.GetTypeId(blogtypename, userName));
                        }
                    }
                    var blogtimeobj = bloghtml.DocumentNode.SelectSingleNode("//*[@id='post-date']");
                    var blogtime = "";
                    if (null != blogtimeobj)
                        blogtime = blogtimeobj.InnerText;


                    BlogsBLL blog = new BlogsBLL();
                    var myBlogTags = new BlogTagsBLL().GetList(t => blogtagid.Contains(t.Id), isAsNoTracking: false).ToList();//.ToList();                                        

                    var myBlogTypes = new BLL.BlogTypesBLL().GetList(t => blogtypeid.Contains(t.Id), isAsNoTracking: false).ToList();//.ToList();
                    try
                    {
                        var modelMyBlogs = new ModelDB.Blogs()
                        {
                            BlogContent = blogcontext,
                            BlogCreateTime = blogtime,
                            BlogTitle = blogtitle,
                            BlogUrl = blogurl,
                            IsDel = false,
                            BlogTags = myBlogTags,
                            BlogTypes = myBlogTypes,
                            UsersId = GetUserId(userName),
                            BlogForUrl = blogurl,
                            IsForwarding = iszf == "checked"
                        };
                        blog.Add(modelMyBlogs);
                        blog.save();
                        blosNumber++;
                    }
                    catch (Exception)
                    {
                        throw;
                    }
                }
            }
            if (blosNumber > 0)
                return "成功导入" + blosNumber + "篇Blog";
            return "ok";
        }

        private int GetTagId(string tagname, string userName)
        {
            BlogTagsBLL blogtag = new BlogTagsBLL();
            try
            {
                var blogtagmode = blogtag.GetList(t => t.TagName == tagname);
                if (blogtagmode.Count() >= 1)
                    return blogtagmode.FirstOrDefault().Id;
                else
                {
                    blogtag.Add(new ModelDB.BlogTags()
                    {
                        TagName = tagname,
                        IsDel = false,
                        UsersId = GetUserId(userName)
                    });
                    blogtag.save();
                    return GetTagId(tagname, userName);
                }
            }
            catch (Exception)
            {
                return -1;
            }
        }


        private int GetTypeId(string typename, string userName)
        {
            BlogTypesBLL blogtype = new BlogTypesBLL();
            var blogtagmode = blogtype.GetList(t => t.TypeName == typename);
            if (blogtagmode.Count() >= 1)
                return blogtagmode.FirstOrDefault().Id;
            else
            {
                blogtype.Add(new ModelDB.BlogTypes()
                {
                    TypeName = typename,
                    CreateTime = DateTime.Now,
                    IsDel = false,
                    UsersId = GetUserId(userName)
                });
                blogtype.save();
                return GetTypeId(typename, userName);
            }
        }

        /// <summary>
        /// 获取haojima用户id
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        private int GetUserId(string userName)
        {
            BlogUsersBLL user = new BlogUsersBLL();
            var blogtagmode = user.GetList(t => t.UserName == userName);
            if (blogtagmode.Count() >= 1)
                return blogtagmode.FirstOrDefault().Id;
            else
            {
                user.Add(new ModelDB.BlogUsers()
                {
                    UserName = userName,
                    IsDel = false,
                    UserPass = "admin",
                    UserNickname = userName
                });
                user.save();
                return GetUserId(userName);
            }
        }

        /// <summary>
        /// 检查 这个 url地址 是否被添加过
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private bool IsAreBlog(string url)
        {
            BLL.BlogsBLL blog = new BLL.BlogsBLL();
            var blogs = blog.GetList(t => t.BlogUrl == url);
            return blogs.Count() >= 1;
        }

        /// <summary>
        /// 获取cnblog用户id
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private string GetCnblogUserId(string url)
        {
            HtmlAgilityPack.HtmlWeb htmlweb = new HtmlAgilityPack.HtmlWeb();
            var docment = htmlweb.Load("http://www.cnblogs.com/" + url);
            var list = docment.DocumentNode.SelectNodes("//link[@rel='stylesheet']");
            foreach (var item in list)
            {
                if (null != item.Attributes && item.Attributes.Contains("href"))
                {
                    var href = item.Attributes["href"].Value;
                    href = href.Substring(href.LastIndexOf("/") + 1, href.IndexOf(".") - href.LastIndexOf("/") - 1);
                    int userid = -1;
                    if (int.TryParse(href, out userid))
                        return userid.ToString();
                }
            }
            return "";
        }
View Code

 

页面布局

      关于页面布局 ,怎样简单怎样来。我是分成了 头、尾、中间。中间二八分。这个不重要,现在暂时这么遭。以后再考虑 多终端的兼容。

数据加载

       现在数据都已经迁移过来的,需要展示在我们自己搭建的博客,我想对于大家来书应该没什么难度。从学编程开始,老师就教我们 增删改查。只是美与丑的问题。

       这里有一点要注意,因为正文内容保存到数据库的都是html代码,而我们要在首页展示文章列表只显示小部分内容,那怎么截取字符串呢?你不能保证刚好是在html标签结尾后截取啊。我这里用到了HtmlAgilityPack取InnerText 的属性。就像jqeruy中 .html() 和 .text()区别,如果截图断了html标签 显示 将会很混乱。       

最后总结

      这个博客我也才刚开始做,现有也仅仅只是实现了博客的展示功能,连分页都还没有去实现。所以本系列博客更新会比较慢。我也需要边做边学边更新,工作中还没用过MVC。

到最后等我做完了,我会放git上开源,到时候大家有兴趣的可以一起来完善和定制自己想要的效果。

       说了这么多来张效果图吧。

       

       如果您对本篇文章感兴趣,那就麻烦您点个赞,您的鼓励将是我的动力。 当然您还可以加入QQ群:嗨 博客讨论,群内共享源码

 

演示地址:http://blog.haojima.net/

原文链接:http://www.cnblogs.com/zhaopei/p/4737958.html 

 

21楼musta
一改版就觉得很复杂,很难看。
Re: 敷衍不起
@musta,什么改版很复杂,很难看?
20楼进击的Jary
思路不错。但博主的界面不怎么好看。
Re: 敷衍不起
@进击的Jary,所以我很想能有个美工配合。毕竟我们开发人员的审美观。。。
19楼醉心
学习了,感谢分享
18楼心尖偏左
我想了解一下阿里云(免费主机)及备案
Re: 敷衍不起
@心尖偏左,可以进群讨论,刚进来的同学 都在讨论这个问题。
17楼妙瞳
好厉害,学习学习。呵呵。
Re: 敷衍不起
@妙瞳,可以加群 群内共享源码
16楼枫伶忆
众人拾柴火焰高,大家一起齐心协力来完善这个博客系统
15楼代码小兵的成长
不能公布源码啊
Re: 敷衍不起
@代码小兵的成长,引用不能公布源码啊 ,不能公布?为什么?
14楼小码农也有春天吧
支持下
Re: 敷衍不起
@小码农也有春天吧,谢谢 支持。
13楼刘子翔
博主思路好清晰
Re: 枫伶忆
@刘子翔,感兴趣可以加我们的QQ群469075305 欢迎欢迎
12楼失落的野火
mark~
11楼云帆济沧海
mark
10楼DotNet开源大本营
没有源码怎么搞。。。。不是白说了么,只有你一个人可以用,哈哈。。。好像搞错了,群内公布源码,呵呵
9楼Cyclone77
来了解下免费主机
8楼HelloChina
楼主,阿里云免费的主机,可以申请备案服务号码?
Re: Supper_litt
@HelloChina,选择万网主机就ok了。不过你需要一个阿里旗下的域名。
7楼让权等待
怎么部署的,也来个教程嘛..,PS:群号多少来着的? 我这边打不开
Re: 枫伶忆
@让权等待,嗨 博客 QQ群469075305 欢迎欢迎
6楼在我机子上运行是好的
支持一下
Re: 敷衍不起
@在我机子上运行是好的,谢谢 您的支持将是我的动力
5楼Vktun
不错! 我域名和主机都搞定了,就是没迟迟动手!
4楼mercy rain
楼主好厉害,支持一下!!!!!!
Re: 敷衍不起
@mercy rain,您的支持将是我的动力 谢谢。
3楼vbfool
你们啊,就光知道要源码,又不是复杂到天上的项目,自己去写啊!
2楼Suzuki.kakeru
www.alidoing.com,,,www.10086bank.com,,,www.zhaochezhu.com,,,全部用的阿里云的服务器一台,全部网站搞定!
1楼查克拉的觉醒
mark

文章评论

当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
为什么程序员都是夜猫子
为什么程序员都是夜猫子
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
旅行,写作,编程
旅行,写作,编程
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
代码女神横空出世
代码女神横空出世
如何成为一名黑客
如何成为一名黑客
每天工作4小时的程序员
每天工作4小时的程序员
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
那些争议最大的编程观点
那些争议最大的编程观点
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
中美印日四国程序员比较
中美印日四国程序员比较
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
 程序员的样子
程序员的样子
我是如何打败拖延症的
我是如何打败拖延症的
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
程序员都该阅读的书
程序员都该阅读的书
鲜为人知的编程真相
鲜为人知的编程真相
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
编程语言是女人
编程语言是女人
程序员的鄙视链
程序员的鄙视链
总结2014中国互联网十大段子
总结2014中国互联网十大段子
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
一个程序员的时间管理
一个程序员的时间管理
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
程序员和编码员之间的区别
程序员和编码员之间的区别
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
我的丈夫是个程序员
我的丈夫是个程序员
程序员应该关注的一些事儿
程序员应该关注的一些事儿
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
程序员必看的十大电影
程序员必看的十大电影
Java程序员必看电影
Java程序员必看电影
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
老程序员的下场
老程序员的下场
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有