又是新的一期了兔院,這一期我們把前面文章于都相關(guān)的基本地方都完成吧缀拭。
每次新寫一章都會有很多話說杠人,到頭來覺得這些話好像無關(guān)痛癢,畢竟我們做技術(shù)的只需要技術(shù)足夠执泰,除非不只做技術(shù)才會想更多枕磁。
說實話,最近經(jīng)歷了很多事情术吝,只想說:時間才是最長的告白计济。
項目github地址:https://github.com/pc859107393/SpringMvcMybatis
我的簡書首頁是:http://www.reibang.com/users/86b79c50cfb3/latest_articles
上一期是:[手把手教程][第二季]java 后端博客系統(tǒng)文章系統(tǒng)——No2
工具
- IDE為idea16
- JDK環(huán)境為1.8
- gradle構(gòu)建,版本:2.14.1
- Mysql版本為5.5.27
- Tomcat版本為7.0.52
- 流程圖繪制(xmind)
- 建模分析軟件PowerDesigner16.5
- 數(shù)據(jù)庫工具MySQLWorkBench排苍,版本:6.3.7build
本期目標
- 文章閱讀前端頁面全部完成
- 根據(jù)頁面框架進行解耦
- 頁面附屬信息
- 文章信息
文章系統(tǒng)前端頁面
文章系統(tǒng)作為我們博客系統(tǒng)中重要的一環(huán)峭咒,我們需要的不僅僅是文章系統(tǒng),更多的是可以理解成一個自媒體平臺纪岁,我們的核心價值通過這個體現(xiàn)出來了凑队,才能把其他的東西做好。
上次我們的文章中可以看到前端頁面的一些東西幔翰,主要是:
- 文章列表(文章內(nèi)容)
- 文章分類導(dǎo)航
- 標簽聚合導(dǎo)航
- 站點基本信息
- 等···
具體顯示信息如圖所示:

