从零开始,搭建博客系统MVC5+EF6搭建框架(5),博客详情页、留言、轮播图管理、右侧统计博文

一、博客系统进度回顾

上一遍博客介绍到,系统已经实现到了发布以及前台布局展示,接下来就是实现一些,详情页,留言、轮播图管理、右侧博文统计信息实现。

二、博客系统详情页实现

2.1先来看看详情页展示的效果

2.2实现控制器在前台控制器中创建一个Blog的控制器,主要是展示博客分类以及详情页

Action详情页实现:

  1 /// <summary>
  2         /// 详情页
  3         /// </summary>
  4         /// <param name="id"></param>
  5         /// <returns></returns>
  6         public ActionResult Detail(int id)
  7         {
  8             //获取控制器名称
  9             ViewBag.controllername = RouteData.Values["controller"].ToString().ToLower();
 10             var model = BlogArticleServive.getBlogDetails(id);
 11             ViewBag.gblist = GuestbookServices.QueryOrderBy(c => c.blogId == id, c => c.createdate, false).ToPagedList(1, 5);
 12
 13             //发布时间排序
 14             ViewBag.blogtimelist = BlogArticleServive.QueryOrderBy(c => true, c => c.bCreateTime, false);
 15             //评论排序
 16             ViewBag.blogtrafficlist = BlogArticleServive.QueryOrderBy(c => true, c => c.btraffic, false);
 17             //留言排序
 18             string sql = @"select a.*,b.btitle from (select blogId,count(1) as counts  from Guestbook group by blogId) as a
 19 inner join BlogArticle as b
 20 on
 21 b.bID=a.blogId order by counts desc";
 22
 23             ViewBag.blogguestbooklist = GuestbookServices.RunProc<TopgbViewModels>(sql);
 24
 25             return View(model);
 26         }

由于展示的内容比实际存储在数据库中的信息多,所以把所有能展示的信息都放在BlogViewModels中,在blog业务逻辑层单独实现了一个包含上一页 下一页,以及摘要赋值的方法。

由于这一部分需要从详情内容中只保留部分文字,所以这里需要对索取的详情信息做处理,由于详情信息是通过富文本编辑来添加的里面包含了很多html代码信息,所以在common程序集中,创建一个工具类,Tools类来存放,辅助的相关方法。

ReplaceHtmlTag方法:

  1   #region 去除富文本中的HTML标签
  2         /// <summary>
  3         /// 去除富文本中的HTML标签
  4         /// </summary>
  5         /// <param name="html"></param>
  6         /// <param name="length"></param>
  7         /// <returns></returns>
  8         public static string ReplaceHtmlTag(string html, int length = 0)
  9         {
 10             string strText = System.Text.RegularExpressions.Regex.Replace(html, "<[^>]+>", "");
 11             strText = System.Text.RegularExpressions.Regex.Replace(strText, "&[^;]+;", "");
 12
 13             if (length > 0 && strText.Length > length)
 14                 return strText.Substring(0, length);
 15
 16             return strText;
 17         }
 18         #endregion

然后在获取到多有信息,要处理的地方就是用三元运算符来判断,截取前面的文字部分

2.3详情页视图代码

  1 @model Wchl.WMBlog.Model.VeiwModels.BlogViewModels
  2
  3 @{
  4     ViewBag.Title = "博客详情页";
  5 }
  6 <link href="~/Content/lib/zui/doc.css" rel="stylesheet" />
  7 <section>
  8     <article>
  9         <div spellcheck="false" class="example">
 10             <br>
 11             <ul class="breadcrumb">
 12                 <li><i class="icon-location-arrow icon-muted"></i></li>
 13                 <li><a href="/home/index">首页</a></li>
 14                 <li><a href="/blog/index">博客</a></li>
 15                 <li class="active">Data</li>
 16             </ul>
 17             <hr>
 18             <article class="article">
 19                 <header>
 20                     <h1 class="text-center">@Model.btitle</h1>
 21                     <dl class="dl-inline">
 22                         <dt>发布时间:</dt>
 23                         <dd>@Model.bCreateTime</dd>
 24                         <dt>作者:</dt>
 25                         <dd>@Model.bsubmitter</dd>
 26                         <dt></dt>
 27                         <dd class="pull-right"><span class="label label-success">新</span> <span class="label label-warning">火爆</span> <span class="label label-info">原创</span> <span class="label label-danger"><i class="icon-eye-open"></i> @Model.btraffic</span></dd>
 28                     </dl>
 29                     <section class="abstract">
 30                         <p><strong>摘要:</strong>@Model.digest</p>
 31                     </section>
 32                 </header>
 33                 <section class="article-content">
 34                     @Html.Raw(Model.bcontent)
 35                 </section>
 36                 <footer>
 37                     <p class="pull-right text-muted">
 38                         发布时间:@Model.bCreateTime.ToString("yyyy年MM月dd日 HH:mm:ss") &nbsp;点击数:@Model.btraffic
 39                     </p>
 40                     <p class="text-important">本文版权所有归<a href="###">@Model.bsubmitter</a></p>
 41                     <ul class="pager pager-justify">
 42                         @if (Model.previous == null)
 43                         {
 44                           <li class="previous disabled"><a href="#" title=""><i class="icon-arrow-left"></i> 上一篇: </a></li>
 45                         }
 46                         else
 47                         {
 48                             <li class="previous"><a href="/blog/Detail/@Model.previousID " title="@Model.previous"><i class="icon-arrow-left"></i> 上一篇: @Model.previous.Substring(0, 5)  </a></li>
 49                         }
 50                         @if (Model.next == null)
 51                         {
 52                             <li class="next disabled"><a href="#">下一篇: <i class="icon-arrow-right"></i></a></li>
 53                         }
 54                         else
 55                         {
 56                             <li class="next"><a href="/blog/Detail/@Model.nextID " title="[email protected]">下一篇:@Model.next.Substring(0, 5) <i class="icon-arrow-right"></i></a></li>
 57                         }
 58
 59
 60                     </ul>
 61                 </footer>
 62             </article>
 63         </div>
 64     </article>
 65     <div id="comment">
 66         @Html.Partial("_GuestbookPage")
 67     </div>
 68
 69 </section>
 70 @section scripts
 71 {
 72     <script src="~/Content/lib/laypage/laypage.js"></script>
 73     <script type="text/javascript">
 74         var blogid;
 75         var curr;
 76         $(function () {
 77             $("#blogId").val(@Model.bID);
 78             //运行分页
 79             blogid = $("#blogId").val();
 80             guestbookpage(curr,blogid);
 81         })
 82
 83     function su(data) {
 84         $("#comment").html(data);
 85         $("#blogId").val(@Model.bID);
 86         //setTimeout(function () {
 87         //    if (document.getElementById(‘textcenter‘) != null) {
 88         //            //运行分页
 89         //            guestbookpage(1, blogid);
 90         //    }
 91         //}, 3000);
 92         if (document.getElementById(‘textcenter‘) != null) {
 93             //运行分页
 94             guestbookpage(1, blogid);
 95         }
 96
 97
 98
 99     }
100
101     //以下将以jquery.ajax为例,演示一个异步分页
102     function guestbookpage(curr,blogid) {
103         $.getJSON(‘/blog/getGuestbook‘, {
104             page: curr || 1,
105             blogId: blogid//向服务端传的参数,此处只是演示
106         }, function (res) {
107             //此处仅仅是为了演示变化的内容
108             $("#comments-list").html(res.content);
109             //显示分页
110             laypage({
111                 cont: document.getElementById(‘textcenter‘), //容器。值支持id名、原生dom对象,jquery对象。【如该容器为】:<div id="page1"></div>
112                 pages: res.pages, //通过后台拿到的总页数
113                 curr: curr || 1, //当前页
114                 jump: function (obj, first) { //触发分页后的回调
115                     if (!first) { //点击跳页触发函数自身,并传递当前页:obj.curr
116                         curr = obj.curr;
117                         guestbookpage(curr, blogid);
118                     } else {
119                         curr = first;
120                         guestbookpage(curr, blogid);
121                     }
122
123                 }
124             });
125         });
126     };
127     </script>
128     }
129 

