[java手把手教程][第二季]java后端博客系統(tǒng)文章系統(tǒng)——No3

又是新的一期了兔院,這一期我們把前面文章于都相關(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)航
  • 站點基本信息
  • 等···

具體顯示信息如圖所示:

我的博客第四章文章系統(tǒng)-首頁結(jié)構(gòu)
我的博客第四章文章系統(tǒng)-首頁結(jié)構(gòu)

從上面的截圖中我們可以看到我們的頁面大概結(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上面下載黄锤。

我的博客第四章文章系統(tǒng)-文章頁面
我的博客第四章文章系統(tǒng)-文章頁面

到目前為止,我們前端的頁面基本完成后面是需要把頁面頭和頁面尾獨立出來食拜,然后我們這種部分方便定制鸵熟。

那么目前前端頁面相關(guān)的東西基本完成,這一期也結(jié)束了负甸,后面我們就是配置系統(tǒng)后端了流强。加油,有興趣額的一起來吧呻待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末打月,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚕捉,更是在濱河造成了極大的恐慌奏篙,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異秘通,居然都是意外死亡为严,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門肺稀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來第股,“玉大人,你說我怎么就攤上這事话原∠ξ牵” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵繁仁,是天一觀的道長涉馅。 經(jīng)常有香客問我,道長黄虱,這世上最難降的妖魔是什么稚矿? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮悬钳,結(jié)果婚禮上盐捷,老公的妹妹穿的比我還像新娘。我一直安慰自己默勾,他們只是感情好碉渡,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著母剥,像睡著了一般滞诺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上环疼,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天习霹,我揣著相機與錄音,去河邊找鬼炫隶。 笑死淋叶,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的伪阶。 我是一名探鬼主播煞檩,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼栅贴!你這毒婦竟也來了斟湃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤檐薯,失蹤者是張志新(化名)和其女友劉穎凝赛,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡墓猎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年捆昏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陶衅。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡屡立,死狀恐怖直晨,靈堂內(nèi)的尸體忽然破棺而出搀军,到底是詐尸還是另有隱情,我是刑警寧澤勇皇,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布罩句,位于F島的核電站,受9級特大地震影響敛摘,放射性物質(zhì)發(fā)生泄漏门烂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一兄淫、第九天 我趴在偏房一處隱蔽的房頂上張望屯远。 院中可真熱鬧,春花似錦捕虽、人聲如沸慨丐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽房揭。三九已至,卻和暖如春晌端,著一層夾襖步出監(jiān)牢的瞬間捅暴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工咧纠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蓬痒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓漆羔,卻偏偏與公主長得像梧奢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钧椰,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容