一、博客系统进度回顾

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

二、博客系统详情页实现

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="=@Model.next">下一篇:@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%左右。

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

补充内容:

根据园友提出的补漏部分说明:

这个QueryByBeginPage是在仓储层写的一个查询分页的功能,是为了配合DataTables使用的。

  1        /// <summary>
2 /// 从第几条开始用于DataTables
3 /// </summary>
4 /// <typeparam name="TKey"></typeparam>
5 /// <param name="pageIndex">第几页开始</param>
6 /// <param name="pagesize">一页几条</param>
7 /// <param name="rowcount">一共多少条</param>
8 /// <param name="predicate">条件</param>
9 /// <param name="keySelector">排序关键字</param>
10 /// <param name="IsQueryOrderBy">升序还是降序</param>
11 /// <returns></returns>
12 public List<TEntity> QueryByBeginPage<TKey>(int pageIndex, int pagesize, out int rowcount, Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, TKey>> keySelector, bool IsQueryOrderBy)
13 {
14 rowcount = _dbSet.Count(predicate);
15 if (IsQueryOrderBy)
16 {
17 return _dbSet.Where(predicate).OrderBy(keySelector).Skip(pageIndex).Take(pagesize).ToList();
18 }
19 else
20 {
21 return _dbSet.Where(predicate).OrderByDescending(keySelector).Skip(pageIndex).Take(pagesize).ToList();
22 }
23 }

这个TopgbViewModels是查询统计留言排行用的一个类,是根据你数据库查询出来表建的相应的类

  1 /// <summary>
2 /// 留言排名展示类
3 /// </summary>
4 public class TopgbViewModels
5 {
6 /// <summary>博客ID
7 ///
8 /// </summary>
9 public int? blogId { get; set; }
10
11 /// <summary>
12 /// 评论数量
13 /// </summary>
14 public int counts { get; set; }
15
16 /// <summary>博客标题
17 ///
18 /// </summary>
19 public string btitle { get; set; }
20 }

有什么不明白的地方都可以跟我留言,我会尽量写清楚点,让大家看的明白点。

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

  1. 从零开始,搭建博客系统MVC5+EF6搭建框架(4)下,前后台布局实现、发布博客以及展示。

    一.博客系统进度回顾 目前已经完成了,前台展示,以及后台发布的功能,最近都在做这个,其实我在国庆的时候就可以弄完的,但是每天自己弄,突然最后国庆2天,连电脑都不想碰,所以就一直拖着,上一篇写了前端实现 ...

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

    一.博客系统进度回顾以及页面设计 1.1页面设计说明 紧接前面基础基本完成了框架搭建,现在开始设计页面,前台页面设计我是模仿我博客园的风格来设计的,后台是常规的左右布局风格. 1.2前台页面风格 主页 ...

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

    前言      从上篇30岁找份程序员的工作(伪程序员的独白),文章开始,我说过我要用我自学的技术,来搭建一个博客系统,也希望大家给点意见,另外我很感谢博客园的各位朋友们,对我那篇算是自我阶段总结文章 ...

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

    一.回顾系统进度以及本章概要 目前博客系统已经数据库创建.以及依赖注入Autofac集成,接下来就是日志和缓存集成,这里日志用的是Nlog,其实还有其他的日志框架如log4,这些博客园都有很多介绍,这 ...

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

    一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...

  6. 一百二十六:CMS系统之轮播图管理页面布局和添加轮播图的模态对话框制作

    视图 @bp.route('/banners/')@login_required@permission_required(CMSPersmission.POSTER)def banners(): re ...

  7. 【干货】利用MVC5+EF6搭建博客系统(四)(下)前后台布局实现、发布博客以及展示

    二.博客系统后台布局实现 2.1.这里所用的是MVC的布局页来实现的,后台主要分为三部分:导航.菜单.主要内容 代码实现: 这里把后台单独放在一个区域里面,所以我这里建立一个admin的区域 在布局页 ...

  8. 【干货】利用MVC5+EF6搭建博客系统(四)(上)前后台页面布局页面实现,介绍使用的UI框架以及JS组件

    一.博客系统进度回顾以及页面设计 1.1页面设计说明 紧接前面基础基本完成了框架搭建,现在开始设计页面,前台页面设计我是模仿我博客园的风格来设计的,后台是常规的左右布局风格. 1.2前台页面风格 主页 ...

  9. day76:luffy:项目前端环境搭建&轮播图的实现

    目录 1.项目前端环境搭建 1.创建项目目录 2.前端初始化全局变量和全局方法 3.跨域CORS 4.axios配置 2.轮播图功能的实现 1.安装依赖模块 2.上传文件相关配置 3.注册home子应 ...

随机推荐

  1. Principles of measurement of sound intensity

    Introduction In accordance with the definition of instantaneous sound intensity as the product of th ...

  2. 拥抱.NET Core,学习.NET Core的基础知识补遗

    前言 .NET Core的新特性之一就是跨平台,但由于对之前框架的兼容导致编写一个.NET Core类库变得相当复杂,主要体现为相当多的框架目标和支持平台,今天我们就对.NET Core的跨平台特性进 ...

  3. 初识ASP.NET Core 1.0

    本文将对微软下一代ASP.NET框架做个概括性介绍,方便大家进一步熟悉该框架. 在介绍ASP.NET Core 1.0之前有必要澄清一些产品名称及版本号.ASP.NET Core1.0是微软下一代AS ...

  4. 【Java并发编程实战】-----synchronized

    在我们的实际应用当中可能经常会遇到这样一个场景:多个线程读或者.写相同的数据,访问相同的文件等等.对于这种情况如果我们不加以控制,是非常容易导致错误的.在java中,为了解决这个问题,引入临界区概念. ...

  5. 说说SQL Server 网络配置

    打开Sql Server Configuration Manager,里面显示了SQL Server的网络配置,这些到底表示什么含义呢? 图一:MSSQLSERVER的协议 这些配置选项,其实就是为了 ...

  6. intellij IDEA 出现“Usage of API documented as @since 1.6+”的解决办法

    问题 在导入java.io.console的时候出现"Usage of API documented as @since 1.6+"

  7. 轻量级前端MVVM框架avalon - 控制器

    引子: 最近工作挺忙,avalon只能断断续续的写下去了,大概看了下angular的源码,看到小一半就比较难坚持了,是块硬骨头,慢慢啃吧 不过angular的的文档中用词还是很优雅: HTML编译器 ...

  8. Linq 知识回顾

    开篇语 在说LINQ之前必须先说说几个重要的C#语言特性 与LINQ有关的语言特性 隐式类型 (1)源起 在隐式类型出现之前, 我们在声明一个变量的时候, 总是要为一个变量指定他的类型 甚至在fore ...

  9. WPF做验证码,小部分修改原作者内容

    原文地址:http://www.cnblogs.com/tianguook/p/4142346.html 首先感谢aparche大牛的帖子,因为过两天可能要做个登录的页面,因此,需要用到验证码,从而看 ...

  10. gcc

    gcc编译源文件一步到位的命令就是 $ gcc demo.c -o demo 实际上这一步包含了四步: 1.预处理 $ gcc -E demo.c demo.i 预处理功能主要包括宏定义,文件包含,条 ...