这里博客的详情页也是通过布局页来实现的。

三、博客系统详情页留言实现

3.1留言展示页面效果

先要创建一个类在数据库中创建一个表:

Guestbook类

  1 namespace Wchl.WMBlog.Model.Models
  2 {
  3     public class Guestbook
  4     {
  5
  6         /// <summary>留言表
  7         ///
  8         /// </summary>
  9         public int id { get; set; }
 10
 11         /// <summary>博客ID
 12         ///
 13         /// </summary>
 14         public int? blogId { get; set; }
 15         /// <summary>创建时间
 16         ///
 17         /// </summary>
 18         public DateTime createdate { get; set; }
 19         public string username { get; set; }
 20
 21         /// <summary>手机
 22         ///
 23         /// </summary>
 24         public string phone { get; set; }
 25         /// <summary>qq
 26         ///
 27         /// </summary>
 28         public string QQ { get; set; }
 29
 30         /// <summary>留言内容
 31         ///
 32         /// </summary>
 33         public string body { get; set; }
 34         /// <summary>ip地址
 35         ///
 36         /// </summary>
 37         public string ip { get; set; }
 38
 39         /// <summary>是否显示在前台,0否1是
 40         ///
 41         /// </summary>
 42         public bool isshow { get; set; }
 43
 44         public BlogArticle blogarticle { get; set; }
 45     }
 46 }

GuestbookViewModels展示类:

  1 namespace Wchl.WMBlog.Model.VeiwModels
  2 {
  3     /// <summary>
  4     /// 留言信息展示类
  5     /// </summary>
  6     public class GuestbookViewModels
  7     {
  8         /// <summary>留言表
  9         ///
 10         /// </summary>
 11         public int id { get; set; }
 12
 13         /// <summary>博客ID
 14         ///
 15         /// </summary>
 16         public int? blogId { get; set; }
 17         /// <summary>创建时间
 18         ///
 19         /// </summary>
 20         public DateTime createdate { get; set; }
 21         public string username { get; set; }
 22
 23         /// <summary>手机
 24         ///
 25         /// </summary>
 26         public string phone { get; set; }
 27         /// <summary>qq
 28         ///
 29         /// </summary>
 30         public string QQ { get; set; }
 31
 32         /// <summary>留言内容
 33         ///
 34         /// </summary>
 35         public string body { get; set; }
 36         /// <summary>ip地址
 37         ///
 38         /// </summary>
 39         public string ip { get; set; }
 40
 41         /// <summary>是否显示在前台,0否1是
 42         ///
 43         /// </summary>
 44         public bool isshow { get; set; }
 45
 46         public BlogArticle blogarticle { get; set; }
 47     }
 48 }

GuestbookMap字段约束:

  1
  2 namespace Wchl.WMBlog.Model.Maps
  3 {
  4     public class GuestbookMap: EntityTypeConfiguration<Guestbook>
  5     {
  6         public GuestbookMap() {
  7             this.HasKey(p => p.id);
  8             //设置外键
  9             this.HasRequired(p => p.blogarticle).WithMany().HasForeignKey(p => p.blogId);
 10         }
 11     }
 12 }

接下来就是创建相应的仓储接口、实现,服务接口、实现,这里就不一一介绍了,跟上一篇实现博客类的是一样的。

我在实现这个功能的时候,想使用ajax来提交:

这里我把所有留言的内容放在一个部分视图页

