又是新的一期了,這一期咱們把前面文章於都相關的基本地方都完成吧。javascript
每次新寫一章都會有不少話說,到頭來以爲這些話好像無關痛癢,畢竟咱們作技術的只須要技術足夠,除非不僅作技術纔會想更多。css
說實話,最近經歷了不少事情,只想說:時間纔是最長的告白。html
項目github地址:github.com/pc859107393…前端
個人簡書首頁是:www.jianshu.com/users/86b79…java
上一期是:[手把手教程][第二季]java 後端博客系統文章系統——No2git
文章系統做爲咱們博客系統中重要的一環,咱們須要的不只僅是文章系統,更多的是能夠理解成一個自媒體平臺,咱們的核心價值經過這個體現出來了,才能把其餘的東西作好。github
上次咱們的文章中能夠看到前端頁面的一些東西,主要是:ajax
具體顯示信息如圖所示:算法
從上面的截圖中咱們能夠看到咱們的頁面大概結構,頁面頭、頁面尾和頁面中間的內容,那麼出於便利考慮咱們須要把頭尾單獨抽取出來存放,頁面其餘的內容咱們須要根據須要處理。如今咱們先不考慮那麼多,咱們只是基於程序合理建設的角度來講,咱們須要把頁面上面動態變化的信息都獨立作成接口來供外部調用,而後通常不怎麼變化的東西咱們就直接固化到頁面中,便是說:sql
因此,咱們須要把前面的首頁接口重寫一下。
首先,咱們給首頁獲取數據的接口打上過期的標記。
/** * 獲取主頁的json數據,按照道理講這裏應該根據頁面結構拆分組合的 * * @param user 用戶信息 * @return 返回首頁json */
@RequestMapping(value = "/home"
, produces = "application/json; charset=utf-8")
@ResponseBody
@Deprecated
public Object getHomeJson(User user) {
//此處代碼省略
}複製代碼
既然咱們已經把首頁的設置爲過期,那麼新的接口必須對照着作一個,那麼咱們須要怎麼處理呢?按照前面的思路來說,咱們如今須要根據需求將咱們頁面信息拆分紅多個接口,首先須要把左邊咱們圈出來的部分整合到一塊兒,那麼咱們須要先把我的信息分類導航和標籤聚合這幾個獨立出來,因此得咱們直接上代碼。
/** * 返回主頁面 * * @return */
@RequestMapping("/main")
public ModelAndView frontMain(HttpServletRequest request) throws Exception {
ModelAndView view = new ModelAndView("frontMain");
//把數據存入前端,避免前端再次發起網絡請求
view.addObject("framJson", getFramJson());
view.addObject("postsJson", findPublishPost(request, 1, 10));
return view;
}
/** * 頁面框架的變化信息 * 一、我的信息 * 二、最新熱點隨機文章信息 * 三、標籤信息 * * @return */
@RequestMapping(value = "/getFramJson"
, produces = "application/json; charset=utf-8")
@ResponseBody
public Object getFramJson() {
HomeBean homeBean = new HomeBean(); //首頁內容
HomeBean.DataBean dataBean = new HomeBean.DataBean(); //首頁下面的Data內容對象
try {
int toalNum = postService.getAllCount(); //先把總條數賦值給總頁數,做爲緩存變量,減小下面算法的查找次數
toalNum = toalNum % 10 > 0 ? toalNum / 10 + 1 : toalNum / 10; //在每頁固定條數下能不能分頁完成,有餘則加一頁碼
List<PostBean> newData = postService.findAllNew();
if (null == newData || newData.isEmpty()) {
//頁面上面推薦的文章信息不爲空
dataBean.setNewPosts(null);
dataBean.setHotPosts(null);
dataBean.setRandomPosts(null);
} else {
//首頁文章列表信息設定
dataBean.setNewPosts(newData);
dataBean.setHotPosts(newData);
dataBean.setRandomPosts(newData);
}
//日期歸檔
List<DateCountBean> allPostDateCount = postService.getAllPostDateCount();
if (null != allPostDateCount && !allPostDateCount.isEmpty()) {
dataBean.setDate(allPostDateCount);
} else {
dataBean.setDate(null);
}
//設置做者信息
List<HashMap<String, String>> userMeta = userService.getUserMeta(1);
dataBean.setAuthor(userMeta);
homeBean.setData(dataBean);
homeBean.setCode(ResponseObj.OK);
homeBean.setMsg(ResponseList.OK_STR);
return new GsonUtils().toJson(homeBean);
} catch (Exception e) {
e.printStackTrace();
//查詢失敗
homeBean.setCode(ResponseObj.FAILED);
homeBean.setMsg(ResponseList.FAILED_STR);
return new GsonUtils().toJson(homeBean);
}
}複製代碼
說實話感受上面沒啥解釋的,說白了就是將數據按照必定的結構組合起來,具體展現的json如何,咱們能夠直接在下面看:
{
"msg" : "success",
"data" : {
"author" : [
{
"meta_key" : "nickname",
"meta_value" : "雨下一整夜"
},
{
"meta_key" : "description",
"meta_value" : "我想在最好的時候碰見最美的你。那是最美。"
},
{
"meta_key" : "managenav-menuscolumnshidden",
"meta_value" : "a:2:{i:0;s:11:\"css-classes\";i:1;s:11:\"description\";}"
}
],
"pageNum" : 0,
"pageSize" : 0,
"newPosts" : [
{
"id" : "286",
"postTitle" : "Android-MVP架構"
},
{
"id" : "282",
"postTitle" : "[手把手教程][JavaWeb]優雅的SpringMvc+Mybatis應用(八)"
}
],
"date" : [
{
"date" : "2015-11-13",
"idList" : [
"71",
"69",
"67"
]
},
{
"date" : "2015-10-15",
"idList" : [
"48",
"46"
]
}
],
"randomPosts" : [
{
"id" : "286",
"postTitle" : "Android-MVP架構"
},
{
"id" : "282",
"postTitle" : "[手把手教程][JavaWeb]優雅的SpringMvc+Mybatis應用(八)"
}
],
"hotPosts" : [
{
"id" : "286",
"postTitle" : "Android-MVP架構"
},
{
"id" : "282",
"postTitle" : "[手把手教程][JavaWeb]優雅的SpringMvc+Mybatis應用(八)"
}
],
"totalNum" : 0
},
"code" : 1
}複製代碼
經過上面咱們組織的json,咱們能夠很清晰明瞭的看到咱們的數據結構是根據頁面結構來組合的,因此咱們須要數據的時候對應着取值就能夠解決問題。
說了這麼多後端的接口,咱們如今須要拿數據去前臺展現,因此咱們須要在前端獲取數據。前臺數據展現仍是使用doT.min.js來展現,代碼以下:
var framJsonStr = JSON.stringify(${framJson});
var framJsonObj = JSON.parse(framJsonStr);
var postsJsonStr = JSON.stringify(${postsJson});
var postsJsonObj = JSON.parse(postsJsonStr);
var pageNum = postsJsonObj.pageNum;
var pageSize = postsJsonObj.pageSize;
var totalNum = postsJsonObj.totalNum;
var authorDes = "<p class=\"text-center\">" + framJsonObj.data.author[0].meta_value + "<br/>" + framJsonObj.data.author[1].meta_value + "</p>";
document.getElementById("authorDescription").innerHTML = authorDes;
if (framJsonObj.code == 1) {
pagefn = doT.template($("#listHot").html()); //初始化列表模板
updateHotList(framJsonObj.data.hotPosts); //更新數據
updateNewList(framJsonObj.data.newPosts); //更新數據
updateRandList(framJsonObj.data.randomPosts); //更新數據
}
function updateHotList(data) {
$("#listHot").empty(); //清空模板數據
$("#hotList").html(pagefn(data)); //加入數據到模板
}
function updateNewList(data) {
$("#listNew").empty(); //清空模板數據
$("#newList").html(pagefn(data)); //加入數據到模板
}
function updateRandList(data) {
$("#listRand").empty(); //清空模板數據
$("#randList").html(pagefn(data)); //加入數據到模板
}
//開始加載列表數據
if (postsJsonObj.code == 1) {
pagefn = doT.template($("#pagetmpl").html()); //初始化列表模板
updateList(postsJsonObj.data); //更新數據
} else {
alert("獲取數據失敗!請聯繫管理員");
}
function updateList(data) {
$("#pagetmpl").empty(); //清空模板數據
$("#blog-table-list").html(pagefn(data)); //加入數據到模板
}
function goToNextPage() {
pageNum = parseInt(pageNum) + 1;
$.ajax({
type: "POST",
url: '<c:url value="/front/findPublishPost"/>',
data: {pageNum: pageNum, pageSize: pageSize},
dataType: 'json', //當這裏指定爲json的時候,獲取到了數據後會本身解析的,只須要 返回值.字段名稱 就能使用了
cache: false,
success: function (data) {
if (data.code == 1) {
updateList(data.data);
pageNum = data.pageNum;
$("#log-controller-now").html(pageNum);
}
}
});
}
function goToLastPage() {
pageNum = parseInt(pageNum) - 1;
$.ajax({
type: "POST",
url: '<c:url value="/front/findPublishPost"/>',
data: {pageNum: pageNum, pageSize: pageSize},
dataType: 'json', //當這裏指定爲json的時候,獲取到了數據後會本身解析的,只須要 返回值.字段名稱 就能使用了
cache: false,
success: function (data) {
if (data.code == 1) {
updateList(data.data);
pageNum = data.pageNum;
$("#log-controller-now").html(pageNum);
}
}
});
}複製代碼
上面咱們能夠看到pagefn用了幾回,這個是doT的關鍵詞,意思是設置模板。
<!--顯示文章列表-->
<div id="blog-table-list">
<script id="pagetmpl" type="text/x-dot-template">
{{ for(var i=0; i
< it.length ; i++){ }} <a href="<c:url value=" /front/post/{{=it[i].id}} "/>">
<div style="width:100%;height: 2px"></div>
<%--<div class="kratos-entry-thumb clearfix">--%>
<%--<img class="kratos-entry-thumb"--%>
<%--src="<c:url value="/static/images/kratos-update.png"/>">--%>
<%--</div>--%>
<div class="kratos-post-inner">
<header class="kratos-entry-header clearfix">
<h1 class="kratos-entry-title">{{=it[i].postTitle}}</h1>
</header>
<div class="kratos-entry-content clearfix">
<p>{{=it[i].postTitle}}</p>
</div>
</div>
<div style="background: #CCCCCC;width:100%;height: 2px"></div>
</a>
{{ } }}
</script>
</div>
<!-- 展現文章導航 -->
<div class="tab-content">
<div class="tab-pane fade" id="newest">
<ul class="list-group" id="newList">
<script id="listNew" type="text/x-dot-template">
{{ for(var i=0; i
< it.length ; i++){ }}
<a class="list-group-item visible-lg"
title="{{=it[i].postTitle}}"
href="<c:url value=" /front/post/{{=it[i].id}} "/>"
rel="bookmark">
<i class="fa fa-book"> {{=it[i].postTitle}}</i>
</a>
{{ } }}</script>
</ul>
</div>
<div class="tab-pane fade in active" id="hot">
<ul class="list-group" id="hotList">
<script id="listHot" type="text/x-dot-template">
{{ for(var i=0; i
< it.length ; i++){ }}
<a class="list-group-item visible-lg"
title="{{=it[i].postTitle}}"
href="<c:url value=" /front/post/{{=it[i].id}} "/>"
rel="bookmark">
<i class="fa fa-book"> {{=it[i].postTitle}}</i>
</a>
{{ } }}</script>
</ul>
</div>
<div class="tab-pane fade" id="rand">
<ul class="list-group" id="randList">
<script id="listRand" type="text/x-dot-template">
{{ for(var i=0; i
< it.length ; i++){ }}
<a class="list-group-item visible-lg"
title="{{=it[i].postTitle}}"
href="<c:url value=" /front/post/{{=it[i].id}} "/>"
rel="bookmark">
<i class="fa fa-book"> {{=it[i].postTitle}}</i>
</a>
{{ } }}</script>
</ul>
</div>
</div>Ï複製代碼
其實在上面的代碼中我們能夠看到doT模板和其餘的都差很少,無非就是按照固定的格式組裝數據,反正就是網頁怎麼寫的,而後把格式套上,而後按照格式輸出就好了。
作到這裏後,咱們就能看到作出的結果是什麼樣子的了。效果圖暫時不上,你們後面自行下載項目運行就知道了。
既然這裏作了,那麼咱們勢必要作一下項目的文章詳情。文章詳情咱們應該怎麼辦呢? 咱們須要經過關鍵數據去查找到具體的文章信息。
咱們能夠看到上面的json數據中包含一個id的字段,而後咱們對照數據庫會看到id和數據庫的id也是對應的。因此咱們須要用接口實現經過ID查找數據庫對應的文章信息。思路有了,那麼代碼實現就是很容易的,直接代碼以下:
/** * RESTful風格的文章頁面 * @RequestMapping(path = "/post/{postId}", method = RequestMethod.GET) * 經過上面的語句配置訪問路徑/post/後面指定是文檔ID,在下面的方法參數中配置註解@PathVariable能夠自動賦值,而後獲取數據。 * @param postId 文章ID * @return 返回文章頁面 */
@RequestMapping(path = "/post/{postId}", method = RequestMethod.GET)
public ModelAndView getPostView(@PathVariable int postId) {
ModelAndView resultView = new ModelAndView("frontPost");
resultView.addObject("framJson", getFramJson());
resultView.addObject("postJson", getPostById(postId));
return resultView;
}
/** * 根據文章ID獲取文章內容 * * @param postId 文章ID * @return 返回文章ID對應的文章內容 */
@RequestMapping(value = "/getPost"
, produces = "application/json; charset=utf-8")
@ResponseBody
public Object getPostById(int postId) {
ResponseObj<Object> responseObj = new ResponseObj<>();
try {
PostBean postBean = postService.findPostById(postId);
if (null == postBean) {
responseObj.setCode(ResponseObj.EMPUTY);
responseObj.setMsg(ResponseObj.EMPUTY_STR);
} else {
responseObj.setCode(ResponseObj.OK);
responseObj.setMsg(ResponseObj.OK_STR);
responseObj.setData(postBean);
}
return new GsonUtils().toJson(responseObj);
} catch (Exception e) {
e.printStackTrace();
responseObj.setCode(ResponseObj.FAILED);
responseObj.setMsg(ResponseObj.FAILED_STR);
return new GsonUtils().toJson(responseObj);
}
}複製代碼
上面的代碼一個是RESTful風格請求地址的文章頁面,一個是api接口訪問地址。下面分別是Service和Dao層的代碼。
/** *這是Service */
@Override
public PostBean findPostById(Serializable postId) {
return dao.findOneById(postId);
}
/** *這是Dao */
@Override
PostBean findOneById(Serializable postId);
<!-- 這是mapper --> <select id="findOneById" resultType="cn.acheng1314.domain.PostBean"> SELECT `ID`,`post_title`,`post_date`,`post_content` FROM `wp_posts` WHERE `ID`=#{postId} AND `post_status`='publish' </select>複製代碼
最後頁面的樣子以下,頁面展現代碼也就是獲取到內容直接輸出,具體代碼就不貼了,影響文章篇幅。你們能夠直接到個人GitHub上面下載。
到目前爲止,咱們前端的頁面基本完成後面是須要把頁面頭和頁面尾獨立出來,而後咱們這種部分方便定製。
那麼目前前端頁面相關的東西基本完成,這一期也結束了,後面咱們就是配置系統後端了。加油,有興趣額的一塊兒來吧。