Django+Nginx+uwsgi搭建自己的博客(八)
在这篇博客中,我们开始为我们的博客开发Blogs App和Users App相关的管理功能,以便每个用户都能管理自己的博客以及评论。目前,Users App的管理功能相对简单,主要功能为查看用户资料以及切换到博客管理页面,如下所示:
在点击了博客管理后,页面将跳转到管理页面,在此可进行对博客的各种管理:
我们的博客管理操作支持对博客的编辑、删除,对草稿的编辑、删除和对评论的删除操作,以及还没有开发的类别管理功能。
首先来添加用户管理功能。我们需要开发一个新页面userIndex来作为用户管理的主页,在该页上会显示出该用户所有的博客列表,以及提供查看用户资料和博客管理的入口。为此,我们需要添加在Users App的目录中添加userTemplate.html作为用户管理的模板,代码如下:
- <!-- userTemplate.html -->
- <!DOCTYPE html>
- <html lang="zh">
- <head>
- <meta charset="UTF-8">
- <script type="text/javascript" src="/static/ckeditor/ckeditor-init.js" data-ckeditor-basepath="/static/ckeditor/ckeditor/" id="ckeditor-init-script"></script>
- <script type="text/javascript" src="/static/ckeditor/ckeditor/ckeditor.js"></script>
- <script type="text/javascript" src="/static/js/jquery-3.2.1.min.js"></script>
- <title>Cap_Liu的博客</title>
- </head>
- <style type="text/css">
- <!-- CSS部分略 -->
- </style>
- <body>
- <h1>Cap_Liu的博客</h1>
- <div class="introduce">
- {{ test }}
- </div>
- <div class="nav">
- {% if username == currentUser.username and currentUser.username != "anony" %}
- <span><a href="{% url 'index' %}">首页</a></span>
- <span><a href="{% url 'users:userinfo' username %}">用户资料</a></span>
- <span><a href="{% url 'blogs:blogmanage' %}">博客管理</a></span>
- {% else %}
- <span><a href="{% url 'index' %}">首页</a>
- <span><a href="{% url 'users:userinfo' username %}">用户资料</a></span>
- {% endif %}
- </div>
- <div class="content">
- {% block content %}
- {% endblock %}
- </div>
- </body>
- </html>
<!-- userTemplate.html --> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <script type="text/javascript" src="/static/ckeditor/ckeditor-init.js" data-ckeditor-basepath="/static/ckeditor/ckeditor/" id="ckeditor-init-script"></script> <script type="text/javascript" src="/static/ckeditor/ckeditor/ckeditor.js"></script> <script type="text/javascript" src="/static/js/jquery-3.2.1.min.js"></script> <title>Cap_Liu的博客</title> </head> <style type="text/css"> <!-- CSS部分略 --> </style> <body> <h1>Cap_Liu的博客</h1> <div class="introduce"> {{ test }} </div> <div class="nav"> {% if username == currentUser.username and currentUser.username != "anony" %} <span><a href="{% url 'index' %}">首页</a></span> <span><a href="{% url 'users:userinfo' username %}">用户资料</a></span> <span><a href="{% url 'blogs:blogmanage' %}">博客管理</a></span> {% else %} <span><a href="{% url 'index' %}">首页</a> <span><a href="{% url 'users:userinfo' username %}">用户资料</a></span> {% endif %} </div> <div class="content"> {% block content %} {% endblock %} </div> </body> </html>在这里,要根据用户登录的用户名来判断是否要显示出博客管理的入口。若查看的用户资料与当前登录用户不符,则无法看到博客管理的入口。
然后,我们建立userindex.html作为用户管理的首页,即显示出该用户所有的博客:
- <!-- userindex.html -->
- {% extends "userTemplate.html" %}
- {% block content %}
- <div id="content" class="list">
- {% if blogList %}
- <ul>
- {% for blog in blogList %}
- <div class="articlelist">
- <a href="{% url 'blogs:content' blog.id %}">{{ blog.title }}</a>-<a href="{% url 'users:userIndex' blog.auther.username %}">{{ blog.auther }}</a>
- <div class="articlelistinfo">
- <span title="阅读次数">阅读 {{ blog.readcount }}</span>
- <span title="创建时间">{{ blog.createdate|date:"Y-m-d H:i:s" }}</span>
- </div>
- </div>
- {% endfor %}
- </ul>
- {% else %}
- <p>No blogs</p>
- {% endif %}
- </div>
- {% endblock %}
<!-- userindex.html --> {% extends "userTemplate.html" %} {% block content %} <div id="content" class="list"> {% if blogList %} <ul> {% for blog in blogList %} <div class="articlelist"> <a href="{% url 'blogs:content' blog.id %}">{{ blog.title }}</a>-<a href="{% url 'users:userIndex' blog.auther.username %}">{{ blog.auther }}</a> <div class="articlelistinfo"> <span title="阅读次数">阅读 {{ blog.readcount }}</span> <span title="创建时间">{{ blog.createdate|date:"Y-m-d H:i:s" }}</span> </div> </div> {% endfor %} </ul> {% else %} <p>No blogs</p> {% endif %} </div> {% endblock %}
userIndex的views函数如下:
- # users/views.py
- # ...
- def userIndex(request,username):
- try:
- user = Users.objects.get(username=username)
- currentUser = Users.objects.get(username=request.session['username'])
- blogList = Blog.objects.filter(auther=username).filter(draft=False)
- content = {'username':username,
- 'currentUser':currentUser,
- 'blogList':blogList
- }
- except Exception as e:
- content = {'username':e}
- return render(request,'users/userindex.html',content)
- # ...
# users/views.py # ... def userIndex(request,username): try: user = Users.objects.get(username=username) currentUser = Users.objects.get(username=request.session['username']) blogList = Blog.objects.filter(auther=username).filter(draft=False) content = {'username':username, 'currentUser':currentUser, 'blogList':blogList } except Exception as e: content = {'username':e} return render(request,'users/userindex.html',content) # ...以及,由于现在我们可以允许其他用户访问用户资料,因此我们要对这个系列第二篇中开发的userInfo函数进行修改,使之能根据不同的用户名显示不同用户的信息:
- # users/views.py
- # ...
- def userinfo(request,username):
- try:
- user = Users.objects.get(username=username)
- currentUser = Users.objects.get(username=request.session['username'])
- birthday = user.birthday
- email = user.email
- registertime = user.registertime
- content = {'username':username,
- 'registertime':registertime,
- 'birthday':birthday,
- 'email':email,
- 'currentUser':currentUser
- }
- except Exception as e:
- pass
- return render(request,'users/userinfo.html',content)
- # ...
# users/views.py # ... def userinfo(request,username): try: user = Users.objects.get(username=username) currentUser = Users.objects.get(username=request.session['username']) birthday = user.birthday email = user.email registertime = user.registertime content = {'username':username, 'registertime':registertime, 'birthday':birthday, 'email':email, 'currentUser':currentUser } except Exception as e: pass return render(request,'users/userinfo.html',content) # ...同时,我们也要对userInfo的url做对应的修改,以及添加userindex的url:
- # users/urls.py
- # ...
- urlpatterns = [
- # ...
- url(r'^userindex/(?P<username>.*)$',views.userIndex,name='userIndex'),
- url(r'^userinfo/(?P<username>.*)$',views.userinfo,name='userinfo')
- ]
# users/urls.py # ... urlpatterns = [ # ... url(r'^userindex/(?P<username>.*)$',views.userIndex,name='userIndex'), url(r'^userinfo/(?P<username>.*)$',views.userinfo,name='userinfo') ]
这样,我们的Users App的管理功能就开发完毕了。现在的Users App的管理功能比较简单,并没有提供修改资料的功能,更主要的是为博客管理功能提供一个入口。
因此,现在我们来看看博客管理功能的实现。当前的博客管理功能包括5个页面articleList.html, blogmanage.html, commentmanage.html, draftmanage.html和failedoperation.html,分别对应文章列表、博客管理、评论管理、草稿箱和拒绝访问功能。为了保持页面风格的统一,以上页面都会继承blogManageTemplate.html模板,如下所示:
- <!-- blogManageTemplate.html-->
- <!DOCTYPE html>
- <html lang="zh">
- <head>
- <meta charset="UTF-8">
- <script type="text/javascript" src="/static/ckeditor/ckeditor-init.js" data-ckeditor-basepath="/static/ckeditor/ckeditor/" id="ckeditor-init-script"></script>
- <script type="text/javascript" src="/static/ckeditor/ckeditor/ckeditor.js"></script>
- <script type="text/javascript" src="/static/js/jquery-3.2.1.min.js"></script>
- <title>Cap_Liu的博客</title>
- </head>
- <style type="text/css">
- <!--CSS部分略,与其他模板相同-->
- </style>
- <body>
- <h1>Cap_Liu的博客</h1>
- <div class="introduce">
- {{ test }}
- </div>
- <div class="nav">
- <span><a href="{% url 'index' %}">首页</a></span>
- <span><a href="{% url 'blogs:articlelist' %}">文章列表</a></span>
- <span><a href="{% url 'blogs:blogmanage' %}">博客管理</a></span>
- <span><a href="{% url 'blogs:commentmanage' %}">评论管理</a></span>
- <span>类别管理</span>
- <span><a href="{% url 'blogs:draftmanage' %}">草稿箱</a></span>
- </div>
- <div class="content">
- {% block content %}
- {% endblock %}
- </div>
- <div class="content">
- {% block comment %}
- {% endblock %}
- </div>
- </body>
- </html>
<!-- blogManageTemplate.html--> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <script type="text/javascript" src="/static/ckeditor/ckeditor-init.js" data-ckeditor-basepath="/static/ckeditor/ckeditor/" id="ckeditor-init-script"></script> <script type="text/javascript" src="/static/ckeditor/ckeditor/ckeditor.js"></script> <script type="text/javascript" src="/static/js/jquery-3.2.1.min.js"></script> <title>Cap_Liu的博客</title> </head> <style type="text/css"> <!--CSS部分略,与其他模板相同--> </style> <body> <h1>Cap_Liu的博客</h1> <div class="introduce"> {{ test }} </div> <div class="nav"> <span><a href="{% url 'index' %}">首页</a></span> <span><a href="{% url 'blogs:articlelist' %}">文章列表</a></span> <span><a href="{% url 'blogs:blogmanage' %}">博客管理</a></span> <span><a href="{% url 'blogs:commentmanage' %}">评论管理</a></span> <span>类别管理</span> <span><a href="{% url 'blogs:draftmanage' %}">草稿箱</a></span> </div> <div class="content"> {% block content %} {% endblock %} </div> <div class="content"> {% block comment %} {% endblock %} </div> </body> </html>
下面来看看5个分页面的实现。blogmanage.html用于列出该用户所有的博客,并提供编辑和删除的功能:
- <!-- blogmanage.html -->
- {% extends "blogManageTemplate.html" %}
- {% block content %}
- <div id="content" class="list">
- <table>
- <tr>
- <td>标题</td>
- <td> </td>
- <td>阅读数</td>
- <td> </td>
- <td>评论数</td>
- <td> </td>
- <td>操作</td>
- </tr>
- {% if blogList %}
- {% for blog in blogList %}
- <tr>
- <td><a href="{% url 'blogs:content' blog.id %}">{{ blog.title }}</a> ({{ blog.createdate|date:"Y-m-d H:i:s" }})</td>
- <td> </td>
- <td>{{ blog.readcount }}</td>
- <td> </td>
- <td>{{ blog.commentcount }}</td>
- <td> </td>
- <td><span><a href="{% url 'blogs:editBlog' blog.id %}">编辑</a></span>|<span><a href="javascript:void(0);" onClick="deleteConfirm('{{ blog.title }}','{{ blog.id }}')">删除</a></span>
- </tr>
- {% endfor %}
- {% else %}
- <p>No blogs</p>
- {% endif %}
- </table>
- </div>
- <script>
- function deleteConfirm(title,id)
- {
- var blogId = id;
- var url_mask = "{% url 'blogs:deleteBlog' 'tmpId' %}".replace('tmpId',blogId);
- if(confirm("确认删除" + title + "吗?"))
- {
- location.href = url_mask;
- }
- }
- </script>
- {% endblock %}
<!-- blogmanage.html --> {% extends "blogManageTemplate.html" %} {% block content %} <div id="content" class="list"> <table> <tr> <td>标题</td> <td> </td> <td>阅读数</td> <td> </td> <td>评论数</td> <td> </td> <td>操作</td> </tr> {% if blogList %} {% for blog in blogList %} <tr> <td><a href="{% url 'blogs:content' blog.id %}">{{ blog.title }}</a> ({{ blog.createdate|date:"Y-m-d H:i:s" }})</td> <td> </td> <td>{{ blog.readcount }}</td> <td> </td> <td>{{ blog.commentcount }}</td> <td> </td> <td><span><a href="{% url 'blogs:editBlog' blog.id %}">编辑</a></span>|<span><a href="javascript:void(0);" onClick="deleteConfirm('{{ blog.title }}','{{ blog.id }}')">删除</a></span> </tr> {% endfor %} {% else %} <p>No blogs</p> {% endif %} </table> </div> <script> function deleteConfirm(title,id) { var blogId = id; var url_mask = "{% url 'blogs:deleteBlog' 'tmpId' %}".replace('tmpId',blogId); if(confirm("确认删除" + title + "吗?")) { location.href = url_mask; } } </script> {% endblock %}在该页面中,会显示出博客的标题、阅读数和评论数,以及提供了编辑和删除的入口链接。这里值得注意的是,对于删除操作,我们需要使用javascript提供一个confirm对话框,防止用户的误操作。而在javascript中,{% url %}标记的参数不能直接设为javascript的变量,因此我们需要设置一个tmpId的占位符,在得到完整的url形式后再用replace函数把tmpId替换成真正的blogId,从而实现删除操作;而对于编辑操作,我们需要将欲编辑的文章的标题、类别和内容填入到addBlog页面中的各个表单中,因此需要修改在第七篇博客中的addBlog.html页面,使得表单的数据可以用后端数据直接填写:
- <!-- addBlog.html -->
- <!--在javascript部分添加以下代码-->
- <script>
- $(document).ready(function(){
- $("#id_title").val('{{ title }}');
- $("#id_category").val('{{ category }}');
- $("#id_content").val('{{ content|safe }}');
- });
- </script>
<!-- addBlog.html --> <!--在javascript部分添加以下代码--> <script> $(document).ready(function(){ $("#id_title").val('{{ title }}'); $("#id_category").val('{{ category }}'); $("#id_content").val('{{ content|safe }}'); }); </script>下面来看一下blogmanage、editblog和deleteblog的view函数:
- # blogs/views.py
- # ...
- def blogmanage(request):
- if request.session['username'] == 'anony':
- return render(request, 'blogs/failedoperation.html')
- else:
- blogList = Blog.objects.filter(auther=request.session['username'])
- return render(request, 'blogs/blogmanage.html', {'blogList': blogList})
- def deleteblog(request,blogId):
- blog = Blog.objects.get(id=blogId)
- if blog.auther.username == request.session['username']:
- blog.delete()
- blogList = Blog.objects.filter(auther=request.session['username'])
- else:
- return render(request, 'blogs/failedoperation.html')
- return HttpResponseRedirect(reverse('blogs:blogmanage'))
- def editblog(request,blogId):
- tmpBlog = Blog.objects.get(id=blogId)
- request.session['currentblogId'] = blogId
- form = BlogForm()
- blogContent = {}
- if tmpBlog.auther.username == request.session['username']:
- blogContent = {
- 'title':tmpBlog.title,
- 'category':tmpBlog.category,
- 'content':tmpBlog.content,
- 'form':form
- }
- else:
- return render(request, 'blogs/failedoperation.html')
- return render(request, 'blogs/addblog.html', blogContent)
- # ...
# blogs/views.py # ... def blogmanage(request): if request.session['username'] == 'anony': return render(request, 'blogs/failedoperation.html') else: blogList = Blog.objects.filter(auther=request.session['username']) return render(request, 'blogs/blogmanage.html', {'blogList': blogList}) def deleteblog(request,blogId): blog = Blog.objects.get(id=blogId) if blog.auther.username == request.session['username']: blog.delete() blogList = Blog.objects.filter(auther=request.session['username']) else: return render(request, 'blogs/failedoperation.html') return HttpResponseRedirect(reverse('blogs:blogmanage')) def editblog(request,blogId): tmpBlog = Blog.objects.get(id=blogId) request.session['currentblogId'] = blogId form = BlogForm() blogContent = {} if tmpBlog.auther.username == request.session['username']: blogContent = { 'title':tmpBlog.title, 'category':tmpBlog.category, 'content':tmpBlog.content, 'form':form } else: return render(request, 'blogs/failedoperation.html') return render(request, 'blogs/addblog.html', blogContent) # ...
对于编辑博客和删除博客这种写操作,我们需要在后端检查博客的作者与当前登录的用户是否相同。相同则进行具体操作,若不同则会跳转至failedoperation.html:
- <!-- failedoperation.html -->
- {% extends "blogManageTemplate.html" %}
- {% block content %}
- <div id="content" class="list">
- <h2>没有权限进行此操作</h2>
- </div>
- {% endblock %}
<!-- failedoperation.html --> {% extends "blogManageTemplate.html" %} {% block content %} <div id="content" class="list"> <h2>没有权限进行此操作</h2> </div> {% endblock %}
在后端检查用户的目的在于,即使前端无法看到编辑或删除的入口,也可以通过拼凑url的方式达到非法编辑或删除的目的。而对于blogManage页面,我们只需检查是否为匿名用户即可,因为该页面不会涉及任何具体操作,只是为编辑和删除操作提供入口。
对于editblog,我们可以复用addblog.html作为编辑的页面,并为其传入博客的标题、种类以及内容,以便通过javascript填入表单;同时,我们还需将currentblogId的值设为当前编辑的blogId,表示我们正在编辑该篇博客。
commentmanage.html用于显示该用户下所有博客的所有评论,包括评论内容、评论作者以及发表时间,博主可以对每条评论实施删除操作。页面代码如下:
- <!-- commentmanage.html -->
- {% extends "blogManageTemplate.html" %}
- {% block content %}
- <div id="content" class="list">
- <table>
- <tr>
- <td>标题</td>
- <td> </td>
- <td>作者</td>
- <td> </td>
- <td>时间</td>
- <td> </td>
- <td>操作</td>
- </tr>
- {% if commentList %}
- {% for comment in commentList %}
- {% for realcomment in comment %}
- <tr>
- <td><a href="{% url 'blogs:content' blog.id %}">{{ realcomment.attachedblog.title }}</a> ({{ realcomment.attachedblog.createdate|date:"Y-m-d H:i:s" }})<br>
- {{ realcomment.content }}
- </td>
- <td> </td>
- <td>{{ realcomment.auther.username }}</td>
- <td> </td>
- <td>{{ realcomment.createtime }}</td>
- <td> </td>
- <td><span><a href="javascript:void(0);" onClick="deleteConfirm('{{ realcomment.id }}')">删除</a></span>
- </tr>
- {% endfor %}
- {% endfor %}
- {% else %}
- <p>No comments</p>
- {% endif %}
- </table>
- </div>
- <script>
- function deleteConfirm(id)
- {
- var commentid = id;
- var url_mask = "{% url 'blogs:deleteComment' 'tmpId' %}".replace('tmpId',commentid);
- if(confirm("确认删除该评论吗?"))
- {
- location.href = url_mask;
- }
- }
- </script>
- {% endblock %}
<!-- commentmanage.html --> {% extends "blogManageTemplate.html" %} {% block content %} <div id="content" class="list"> <table> <tr> <td>标题</td> <td> </td> <td>作者</td> <td> </td> <td>时间</td> <td> </td> <td>操作</td> </tr> {% if commentList %} {% for comment in commentList %} {% for realcomment in comment %} <tr> <td><a href="{% url 'blogs:content' blog.id %}">{{ realcomment.attachedblog.title }}</a> ({{ realcomment.attachedblog.createdate|date:"Y-m-d H:i:s" }})<br> {{ realcomment.content }} </td> <td> </td> <td>{{ realcomment.auther.username }}</td> <td> </td> <td>{{ realcomment.createtime }}</td> <td> </td> <td><span><a href="javascript:void(0);" onClick="deleteConfirm('{{ realcomment.id }}')">删除</a></span> </tr> {% endfor %} {% endfor %} {% else %} <p>No comments</p> {% endif %} </table> </div> <script> function deleteConfirm(id) { var commentid = id; var url_mask = "{% url 'blogs:deleteComment' 'tmpId' %}".replace('tmpId',commentid); if(confirm("确认删除该评论吗?")) { location.href = url_mask; } } </script> {% endblock %}
这里要注意的是我们要显示所有博客下的所有评论,因此我们使用了一个二重循环来查找。该页面的view函数如下:
- # blogs/views.py
# blogs/views.py
- # ...
- def commentmanage(request):
- blogList = Blog.objects.filter(auther=request.session['username'])
- commentList = []
- for blog in blogList:
- commentList.append(Comment.objects.filter(attachedblog=blog))
- return render(request,'blogs/commentmanage.html',{'commentList':commentList})
- def deletecomment(request,commentId):
- comment = Comment.objects.get(id=commentId)
- attachedBlog = comment.attachedblog
- if attachedBlog.auther.username == request.session['username']:
- comment.delete()
- attachedBlog.commentcount -= 1
- attachedBlog.save()
- else:
- return render(request, 'blogs/failedoperation.html')
- return HttpResponseRedirect(reverse('blogs:commentmanage'))
# ... def commentmanage(request): blogList = Blog.objects.filter(auther=request.session['username']) commentList = [] for blog in blogList: commentList.append(Comment.objects.filter(attachedblog=blog)) return render(request,'blogs/commentmanage.html',{'commentList':commentList}) def deletecomment(request,commentId): comment = Comment.objects.get(id=commentId) attachedBlog = comment.attachedblog if attachedBlog.auther.username == request.session['username']: comment.delete() attachedBlog.commentcount -= 1 attachedBlog.save() else: return render(request, 'blogs/failedoperation.html') return HttpResponseRedirect(reverse('blogs:commentmanage'))
- # ...
# ...在commentmanage函数里,我们首先需要用username拿到该用户所有的blog,随后再根据每个blog去获取其下所有的comment。此时,commentList的元素为QuerySet对象,因此在前端需要二重循环来显示所有的评论。
deletecomment相对简单,基本与deleteblog函数相同,要注意的是在删除评论后要将对应博客的commentcount-1。
至于draftmanage.html,该页面与blogmanage.html相同,只不过在view函数中获取的是该用户所有draft=True的博客:
- # blogs/views.py
- # ...
- def draftmanage(request):
- blogList = Blog.objects.filter(auther=request.session['username']).filter(draft=True)
- return render(request, 'blogs/draftmanage.html', {'blogList': blogList})
- # ...
# blogs/views.py # ... def draftmanage(request): blogList = Blog.objects.filter(auther=request.session['username']).filter(draft=True) return render(request, 'blogs/draftmanage.html', {'blogList': blogList}) # ...而articleList.html页面与userindex.html相同,这里就不再赘述。
最后是以上页面的url配置:
- # blogs/urls.py
- urlpatterns = [
- # ...
- # blog manage
- url(r'^articleList/$',views.articlelist,name='articlelist'),
- url(r'^blogmanage$',views.blogmanage,name='blogmanage'),
- url(r'^deleteblog/(?P<blogId>.*)$',views.deleteblog,name='deleteBlog'),
- url(r'^editblog/(?P<blogId>.*)$',views.editblog,name='editBlog'),
- url(r'^commentmanage$',views.commentmanage,name='commentmanage'),
- url(r'^deletecomment/(?P<commentId>.*)$',views.deletecomment,name='deleteComment'),
- url(r'^draftmanage$',views.draftmanage,name='draftmanage')
- ]
# blogs/urls.py urlpatterns = [ # ... # blog manage url(r'^articleList/$',views.articlelist,name='articlelist'), url(r'^blogmanage$',views.blogmanage,name='blogmanage'), url(r'^deleteblog/(?P<blogId>.*)$',views.deleteblog,name='deleteBlog'), url(r'^editblog/(?P<blogId>.*)$',views.editblog,name='editBlog'), url(r'^commentmanage$',views.commentmanage,name='commentmanage'), url(r'^deletecomment/(?P<commentId>.*)$',views.deletecomment,name='deleteComment'), url(r'^draftmanage$',views.draftmanage,name='draftmanage') ]
这篇博文介绍了Users App和Blogs App的相关管理功能,篇幅比较长,主要是不想把Blogs App的管理部分拆成两部分来写,这样不利于程序的连贯性。至此,我们的博客又添加了较为完备的博客管理功能,支持博主对博客进行编辑、删除以及管理评论等操作。在后续的博客中,将继续为大家带来学习Django的心得以及博客的新功能,希望大家继续关注~