_GuestbookPage代码:

  1 <article>
  2     <div spellcheck="false" class="example">
  3         <div class="comments">
  4             <header>
  5                 <div class="pull-right"><a href="#commentReplyForm2" class="btn btn-primary"><i class="icon-comment-alt"></i> 发表评论</a></div>
  6                 <h3>所有评论</h3>
  7             </header>
  8             <section class="comments-list" id="comments-list">
  9               @{ if (ViewBag.gblist != null)
 10                   {
 11                       foreach (var list in ViewBag.gblist)
 12                       {
 13                         <div class="comment">
 14                             <a href="###" class="avatar">
 15                                 <i class="icon-user icon-2x"></i>
 16                             </a>
 17                             <div class="content">
 18                                 <div class="pull-right text-muted">@list.createdate</div>
 19                                 <div><a href="###"><strong>@list.username</strong></a></div>
 20                                 <div class="text">@list.body</div>
 21                                 <div class="actions">
 22                                     <a href="##">回复</a>
 23                                 </div>
 24                             </div>
 25                         </div>
 26                       }
 27                   }
 28
 29             }
 30             </section>
 31             <br />
 32             <div class="text-center" id="textcenter">
 33
 34             </div>
 35             <footer>
 36                 <div class="reply-form" id="commentReplyForm2">
 37                     <a href="###" class="avatar"><i class="icon-user icon-2x"></i></a>
 38                     @using (Ajax.BeginForm("addGuestbook", "Blog", new AjaxOptions()
 39                     {
 40                         HttpMethod = "post",
 41                         OnSuccess="su"
 42
 43                     }, new { @class = "form-horizontal" }))
 44                     {
 45                         <input type="hidden" id="blogId" name="blogId" value=""/>
 46                         <div class="form-group col-md-4 form-inline">
 47                             <label for="username" class="col-xs-3">昵称</label>
 48                             <div>
 49                                 <input type="text" class="form-control" name="username" id="username" placeholder="昵称">
 50                             </div>
 51                         </div>
 52                         <div class="form-group col-md-4 form-inline">
 53                             <label for="phone" class="col-xs-3">手机</label>
 54                             <div>
 55                                 <input type="text" class="form-control" name="phone" id="phone" placeholder="手机">
 56                             </div>
 57                         </div>
 58                         <div class="form-group col-md-4 form-inline">
 59                             <label for="QQ" class="col-xs-3">Q Q</label>
 60                             <div>
 61                                 <input type="text" class="form-control" name="QQ" id="QQ" placeholder="Q Q">
 62                             </div>
 63                         </div>
 64                         <div class="form-group"></div>
 65                         <div class="form-group">
 66                             <textarea class="form-control new-comment-text" id="body" name="body" rows="4" placeholder="撰写留言..."></textarea>
 67                         </div>
 68                         <div class="form-group comment-user">
 69                             <div class="row">
 70                                 <div class="col-md-2 col-md-offset-10"><button type="submit" class="btn btn-block btn-primary " value="提交">提交</button></div>
 71                             </div>
 72                         </div>
 73                     }
 74                 </div>
 75             </footer>
 76         </div>
 77     </div>
 78 </article>
 79 

其中分为两部分,一部分是输入留言,一部分是展示信息。

留言提交的表单如下:

在blog控制器中实现添加数据方法:

  1         /// <summary>
  2         ///提交评论
  3         /// </summary>
  4         /// <param name="model"></param>
  5         /// <returns></returns>
  6         [HttpPost]
  7         public ActionResult addGuestbook(GuestbookViewModels model)
  8         {
  9             model.createdate = DateTime.Now;
 10             model.ip = Request.UserHostAddress;
 11             //AutoMapper自动映射
 12             Mapper.Initialize(cfg => cfg.CreateMap<GuestbookViewModels, Guestbook > ());
 13             Guestbook models = Mapper.Map< GuestbookViewModels, Guestbook> (model);
 14             BlogArticle blogArticle = BlogArticleServive.QueryWhere(a => a.bID == model.blogId).FirstOrDefault();
 15             blogArticle.bcommentNum += 1;
 16             BlogArticleServive.SaverChanges();
 17             GuestbookServices.Add(models);
 18             GuestbookServices.SaverChanges();
 19             ViewBag.gblist = GuestbookServices.QueryOrderBy(c => c.blogId == model.blogId, c => c.createdate, false).ToPagedList(1, 5);
 20             return PartialView("_GuestbookPage");
 21         }

执行成功之后就把信息加载到分页信息的位置。

3.2添加实现之后就是展示数据,展示数据使用的是一个js分页插件laypage.js

在mvc的视图中只能在页面有一个model类,所以就只能使用ViewBag.gblist来传值了,本来这个打算用mvcpager插件,结果发现不行,就只能使用js来分页,实现如下:

后台blog控制器下,实现分页,然后拼接数据:

  1 /// <summary>
  2         /// js分页实现
  3         /// </summary>
  4         /// <param name="page"></param>
  5         /// <param name="blogId"></param>
  6         /// <returns></returns>
  7         public ActionResult getGuestbook(int page,int blogId)
  8         {
  9             StringBuilder sb = new StringBuilder();
 10             int pages = 0;
 11             var modelsLists = GuestbookServices.QueryByPage(page, 5,out pages, c => c.blogId == blogId, c => c.createdate, false);
 12             foreach (var item in modelsLists)
 13             {
 14                 sb.AppendFormat(@"<div class=‘comment‘>
 15 <a href = ‘###‘ class=‘avatar‘>
 16 <i class=‘icon-user icon-2x‘></i>
 17 </a>
 18 <div class=‘content‘>
 19 <div class=‘pull-right text-muted‘>{0}</div>
 20 <div><a href = ‘###‘ ><strong > {1}</strong ></a ></div>
 21 <div class=‘text‘>{2}</div>
 22 <div class=‘actions‘>
 23 <a href = ‘##‘ > 回复 </a>
 24 </div >
 25 </div >
 26 </div >",item.createdate,item.username,item.body);
 27             }
 28             if (pages % 5 == 0)
 29             {
 30                 pages = pages / 5;
 31             }
 32             else
 33             {
 34                 pages = (pages / 5)+1;
 35             }
 36
 37
 38             return Json(new {
 39                 content = sb.ToString(),
 40                 pages= pages
 41             });
 42         }

在详情页中直接调用就可以了实现分页了

四、博客系统广告轮播图管理实现

4.1实现效果这里的轮播图使用的是zui中组件来实现的,

4.2主页轮播图视图中的代码实现

4.3轮播图管理后台页面实现展示

这里上传图片使用的是百度的上传控件

视图页代码实现:

  1
  2 @{
  3     ViewBag.Title = "广告管理";
  4 }
  5 @section stylesheet{
  6     <link href="~/Content/CSS/blogArticleStyle.css" rel="stylesheet" />
  7     <link href="~/Content/lib/DataTables/css/jquery.dataTables.css" rel="stylesheet" />
  8     <link href="~/Content/lib/DataTables/css/dataTables.bootstrap.css" rel="stylesheet" />
  9     <link href="~/Content/lib/webuploader/dist/webuploader.css" rel="stylesheet" />
 10     <style type="text/css">
 11         .uploader-list {
 12             width: 100%;
 13             overflow: hidden;
 14         }
 15
 16         .file-item {
 17             float: left;
 18             position: relative;
 19             margin: 0 20px 20px 0;
 20             padding: 4px;
 21         }
 22
 23             .file-item .info {
 24                 position: absolute;
 25                 left: 4px;
 26                 bottom: 4px;
 27                 right: 4px;
 28                 height: 20px;
 29                 line-height: 20px;
 30                 text-indent: 5px;
 31                 background: rgba(0, 0, 0, 0.6);
 32                 color: white;
 33                 overflow: hidden;
 34                 white-space: nowrap;
 35                 text-overflow: ellipsis;
 36                 font-size: 12px;
 37                 z-index: 10;
 38             }
 39
 40             .file-item .error {
 41                 position: absolute;
 42                 top: 4px;
 43                 left: 4px;
 44                 right: 4px;
 45                 background: red;
 46                 color: white;
 47                 text-align: center;
 48                 height: 20px;
 49                 font-size: 14px;
 50                 line-height: 23px;
 51             }
 52
 53         .upload-state-done:after {
 54             content: "\f00c";
 55             font-family: FontAwesome;
 56             font-style: normal;
 57             font-weight: normal;
 58             line-height: 1;
 59             -webkit-font-smoothing: antialiased;
 60             -moz-osx-font-smoothing: grayscale;
 61             font-size: 32px;
 62             position: absolute;
 63             bottom: 0;
 64             right: 4px;
 65             color: #4cae4c;
 66             z-index: 99;
 67         }
 68
 69         .thumbnail {
 70         }
 71         /*表格信息对齐重写*/
 72         .dataTables_wrapper .dataTables_length {
 73             float: left;
 74             margin-left: 15px;
 75             margin-top: 5px;
 76         }
 77     </style>
 78 }
 79
 80 @*<link href="~/Content/CSS/userStyle.css" rel="stylesheet" />*@
 81 <script src="~/Content/lib/DataTables/js/jquery.dataTables.js"></script>
 82 <script src="~/Content/lib/DataTables/js/dataTables.bootstrap.js"></script>
 83 <script src="~/Content/lib/webuploader/dist/webuploader.js"></script>
 84 <script type="text/javascript">
 85     var table;
 86     // 图片上传demo
 87     $(function () {
 88         //百度上传方法
 89         baiduuploader();
 90         //创建表格
 91         creatabel();
 92     });
 93     //初始化表格
 94     function creatabel() {
 95         table = $(‘#adtabel‘).DataTable({
 96             "processing": true,
 97             "serverSide": true,
 98             //"paging": true,
 99             "scrollY": 366,
100             "ajax": {
101                 url: ‘@Url.Action("getData", "Advertisement")‘
102                 //"dataType": "json"
103             },
104            // "pagingType": "full_numbers",
105            // "sLoadingRecords": "正在加载数据...",
106            // "sZeroRecords": "暂无数据",
107             //"stateSave": true,
108             "searching": false,
109             "aaSorting": [[1, "desc"]],//默认第几个排序
110             "dom": ‘rt<"bottom"iflp><"clear">‘,
111             "columns": [
112                {
113                    "data": "count",
114                     "width": "28px",
115                },
116                {
117                    "data": "imgUrl",
118                    "width": "60px",
119                    render: function (data, type, row, meta) {
120                        //这里是主题  把url变成超链接、把图片路径显示为图片
121                        //return "<a href=‘" + data + "‘>" + data + "</a>";
122                        return "<img src=‘" + data + "‘ style=‘width:50px;height:50px‘  />";
123                    }
124                },
125                { "data": "title" },
126                { "data": "url" },
127                { "data": "createdate" },
128                { "data": "remark" },
129                {
130                    data: null
131                }
132             ],
133             "columnDefs": [
134                 {
135                     //   指定第一列,从0开始,0表示第一列,1表示第二列……
136                     targets: -1,
137                     "width": "100px",
138                     render: function (data, type, row, meta) {
139                         return ‘<a type="button" class="btn btn-danger"  href="#" onclick="del(\‘‘ + row.id + ‘\‘)" ><i class="icon icon-trash"></i>删除</a>‘
140                     }
141                 }
142             ],
143             "language": {
144                 "processing": "玩命加载中...",
145                 "lengthMenu": "显示 _MENU_ 项结果",
146                 "zeroRecords": "没有匹配结果",
147                 "info": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
148                 "infoEmpty": "显示第 0 至 0 项结果,共 0 项",
149                 "infoFiltered": "(由 _MAX_ 项结果过滤)",
150                 "infoPostFix": "",
151                 "url": "",
152                 "paginate": {
153                     "first": "首页",
154                     "previous": "上一页",
155                     "next": "下一页",
156                     "last": "末页"
157                 }
158             }
159         });
160     };
161
162     //删除轮播数据
163     function del(adid) {
164         if (confirm("是否确认删除?"))
165         {
166             $.post(‘@Url.Action("del", "Advertisement")‘, { id: adid },function(ajaxobj){
167                 if(ajaxobj.status=="0")
168                 {
169                     //如果后台删除成功,则刷新表格,并提示用户删除成功
170                     //保留分页信息
171                     table.ajax.reload(null,false);
172                     alert("删除成功");
173                 }
174             })
175         }
176     }
177
178     //百度上传
179     function baiduuploader() {
180         var $ = jQuery,
181            $list = $(‘#fileList‘),
182            // 优化retina, 在retina下这个值是2
183            ratio = window.devicePixelRatio || 1,
184
185            // 缩略图大小
186            thumbnailWidth = 80 * ratio,
187            thumbnailHeight = 80 * ratio,
188
189            // Web Uploader实例
190            uploader;
191
192         // 初始化Web Uploader
193         uploader = WebUploader.create({
194
195             // 自动上传。
196             auto: true,
197
198             // swf文件路径
199             swf: ‘/Content/lib/webuploader/dist/Uploader.swf‘,
200
201             // 文件接收服务端。
202             server: ‘@Url.Action("UpLoadProcess", "Advertisement")‘,
203
204             // 选择文件的按钮。可选。
205             // 内部根据当前运行是创建,可能是input元素,也可能是flash.
206             pick: ‘#filePicker‘,
207
208             // 只允许选择文件,可选。
209             accept: {
210                 title: ‘Images‘,
211                 extensions: ‘gif,jpg,jpeg,bmp,png‘,
212                 mimeTypes: ‘image/*‘
213             }
214         });
215
216         // 当有文件添加进来的时候
217         uploader.on(‘fileQueued‘, function (file) {
218             var $li = $(
219                     ‘<div id="‘ + file.id + ‘" class="file-item thumbnail">‘ +
220                         ‘<img>‘ +
221                         ‘<div class="info">‘ + file.name + ‘</div>‘ +
222                     ‘</div>‘
223                     ),
224                 $img = $li.find(‘img‘);
225
226             $list.append($li);
227
228             // 创建缩略图
229             uploader.makeThumb(file, function (error, src) {
230                 if (error) {
231                     $img.replaceWith(‘<span>不能预览</span>‘);
232                     return;
233                 }
234
235                 $img.attr(‘src‘, src);
236             }, thumbnailWidth, thumbnailHeight);
237         });
238
239         // 文件上传过程中创建进度条实时显示。
240         uploader.on(‘uploadProgress‘, function (file, percentage) {
241             var $li = $(‘#‘ + file.id),
242                 $percent = $li.find(‘.progress span‘);
243
244             // 避免重复创建
245             if (!$percent.length) {
246                 $percent = $(‘<p class="progress"><span></span></p>‘)
247                         .appendTo($li)
248                         .find(‘span‘);
249             }
250
251             $percent.css(‘width‘, percentage * 100 + ‘%‘);
252         });
253
254         // 文件上传成功,给item添加成功class, 用样式标记上传成功。
255         uploader.on(‘uploadSuccess‘, function (file, response) {
256             $(‘#‘ + file.id).addClass(‘upload-state-done‘);
257             //alert(response.filePath);
258             $(‘#ImgUrl‘).val(response.filePath);
259         });
260
261         // 文件上传失败,现实上传出错。
262         uploader.on(‘uploadError‘, function (file) {
263             var $li = $(‘#‘ + file.id),
264                 $error = $li.find(‘div.error‘);
265
266             // 避免重复创建
267             if (!$error.length) {
268                 $error = $(‘<div class="error"></div>‘).appendTo($li);
269             }
270
271             $error.text(‘上传失败‘);
272         });
273
274         // 完成上传完了,成功或者失败,先删除进度条。
275         uploader.on(‘uploadComplete‘, function (file) {
276             $(‘#‘ + file.id).find(‘.progress‘).remove();
277         });
278     };
279     //上传轮播信息成功之后调用
280     function afterSu(ajaxobj) {
281         if (ajaxobj.status == "0") {
282             alert("上传成功!");
283             window.location.reload();
284         } else if (ajaxobj.status == "1") {
285             alert("上传失败!");
286             window.location.reload();
287         }
288     }
289 </script>
290
291 <!-- head star -->
292 <div class="tnav row border-bottom white-bg page-heading">
293     <div class="col-sm-4">
294         <h2 class="fl">博客后台</h2>
295         <ol class="breadcrumb fl">
296             <li><a href="/admin/Home">广告管理</a></li>
297             <li><strong>轮播图管理</strong></li>
298         </ol>
299     </div>
300 </div>
301 <!-- head end -->
302
303 <div class="example scrollbar-hover" style="max-height: 600px; overflow: scroll;">
304     <!--table star-->
305     <table id="adtabel" class="table table-striped table-bordered table-hover dataTables-example dataTable" cellspacing="0">
306         <thead>
307             <tr>
308                 <th>编号</th>
309                 <th>图片</th>
310                 <th>标题</th>
311                 <th>链接</th>
312                 <th>创建时间</th>
313                 <th>备注</th>
314                 <th>操作</th>
315             </tr>
316         </thead>
317         <!-- tbody是必须的 -->
318
319     </table>
320     <!--table end-->
321     <hr />
322     <!--form star-->
323     @using (Ajax.BeginForm("add", "Advertisement", new AjaxOptions()
324     {
325         HttpMethod = "post",
326         OnSuccess = "afterSu"
327     }, new { @class = "form-horizontal" }))
328     {
329         <input type="hidden" id="ImgUrl" name="ImgUrl" value="" />
330             <div class="form-group">
331                 <div class="form-group">
332                     <label for="Title" class="col-sm-2">标题:</label>
333                     <div class="col-md-4 col-sm-10">
334                         <input type="text" class="form-control" id="Title" name="Title" placeholder="标题">
335                     </div>
336                 </div>
337                 <div class="form-group">
338                     <label for="Url" class="col-sm-2">链接:</label>
339                     <div class="col-md-4 col-sm-10">
340                         <input type="text" class="form-control" name="Url" id="Url" placeholder="http://">
341                     </div>
342                 </div>
343                 <div class="form-group">
344                     <label for="Remark" class="col-sm-2">备注:</label>
345                     <div class="col-md-4 col-sm-10">
346                         <textarea rows="2" type="text" class="form-control" name="Remark" id="Remark" placeholder="说明"></textarea>
347                     </div>
348                 </div>
349             </div>
350             <div class="form-group">
351                 <label for="exampleInputPassword4" class="col-sm-2">上传图片:</label>
352                 <div class="col-md-10 col-sm-10">
353                     <!--dom结构部分-->
354                     <div id="uploader-demo">
355                         <!--用来存放item-->
356                         <div id="fileList" class="uploader-list"></div>
357                         <div id="filePicker">选择图片</div>
358                     </div>
359                 </div>
360             </div>
361             <div class="form-group">
362                 <div class="col-sm-offset-2 col-sm-10">
363                     <button type="submit" class="btn btn-info">提交</button>
364                 </div>
365             </div>
366     }
367     <!--form end-->
368 </div>
369
370
371 

控制器实现后台代码

  1 namespace Wchl.WMBlog.WebUI.Areas.admin.Controllers
  2 {
  3     public class AdvertisementController : BaseController
  4     {
  5         IAdvertisementServices AdvertisementServices;
  6         public AdvertisementController(IAdvertisementServices AdvertisementServices)
  7         {
  8             this.AdvertisementServices = AdvertisementServices;
  9         }
 10
 11         // GET: admin/Advertisement
 12         public ActionResult Index()
 13         {
 14             return View();
 15         }
 16
 17         /// <summary>
 18         /// 获取广告信息
 19         /// </summary>
 20         /// <returns></returns>
 21         public ActionResult getData()
 22         {
 23             int pageIndex = Request["start"] != null ? int.Parse(Request["start"]) : 1;
 24             int pageSize = Request["length"] != null ? int.Parse(Request["length"]) : 5;
 25             int draw = Request["draw"] != null ? int.Parse(Request["draw"]) : 1;
 26             int totalCount;
 27             int count = 0;
 28             var adInfoList = AdvertisementServices.QueryByBeginPage(pageIndex, pageSize, out totalCount, r =>true , r => r.Createdate, false);
 29             var temp = from u in adInfoList
 30                        select new { count= count+=1, ID = u.Id, Title = u.Title, ImgUrl = u.ImgUrl, Createdate = u.Createdate,url=u.Url, Remark = u.Remark };
 31             return Json(new {
 32                 data = temp.ToList(),
 33                 draw = draw,
 34                 recordsTotal = totalCount,
 35                 recordsFiltered = totalCount
 36             },JsonRequestBehavior.AllowGet);
 37         }
 38
 39         /// <summary>
 40         /// 删除广告
 41         /// </summary>
 42         /// <param name="id"></param>
 43         /// <returns></returns>
 44         [HttpPost]
 45         public ActionResult del(int id)
 46         {
 47             Advertisement model = new Advertisement() {Id=id };
 48             AdvertisementServices.Delete(model, false);
 49             AdvertisementServices.SaverChanges();
 50             return Json(new { status = "0" },JsonRequestBehavior.AllowGet);
 51         }
 52
 53         /// <summary>
 54         /// 添加广告信息
 55         /// </summary>
 56         /// <returns></returns>
 57         [HttpPost]
 58         public ActionResult Add(AdvertisementViewModels model)
 59         {
 60             model.Createdate = DateTime.Now;
 61             //AutoMapper自动映射
 62             Mapper.Initialize(cfg => cfg.CreateMap<AdvertisementViewModels, Advertisement>());
 63             Advertisement models = Mapper.Map<AdvertisementViewModels, Advertisement>(model);
 64             AdvertisementServices.Add(models);
 65             AdvertisementServices.SaverChanges();
 66             return Json(new { status="0" },JsonRequestBehavior.AllowGet);
 67         }
 68
 69         /// <summary>
 70         /// 百度上传图片
 71         /// </summary>
 72         /// <param name="id">百度插件自定义对图片的命名id</param>
 73         /// <param name="name">图片名称</param>
 74         /// <param name="type">图片类型</param>
 75         /// <param name="lastModifiedDate">图片本身的修改时间</param>
 76         /// <param name="size">图片大小</param>
 77         /// <param name="file">文件流</param>
 78         /// <returns></returns>
 79         public ActionResult UpLoadProcess(string id, string name, string type, string lastModifiedDate, int size, HttpPostedFileBase file)
 80         {
 81             string filePathName = string.Empty;
 82
 83             string localPath = Server.MapPath("/upload/");
 84             if (Request.Files.Count == 0)
 85             {
 86                 return Json(new { jsonrpc = 2.0, error = new { code = 102, message = "保存失败" }, id = "id" });
 87             }
 88
 89             string ex = Path.GetExtension(file.FileName);
 90             filePathName = Guid.NewGuid().ToString("N") + ex;
 91
 92             string datedir = DateTime.Now.ToString("yyyyMMdd");
 93             if (!Directory.Exists(localPath + datedir))
 94             {
 95                 Directory.CreateDirectory(localPath + datedir);
 96             }
 97             string path = localPath + datedir;
 98             try
 99             {
100                 file.SaveAs(Path.Combine(path, filePathName));
101             }
102             catch (Exception)
103             {
104                 return Json(new { jsonrpc = 2.0, error = new { code = 103, message = "保存失败" }, id = "id" });
105             }
106             return Json(new
107             {
108                 jsonrpc = "2.0",
109                 id = id,
110                 filePath =  "/Upload/"+datedir + "/" + filePathName
111             });
112
113         }
114     }
115 }

广告对应的表的类Advertisement:

  1 namespace Wchl.WMBlog.Model.Models
  2 {
  3     public class Advertisement
  4     {
  5         /// <summary>
  6         /// 分类ID
  7         /// </summary>
  8         public int Id { get; set; }
  9         /// <summary>
 10         /// 创建时间
 11         /// </summary>
 12         public DateTime Createdate { get; set; }
 13
 14         /// <summary>
 15         /// 广告图片
 16         /// </summary>
 17         public string ImgUrl { get; set; }
 18
 19         /// <summary>
 20         /// 广告标题
 21         /// </summary>
 22         public string Title { get; set; }
 23
 24         /// <summary>
 25         /// 广告链接
 26         /// </summary>
 27         public string Url { get; set; }
 28
 29         /// <summary>
 30         /// 备注
 31         /// </summary>
 32         public string Remark { get; set; }
 33     }
 34 }

展示类AdvertisementViewModels:

  1 namespace Wchl.WMBlog.Model.VeiwModels
  2 {
  3     /// <summary>
  4     /// 广告类
  5     /// </summary>
  6     public class AdvertisementViewModels
  7     {
  8         /// <summary>
  9         /// 分类ID
 10         /// </summary>
 11         public int Id { get; set; }
 12         /// <summary>
 13         /// 创建时间
 14         /// </summary>
 15         public DateTime Createdate { get; set; }
 16
 17         /// <summary>
 18         /// 广告图片
 19         /// </summary>
 20         public string ImgUrl { get; set; }
 21
 22         /// <summary>
 23         /// 广告标题
 24         /// </summary>
 25         public string Title { get; set; }
 26
 27         /// <summary>
 28         /// 广告链接
 29         /// </summary>
 30         public string Url { get; set; }
 31
 32         /// <summary>
 33         /// 备注
 34         /// </summary>
 35         public string Remark { get; set; }
 36     }
 37 }

表约束AdvertisementMap:

  1 namespace Wchl.WMBlog.Model.Maps
  2 {
  3     public class AdvertisementMap: EntityTypeConfiguration<Advertisement>
  4     {
  5         public AdvertisementMap()
  6         {
  7             this.HasKey(p => p.Id);
  8             this.Property(p => p.ImgUrl).HasMaxLength(512);
  9             this.Property(p => p.Title).HasMaxLength(64);
 10             this.Property(p => p.Url).HasMaxLength(256);
 11         }
 12     }
 13 }

这里实现的是添加图片自动上传:

五、博客系统右侧统计

5.1效果显示,这里的统计主要是对发布时间、阅读排行、评论排行做了统计。

后台实现代码:

部分布局视图代码:

  1 <!--右边栏部分-->
  2 <aside>
  3     <div class="col-md-4">
  4         <section class="youbianlan">
  5             <div class="panel-group">
  6                 <div class="panel">
  7                     <div class="panel-heading">
  8                         <div class="panel-title panel-info">
  9                             <h4>最新发布</h4>
 10                         </div>
 11                     </div>
 12                     <div class="panel-body">
 13                         <ul>
 14                             @{
 15                                 if (ViewBag.blogtimelist != null)
 16                                 {
 17                                     for (int i = 0; i < 10; i++)
 18                                     {
 19                                         <li><a href="/blog/Detail/@ViewBag.blogtimelist[i].bID">@ViewBag.blogtimelist[i].btitle</a></li>
 20                                     }
 21                                 }
 22
 23                             }
 24                         </ul>
 25                     </div>
 26                 </div>
 27             </div>
 28         </section>
 29         <section class="youbianlan">
 30             <div class="panel-group">
 31                 <div class="panel">
 32                     <div class="panel-heading">
 33                         <div class="panel-title panel-info">
 34                             <h4>阅读排行榜</h4>
 35                         </div>
 36                     </div>
 37                     <div class="panel-body">
 38                         <ul>
 39                             @{
 40                                 if (ViewBag.blogtrafficlist != null)
 41                                 {
 42                                     for (int i = 0; i < 10; i++)
 43                                     {
 44                                         <li><a href="/blog/Detail/@ViewBag.blogtrafficlist[i].bID">@ViewBag.blogtrafficlist[i].btitle</a></li>
 45                                     }
 46                                 }
 47
 48                             }
 49                         </ul>
 50                     </div>
 51                 </div>
 52             </div>
 53         </section>
 54         <section class="youbianlan">
 55             <div class="panel-group">
 56                 <div class="panel">
 57                     <div class="panel-heading">
 58                         <div class="panel-title panel-info">
 59                             <h4>评论排行榜</h4>
 60                         </div>
 61                     </div>
 62                     <div class="panel-body">
 63                         <ul>
 64                             @{
 65                                 List<TopgbViewModels> list = ViewBag.blogguestbooklist as List<TopgbViewModels>;
 66                                 if (list != null && list.Any())
 67                                 {
 68                                     if (list.Count < 10)
 69                                     {
 70                                         for (int i = 0; i < list.Count; i++)
 71                                         {
 72                                             <li><a href="/blog/Detail/@list[i].blogId">@list[i].btitle</a></li>
 73                                         }
 74                                     }
 75                                     else
 76                                     {
 77                                         for (int i = 0; i < 10; i++)
 78                                         {
 79                                             <li><a href="/blog/Detail/@list[i].blogId">@list[i].btitle</a></li>
 80                                         }
 81                                     }
 82
 83                                 }
 84
 85                             }
 86                         </ul>
 87                     </div>
 88                 </div>
 89             </div>
 90         </section>
 91     </div>
 92 </aside>
 93 <!--右边栏部分结束-->
 94
 95 

这里重点讲讲怎么在EF中执行SQL语句:

在仓储父类的实现中这里传入的实体就是需要展示表内容的类:

六、博客系统小结

现阶段博客系统已经完成了前台展示,后台发布基本功能,接下来打算在后台添加一个权限模块,个人能力有限,代码水平不够好,也许我这样的代码还入不了大神的法眼,等我把权限做完之后,我会一点一点的来修改代码。

其实我写代码的时间不长,主要是每次想功能怎么实现的时候,要把每一步都想到,感觉编程,真正实现功能的开发编码的时间只有40%左右。

如果大家对这个有什么意见和想法,可以提出来,我会尽量,去修改的,谢谢了。

时间: 2024-10-10 11:45:07

从零开始,搭建博客系统MVC5+EF6搭建框架(5),博客详情页、留言、轮播图管理、右侧统计博文的相关文章

从零开始,搭建博客系统MVC5+EF6搭建框架(4)上,前后台页面布局页面实现,介绍使用的UI框架以及JS组件

一.博客系统进度回顾以及页面设计 1.1页面设计说明 紧接前面基础基本完成了框架搭建,现在开始设计页面,前台页面设计我是模仿我博客园的风格来设计的,后台是常规的左右布局风格. 1.2前台页面风格 主页面: 技术博客风格: 详情页风格: 详情页留言风格: 1.3后台风格: 表格风格: 博客发布风格: 以上看到的系统页面是目前系统完成的风格,以后页面设计都参考这些页面风格. 二.使用前端web框架以及插件说明 2.1选择前端web框架,我找了很多框架,以前学过自学过bootstrap觉得对于没有前端

从零开始,搭建博客系统MVC5+EF6搭建框架(1),EF Code frist、实现泛型数据仓储以及业务逻辑

前言      从上篇30岁找份程序员的工作(伪程序员的独白),文章开始,我说过我要用我自学的技术,来搭建一个博客系统,也希望大家给点意见,另外我很感谢博客园的各位朋友们,对我那篇算是自我阶段总结文章的评论,在里面能看出有很多种声音,有支持的我的朋友给我加油打气,有分享自己工作经历的朋友,有提出忠肯意见的朋友,有对记事本写代码吐槽的朋友,也有希望让我换个行业的,觉得我可能不适合这个行业朋友,不管怎样,我都接受,都是大家同行的一些忠告,谢谢大家. 首先我要在这里感谢很多博客园里面的大牛,写了很多系

从零开始,搭建博客系统MVC5+EF6搭建框架(3),添加Nlog日志、缓存机制(MemoryCache、RedisCache)、创建控制器父类BaseController

一.回顾系统进度以及本章概要 目前博客系统已经数据库创建.以及依赖注入Autofac集成,接下来就是日志和缓存集成,这里日志用的是Nlog,其实还有其他的日志框架如log4,这些博客园都有很多介绍,这里就不说了,缓存机制用的是微软自带的MemoryCache和比较流行Redis,这里我也只是了解使用,没有做更升入的研究,以后好好学一下Redis,然后就是实现一个BaseController父类用来重写JsonResult方法为的是返回时间格式问题,默认json返回的时间格式是Date(84923

从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入

一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 1 namespace Wchl.WMBlog.IRepository 2 { 3 public partial interface IsysUserInfoRepository : IBaseRepository<sysUserInfo> 4 { 5 6 } 7 } 2.创建sysUserInfoRepository类继承BaseReposit

NodeJS Express博客项目实战 之 轮播图管理

轮播图管理添加功能 后台轮播图管理的位置: 因此需在此处加一个路由的跳转: 在视图views中后台的index.html <h2><span class="icon-user"></span>系统管理</h2> <ul > <li><a href="/admin/slider" target="right"><span class="icon-ca

luffy-city 基础环境搭建(至轮播图前后台交互实现)-步骤目录

前后台基础环境搭建 以 luffy-city 的主页为例,打通了轮播图的前后台交互 前言:复习-luffy 项目技术点概括 pip 源配置 python 虚拟环境搭建 luffy 后台配置-项目创建-基本插件安装-目录重构-开发环境配置文件配置(dev.prod)-日志配置 luffy 后台配置-项目环境变量 配置-logger自定义封装与使用-异常模块封装-Response二次封装 创建数据库并分配用户权限 创建应用(app)与用户-配置 media 静态资源接口 vue 环境配置-项目创建-

MVC5+EF6+BootStrap3.3.5 博客系统之项目搭建(一)

环境:vs2013,sql2008R2 引用版本:MVC5,EF6,BootStrap3.3.5 在之前一直都是webfrom开发,虽然开发简单:但是有很多不足的地方.在之前开发都是webfrom+MVC三层架构+数据库等等 我在想将MVC5,EF6,BootStrap3.3.5,结合融于之前的开发模式之中. 1.新建解决方案 2.新建控制台应用程序 Blog.MVC.EF.BootStrap.DAL,主要用于EF数据处理 3.新建3个类库 Blog.MVC.EF.BootStrap.Model

node.js开发博客系统前端项目搭建(一)

Express: https://github.com/petecoop/generator-express 安装node.js和npm 执行: npm install -g yo npm install -g generator-express 执行:yo 创建项目成功. 项目的目录: brew安装:MongoDb http://blog.csdn.net/moumaobuchiyu/article/details/54885306 http://www.cnblogs.com/junqili

MVC5+EF6 基本框架介绍并搭建 01

首先介紹一下MVC结构模式 MVC(Model-View-Controller) Model(模型):充当着两个角色.1,保存数据(原有的数据) 2,处理逻辑数据 View(视图):展示数据,提供操作给用户的UI Controller(控制器):核心之一,用来接收用户的输入并处理,与Model对话,.选择需要呈现的视图 搭建平台:VS2017 打开VS,新建一个解决方案后向解决方案点击右键->添加新项目->选中左侧的Web->选择第一个(ASP.NET WEB 应用程序),然后新建一个名