從上面的截圖中我們可以看到我們的頁面大概結(jié)構(gòu)漩氨,頁面頭、頁面尾和頁面中間的內(nèi)容遗增,那么出于便利考慮我們需要把頭尾單獨抽取出來存放叫惊,頁面其他的內(nèi)容我們需要根據(jù)需要處理。現(xiàn)在我們先不考慮那么多做修,我們只是基于程序合理建設(shè)的角度來說霍狰,我們需要把頁面上面動態(tài)變化的信息都獨立做成接口來供外部調(diào)用,然后一般不怎么變化的東西我們就直接固化到頁面中饰及,即是說:
- 中間的列表我們采用分頁加載蔗坯,全部動態(tài)從接口獲取
- 上面的一些其他變化的信息我們從請求的時候就附加給它
所以,我們需要把前面的首頁接口重寫一下燎含。
首先宾濒,我們給首頁獲取數(shù)據(jù)的接口打上過時的標記。
/**
* 獲取主頁的json數(shù)據(jù)屏箍,按照道理講這里應(yīng)該根據(jù)頁面結(jié)構(gòu)拆分組合的
*
* @param user 用戶信息
* @return 返回首頁json
*/
@RequestMapping(value = "/home"
, produces = "application/json; charset=utf-8")
@ResponseBody
@Deprecated
public Object getHomeJson(User user) {
//此處代碼省略
}
既然我們已經(jīng)把首頁的設(shè)置為過時绘梦,那么新的接口必須對照著做一個橘忱,那么我們需要怎么處理呢?按照前面的思路來講卸奉,我們現(xiàn)在需要根據(jù)需求將我們頁面信息拆分成多個接口钝诚,首先需要把左邊我們?nèi)Τ鰜淼牟糠终系揭黄穑敲次覀冃枰劝褌€人信息分類導(dǎo)航和標簽聚合這幾個獨立出來榄棵,所以得我們直接上代碼敲长。
/**
* 返回主頁面
*
* @return
*/
@RequestMapping("/main")
public ModelAndView frontMain(HttpServletRequest request) throws Exception {
ModelAndView view = new ModelAndView("frontMain");
//把數(shù)據(jù)存入前端,避免前端再次發(fā)起網(wǎng)絡(luò)請求
view.addObject("framJson", getFramJson());
view.addObject("postsJson", findPublishPost(request, 1, 10));
return view;
}
/**
* 頁面框架的變化信息
* 1秉继、個人信息
* 2祈噪、最新熱點隨機文章信息
* 3、標簽信息
*
* @return
*/
@RequestMapping(value = "/getFramJson"
, produces = "application/json; charset=utf-8")
@ResponseBody
public Object getFramJson() {
HomeBean homeBean = new HomeBean(); //首頁內(nèi)容
HomeBean.DataBean dataBean = new HomeBean.DataBean(); //首頁下面的Data內(nèi)容對象
try {
int toalNum = postService.getAllCount(); //先把總條數(shù)賦值給總頁數(shù)尚辑,作為緩存變量辑鲤,減少下面算法的查找次數(shù)
toalNum = toalNum % 10 > 0 ? toalNum / 10 + 1 : toalNum / 10; //在每頁固定條數(shù)下能不能分頁完成,有余則加一頁碼
List<PostBean> newData = postService.findAllNew();
if (null == newData || newData.isEmpty()) {
//頁面上面推薦的文章信息不為空
dataBean.setNewPosts(null);
dataBean.setHotPosts(null);
dataBean.setRandomPosts(null);
} else {
//首頁文章列表信息設(shè)定
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);
}
//設(shè)置作者信息
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);
}
}
說實話感覺上面沒啥解釋的杠茬,說白了就是將數(shù)據(jù)按照一定的結(jié)構(gòu)組合起來月褥,具體展示的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架構(gòu)"
},
{
"id" : "282",
"postTitle" : "[手把手教程][JavaWeb]優(yōu)雅的SpringMvc+Mybatis應(yīng)用(八)"
}
],
"date" : [
{
"date" : "2015-11-13",
"idList" : [
"71",
"69",
"67"
]
},
{
"date" : "2015-10-15",
"idList" : [
"48",
"46"
]
}
],
"randomPosts" : [
{
"id" : "286",
"postTitle" : "Android-MVP架構(gòu)"
},
{
"id" : "282",
"postTitle" : "[手把手教程][JavaWeb]優(yōu)雅的SpringMvc+Mybatis應(yīng)用(八)"
}
],
"hotPosts" : [
{
"id" : "286",
"postTitle" : "Android-MVP架構(gòu)"
},
{
"id" : "282",
"postTitle" : "[手把手教程][JavaWeb]優(yōu)雅的SpringMvc+Mybatis應(yīng)用(八)"
}
],
"totalNum" : 0
},
"code" : 1
}
通過上面我們組織的json,我們可以很清晰明了的看到我們的數(shù)據(jù)結(jié)構(gòu)是根據(jù)頁面結(jié)構(gòu)來組合的栓票,所以我們需要數(shù)據(jù)的時候?qū)?yīng)著取值就可以解決問題决左。
說了這么多后端的接口,我們現(xiàn)在需要拿數(shù)據(jù)去前臺展示走贪,所以我們需要在前端獲取數(shù)據(jù)佛猛。前臺數(shù)據(jù)展示還是使用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); //更新數(shù)據(jù)
updateNewList(framJsonObj.data.newPosts); //更新數(shù)據(jù)
updateRandList(framJsonObj.data.randomPosts); //更新數(shù)據(jù)
}
function updateHotList(data) {
$("#listHot").empty(); //清空模板數(shù)據(jù)
$("#hotList").html(pagefn(data)); //加入數(shù)據(jù)到模板
}
function updateNewList(data) {
$("#listNew").empty(); //清空模板數(shù)據(jù)
$("#newList").html(pagefn(data)); //加入數(shù)據(jù)到模板
}
function updateRandList(data) {
$("#listRand").empty(); //清空模板數(shù)據(jù)
$("#randList").html(pagefn(data)); //加入數(shù)據(jù)到模板
}
//開始加載列表數(shù)據(jù)
if (postsJsonObj.code == 1) {
pagefn = doT.template($("#pagetmpl").html()); //初始化列表模板
updateList(postsJsonObj.data); //更新數(shù)據(jù)
} else {
alert("獲取數(shù)據(jù)失斪菇啤继找!請聯(lián)系管理員");
}
function updateList(data) {
$("#pagetmpl").empty(); //清空模板數(shù)據(jù)
$("#blog-table-list").html(pagefn(data)); //加入數(shù)據(jù)到模板
}
function goToNextPage() {
pageNum = parseInt(pageNum) + 1;
$.ajax({
type: "POST",
url: '<c:url value="/front/findPublishPost"/>',
data: {pageNum: pageNum, pageSize: pageSize},
dataType: 'json', //當這里指定為json的時候,獲取到了數(shù)據(jù)后會自己解析的逃沿,只需要 返回值.字段名稱 就能使用了
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的時候婴渡,獲取到了數(shù)據(jù)后會自己解析的,只需要 返回值.字段名稱 就能使用了
cache: false,
success: function (data) {
if (data.code == 1) {
updateList(data.data);
pageNum = data.pageNum;
$("#log-controller-now").html(pageNum);
}
}
});
}
上面我們可以看到pagefn用了幾次凯亮,這個是doT的關(guān)鍵詞边臼,意思是設(shè)置模板。
<!--顯示文章列表-->
<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>
<!-- 展示文章導(dǎo)航 -->
<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模板和其他的都差不多触幼,無非就是按照固定的格式組裝數(shù)據(jù)硼瓣,反正就是網(wǎng)頁怎么寫的,然后把格式套上置谦,然后按照格式輸出就行了堂鲤。
做到這里后,我們就能看到做出的結(jié)果是什么樣子的了媒峡。效果圖暫時不上瘟栖,大家后面自行下載項目運行就知道了。
既然這里做了谅阿,那么我們勢必要做一下項目的文章詳情半哟。文章詳情我們應(yīng)該怎么辦呢? 我們需要通過關(guān)鍵數(shù)據(jù)去查找到具體的文章信息签餐。
我們可以看到上面的json數(shù)據(jù)中包含一個id的字段寓涨,然后我們對照數(shù)據(jù)庫會看到id和數(shù)據(jù)庫的id也是對應(yīng)的。所以我們需要用接口實現(xiàn)通過ID查找數(shù)據(jù)庫對應(yīng)的文章信息氯檐。思路有了戒良,那么代碼實現(xiàn)就是很容易的,直接代碼如下:
/**
* RESTful風格的文章頁面
* @RequestMapping(path = "/post/{postId}", method = RequestMethod.GET)
* 通過上面的語句配置訪問路徑/post/后面指定是文檔ID冠摄,在下面的方法參數(shù)中配置注解@PathVariable可以自動賦值糯崎,然后獲取數(shù)據(jù)。
* @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;
}
/**
* 根據(jù)文章ID獲取文章內(nèi)容
*
* @param postId 文章ID
* @return 返回文章ID對應(yīng)的文章內(nèi)容
*/
@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>
最后頁面的樣子如下拆挥,頁面展示代碼也就是獲取到內(nèi)容直接輸出薄霜,具體代碼就不貼了,影響文章篇幅纸兔。大家可以直接到我的GitHub上面下載黄锤。

到目前為止,我們前端的頁面基本完成后面是需要把頁面頭和頁面尾獨立出來食拜,然后我們這種部分方便定制鸵熟。
那么目前前端頁面相關(guān)的東西基本完成,這一期也結(jié)束了负甸,后面我們就是配置系統(tǒng)后端了流强。加油,有興趣額的一起來吧呻待。