一、博客系统进度回顾
上一遍博客介绍到,系统已经实现到了发布以及前台布局展示,接下来就是实现一些,详情页,留言、轮播图管理、右侧博文统计信息实现。
二、博客系统详情页实现
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") 点击数:@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%左右。
如果大家对这个有什么意见和想法,可以提出来,我会尽量,去修改的,谢谢了。
补充内容:
根据园友提出的补漏部分说明:
这个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 }
有什么不明白的地方都可以跟我留言,我会尽量写清楚点,让大家看的明白点。