【SpringBoot搭建個人博客】- 博客管理(七)

博客地址:ONESTARの客棧

源碼領取方式一:

  • 掃一掃文末二維碼,關注公衆號【編程日刊】,後臺回覆【博客】,即可領取源碼

源碼領取方式二:

歡迎給star以鼓勵(^_−)☆

本文將從功能來進行講述,分別有博客新增、查詢,刪除,編輯修改,搜索博客功能,這裏會有比較多的多表查詢,SQL會稍微複雜點。

一、搭建MVC結構

先將MVC架構模型搭建出來,後面再直接根據功能編寫各模塊代碼,創建如下包、類、接口:

  • dao包下持久層接口BlogDao:
package com.star.dao;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

/**
 * @Description: 博客管理持久層接口
 * @Date: Created in 23:45 2020/6/2
 * @Author: ONESTAR
 * @QQ羣: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
@Mapper
@Repository
public interface BlogDao {
    
}
  • mapper文件夾下:BlogDao.xml:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.star.dao.BlogDao">

</mapper>
  • service包下BlogService接口:
package com.star.service;

/**
 * @Description: 博客列表業務層接口
 * @Date: Created in 23:46 2020/6/2
 * @Author: ONESTAR
 * @QQ羣: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
public interface BlogService {

}
  • Impl包下BlogServiceImpl接口實現類:
package com.star.service.Impl;

import com.star.service.BlogService;
import org.springframework.stereotype.Service;

/**
 * @Description: 博客列表業務層接口實現類
 * @Date: Created in 23:47 2020/6/2
 * @Author: ONESTAR
 * @QQ羣: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
@Service
public class BlogServiceImpl implements BlogService {
    
}
  • admin包下BlogController控制器:
package com.star.controller.admin;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Description: 博客管理控制器
 * @Date: Created in 23:45 2020/6/2
 * @Author: ONESTAR
 * @QQ羣: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
@Controller
@RequestMapping("/admin")
public class BlogController {
    
}

接下來就直接根據功能來填充各模塊代碼了,至此,目錄結構如下:

二、博客新增、列表查詢

新增博客包括標題、內容、分類、首圖地址、博客描述,推薦、轉載、讚賞、評論、原創等設置,新增後發佈,在後臺可以展示博客列表,這裏就要進行博客列表查詢了,和之前有重複的知識點就不再提了,新出現的知識點會進行講解,這裏最主要的就是多表查詢了。

分析:

問:在查詢文章列表的時候,前端頁面需要顯示分類名稱,但博客數據表沒有分類字段,這個要如何處理?

答:這裏就要用到Mybatis的多表查詢了,可以通過建立實體類的方式,在mapper定義專門的resultMap用於映射多對一的關係

1. 創建查詢實體類

在com.star包下創建queryvo包,創建BlogQuery查詢列表實體類,根據需要查詢的內容來定義變量,有:主鍵(id)、標題(title)、更新時間(updateTime)、是否推薦(recommend)、是否發佈(published)、分類id(typeId)、分類(type),如下(省去get、set、toString方法):

package com.star.queryvo;

import com.star.entity.Type;

import java.util.Date;

/**
 * @Description: 查詢博客列表
 * @Date: Created in 9:31 2020/6/3
 * @Author: ONESTAR
 * @QQ羣: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
public class BlogQuery {

    private Long id;
    private String title;
    private Date updateTime;
    private Boolean recommend;
    private Boolean published;
    private Long typeId;
    private Type type;
    
}

2. 新增、查詢列表持久層接口

在BlogDao下添加接口:

//保存新增博客
int saveBlog(Blog blog);

//查詢文章管理列表
List<BlogQuery> getAllBlogQuery();

3. 新增、查詢列表mapper:

在BlogDao.xml添加SQL

<!--新增保存文章-->
<insert id="saveBlog" parameterType="com.star.entity.Blog">
    insert into myblog.t_blog (id,title, content, first_picture, flag,
    views, comment_count, appreciation, share_statement, commentabled, published,
    recommend, create_time, update_time, type_id, user_id, description)
    values (#{id},#{title},#{content},#{firstPicture},#{flag},#{views},#{commentCount},#{appreciation},
    #{shareStatement},#{commentabled},#{published},#{recommend},#{createTime},
    #{updateTime},#{typeId},#{userId},#{description});
</insert>

<!--查詢文章管理列表多對一配置-->
<resultMap id="blog" type="com.star.queryvo.BlogQuery">
    <id property="id" column="id"/>
    <result property="title" column="title"/>
    <result property="updateTime" column="update_time"/>
    <result property="recommend" column="recommend"/>
    <result property="published" column="published"/>
    <result property="typeId" column="type_id"/>
    <association property="type" javaType="com.star.entity.Type">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
    </association>
</resultMap>
<!--查詢文章管理列表-->
<select id="getAllBlogQuery" resultMap="blog">
    select b.id,b.title,b.update_time,b.recommend,b.published,b.type_id,t.id,t.name
    from myblog.t_blog b left outer join
    myblog.t_type t on b.type_id = t.id order by b.update_time desc
</select>

多表查詢講解:

  • resultMap屬性:用於映射查詢結果,這裏定義封裝BlogQuery的resultMap
  • association屬性:用於一對一和多對一的關係,把Type實體映射從association元素中提取出來,用一個resultMap元素表示
  • property屬性:關聯查詢的結果集存儲在BlogQuery對象哪個屬性上
  • javaType屬性:用來指定對象所屬的java數據類型

4. 新增、查詢列表業務層接口

在BlogService接口下添加:

//保存新增博客
int saveBlog(Blog blog);

//查詢文章管理列表
List<BlogQuery> getAllBlog();

5. 新增、查詢列表業務層接口實現類

在BlogServiceImpl接口實現類下添加:

@Autowired
private BlogDao blogDao;

//保存新增博客
@Override
public int saveBlog(Blog blog) {
    blog.setCreateTime(new Date());
    blog.setUpdateTime(new Date());
    blog.setViews(0);
    blog.setCommentCount(0);
    return blogDao.saveBlog(blog);
}

//查詢文章管理列表
@Override
public List<BlogQuery> getAllBlog() {
    return blogDao.getAllBlogQuery();
}

講解:

  • 在新增博客中需要初始化創建時間、更新時間、瀏覽數量、訪問數量
  • 調用持久層接口實現相關功能

6. 新增、查詢列表控制器

分析:

問:控制器要如何去編寫,直接做頁面跳轉就行嗎?

答:做頁面跳轉的時候首先要思考需要傳遞哪些數據(model)給前端,光做頁面跳轉肯定是不行的

問:新增博客需要傳遞哪些model

答:博客新增後,會跳轉到博客列表,需要傳遞博客對象和分類的信息, 因此除了博客的model還需要Type相關model

在admin包下的BlogController類中添加控制器代碼:

@Autowired
private BlogService blogService;
@Autowired
private TypeService typeService;

//跳轉博客新增頁面
@GetMapping("/blogs/input")
public String input(Model model) {
    model.addAttribute("types",typeService.getAllType());
    model.addAttribute("blog", new Blog());
    return "admin/blogs-input";
}

//博客新增
@PostMapping("/blogs")
public String post(Blog blog, RedirectAttributes attributes, HttpSession session){
    //新增的時候需要傳遞blog對象,blog對象需要有user
    blog.setUser((User) session.getAttribute("user"));
    //設置blog的type
    blog.setType(typeService.getType(blog.getType().getId()));
    //設置blog中typeId屬性
    blog.setTypeId(blog.getType().getId());
    //設置用戶id
    blog.setUserId(blog.getUser().getId());

    int b = blogService.saveBlog(blog);
    if(b == 0){
        attributes.addFlashAttribute("message", "新增失敗");
    }else {
        attributes.addFlashAttribute("message", "新增成功");
    }
    return "redirect:/admin/blogs";
}

//博客列表
@RequestMapping("/blogs")
public String blogs(Model model, @RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum){

    //按照排序字段 倒序 排序
    String orderBy = "update_time desc";
    PageHelper.startPage(pageNum,10,orderBy);
    List<BlogQuery> list = blogService.getAllBlog();
    PageInfo<BlogQuery> pageInfo = new PageInfo<BlogQuery>(list);
    model.addAttribute("types",typeService.getAllType());
    model.addAttribute("pageInfo",pageInfo);
    return "admin/blogs";

}

7. 前後端交互

前端不做講解,只貼部分代碼,只做參考,有需要可以下載源碼查看:https://github.com/oneStarLR/myblog-mybatis

  • 新增博客:
<a href="#" th:href="@{/admin/blogs/input}">
  <button type="button" class="ui teal button m-mobile-wide m-margin-top"><i class="pencil icon"></i>新增</button>
</a>
  • 新增內容
<!--標記原創、轉載、翻譯-->
<input type="hidden" value="原創" name="flag" th:value="*{flag}" >

<!--博客標題-->
<input type="text" name="title" placeholder="標題" th:value="*{title}">

<!--博客正文-->
<div class="" id="md-content" style="z-index: 1 !important;">
    <textarea placeholder="博客內容" name="content" style="display: none" th:text="*{content}"></textarea>
</div>

<!--分類設置-->
<div th:each="type : ${types}" class="item" data-value="1" th:data-value="${type.id}" th:text="${type.name}">我的故事</div>

<!--首圖設置-->
<input type="text" name="firstPicture" th:value="*{firstPicture}" placeholder="首圖引用地址">

<!--博客描述-->
<textarea name="description" placeholder="博客描述..." maxlength="200" th:text="*{description}"></textarea>

<!--推薦設置-->
<input type="checkbox" id="recommend" name="recommend" checked th:checked="*{recommend}" class="hidden">

<!--轉載聲明-->
<input type="checkbox" id="shareStatement" name="shareStatement" th:checked="*{shareStatement}" class="hidden">

<!--讚賞設置-->
<input type="checkbox" id="appreciation" name="appreciation" th:checked="*{appreciation}" class="hidden">

<!--評論設置-->
<input type="checkbox" id="commentabled" name="commentabled" th:checked="*{commentabled}" class="hidden">
  • 保存發佈:
<button type="button" id="save-btn" class="ui secondary button">保存</button>
<button type="button" id="publish-btn" class="ui teal button">發佈</button>
$('#save-btn').click(function () {
  $('[name="published"]').val(false);
  $('#blog-form').submit();
});
  
$('#publish-btn').click(function () {
  $('[name="published"]').val(true);
  $('#blog-form').submit();
});
  • 提交表單
<form id="blog-form" action="#" th:object="${blog}" th:action="*{id}==null ? @{/admin/blogs} : @{/admin/blogs/{id}(id=*{id})}" method="post" class="ui form">
    <input type="hidden" name="published" th:value="*{published}">
    <input type="hidden" name="id" th:value="*{id}">
    ......
</form>
  • 分頁查詢
<div class="ui inverted divided stackable grid">
    <div class="three wide column" align="center">
      <a class="item" th:href="@{/admin/blogs(pageNum=${pageInfo.hasPreviousPage}?${pageInfo.prePage}:1)}" th:unless="${pageInfo.isFirstPage}">上一頁</a>
    </div>
    
    <div class="ten wide column" align="center">
      <p>第 <span th:text="${pageInfo.pageNum}"></span> 頁,共 <span th:text="${pageInfo.pages}"></span> 頁,有 <span th:text="${pageInfo.total}"></span> 篇文章</p>
    </div>
    
    <div class="three wide column" align="center">
      <a class="item" th:href="@{/admin/blogs(pageNum=${pageInfo.hasNextPage}?${pageInfo.nextPage}:${pageInfo.pages})}" th:unless="${pageInfo.isLastPage}">下一頁</a>
    </div>
</div>

8. 運行訪問

運行項目,訪問 http://localhost:8080/admin, 登錄後點擊文章管理,點擊新增按鈕,跳轉新增頁面,可以新增博文,發佈後跳轉博客列表,並查詢出文章信息。

三、博客刪除

分析:

問:博客刪除delete刪除,一條SQL語句就可以了嗎?

答:刪除比較簡單,實現功能的話直接delete就可以了,但要考慮到刪除後還要跳轉到博客列表,因此還要重定向到博客列表查詢

1.刪除持久層接口

在BlogDao接口中添加:

//刪除博客
void deleteBlog(Long id);

2. 刪除mapper

在BlogDao.xml中添加:

<!--刪除文章-->
<delete id="deleteBlog">
    delete from myblog.t_blog where id = #{id}
</delete>

3. 刪除業務層

  • 刪除業務層接口

在BlogService接口中添加:

//刪除博客
void deleteBlog(Long id);
  • 刪除業務層接口實現

在BlogServiceImpl類中添加:

//刪除博客
@Override
public void deleteBlog(Long id) {
    blogDao.deleteBlog(id);
}

4. 刪除控制器

在BlogController類中添加:

//刪除博客
@GetMapping("/blogs/{id}/delete")
public String delete(@PathVariable Long id, RedirectAttributes attributes) {
    blogService.deleteBlog(id);
    attributes.addFlashAttribute("message", "刪除成功");
    return "redirect:/admin/blogs";
}

講解:

  • @GetMapping("/blogs/{id}/delete"):路徑參數傳遞,{id}爲需要傳遞進去的id值
  • return "redirect:/admin/blogs":用於controller之間的跳轉,重定向到查詢博客列表

5. 前後端交互

<a href="#" th:href="@{/admin/blogs/{id}/delete(id=${blog.id})}" onclick="return confirm('確定要刪除該文章嗎?三思啊! 刪了可就沒了!')" class="ui mini red basic button">刪除</a>

6. 運行訪問

運行項目,訪問 http://localhost:8080/admin, 登錄後點擊文章管理,點擊刪除按鈕,可以刪除文章,並有刪除成功的提示

四、博客編輯

分析:

問:博客編輯需要考慮哪些問題?

答:跳轉編輯頁面的時候需要知道是編輯的哪篇文章,將博客的id傳遞給後端,並且爲了用戶體驗,需要將要修改的數據一併傳過去在前端顯示出來

問:那要如何編寫呢?

答:首先爲了簡化查詢,可以單獨創建博客顯示類:BlogShow類,查詢出需要編輯的博客信息,並使用getBlogById(id)查詢出需要編輯修改的博客

1. 創建編輯修改文章實體類

在queryvo包下創建ShowBlog實體類(省略get、set、toString方法):

package com.star.queryvo;

import java.util.Date;

/**
 * @Description: 編輯修改文章實體類
 * @Date: Created in 15:55 2020/6/6
 * @Author: ONESTAR
 * @QQ羣: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
public class ShowBlog {

    private Long id;
    private String flag;
    private String title;
    private String content;
    private Long typeId;
    private String firstPicture;
    private String description;
    private boolean recommend;
    private boolean published;
    private boolean shareStatement;
    private boolean appreciation;
    private boolean commentabled;
    private Date updateTime;
    
}

2. 博客編輯持久層

在BlogDao接口中添加:

//編輯博客
int updateBlog(ShowBlog showBlog);

//查詢編輯修改的文章
ShowBlog getBlogById(Long id);

3.博客編輯mapper

在BlogDao下添加:

<!--查詢編輯修改的文章-->
<select id="getBlogById" resultType="com.star.queryvo.ShowBlog">
    select b.id,b.flag,b.title,b.content,b.type_id,
    b.first_picture,b.description,b.recommend,b.published,b.share_statement,
    b.appreciation,b.commentabled from myblog.t_blog b  where  b.id = #{id};
</select>

<!--編輯修改文章-->
<update id="updateBlog" parameterType="com.star.queryvo.ShowBlog">
    update myblog.t_blog set published = #{published},flag = #{flag} ,
    title = #{title}, content = #{content}, type_id = #{typeId},
    first_picture = #{firstPicture} , description = #{description} , recommend = #{recommend} ,
    share_statement = #{shareStatement}, appreciation = #{appreciation},
    commentabled = #{commentabled} ,update_time = #{updateTime} where id = #{id};
</update>

4.博客修改業務層

  • 業務層接口

在BlogService下添加:

//查詢編輯修改的文章
ShowBlog getBlogById(Long id);

//編輯修改文章
int updateBlog(ShowBlog showBlog);
  • 接口實現類:
//查詢編輯修改的文章
@Override
public ShowBlog getBlogById(Long id) {
    return blogDao.getBlogById(id);
}

//編輯修改文章
@Override
public int updateBlog(ShowBlog showBlog) {
    showBlog.setUpdateTime(new Date());
    return blogDao.updateBlog(showBlog);
}

5. 博客修改控制器

在BlogController添加:

//跳轉編輯修改文章
@GetMapping("/blogs/{id}/input")
public String editInput(@PathVariable Long id, Model model) {
    ShowBlog blogById = blogService.getBlogById(id);
    List<Type> allType = typeService.getAllType();
    model.addAttribute("blog", blogById);
    model.addAttribute("types", allType);
    return "admin/blogs-input";
}

//編輯修改文章
@PostMapping("/blogs/{id}")
public String editPost(@Valid ShowBlog showBlog, RedirectAttributes attributes) {
    int b = blogService.updateBlog(showBlog);
    if(b == 0){
        attributes.addFlashAttribute("message", "修改失敗");
    }else {
        attributes.addFlashAttribute("message", "修改成功");
    }
    return "redirect:/admin/blogs";
}

6. 前後端交互

<a href="#" th:href="@{/admin/blogs/{id}/input(id=${blog.id})}" class="ui mini teal basic button">編輯</a>

7. 運行訪問

運行項目,訪問 http://localhost:8080/admin, 登錄後點擊文章管理,點擊編輯按鈕,跳轉編輯博客頁面,可以對文章進行編輯

五、搜索博客管理列表

分析:

問:搜索博客管理列表需要考慮哪些問題?

答:這裏的搜索是使用的MySQL的模糊查詢,根據博客標題和博客分類查詢出想要搜索的文章,需要創建有標題和分類屬性的實體類做vo查詢

問:模糊查詢如何操作

答:可以使用bind標籤,bind標籤可以使用OGNL表達式創建一個變量並將其綁定到上下文中

1. 創建搜索博客管理列表實體類

在queryvo包下創建SearchBlog實體類(省略get、set、toString方法):

package com.star.queryvo;

/**
 * @Description: 搜索博客管理列表
 * @Date: Created in 14:16 2020/6/8
 * @Author: ONESTAR
 * @QQ羣: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
public class SearchBlog {

    private String title;
    private Long typeId;
    
}

2. 搜索博客管理列表持久層接口

在BlogDao接口中添加:

//搜索博客管理列表
List<BlogQuery> searchByTitleAndType(SearchBlog searchBlog);

3. 搜索博客管理列表mapper

在BlogDao.xml文件中添加:

<!--搜索博客管理列表-->
<select id="searchByTitleAndType" parameterType="com.star.queryvo.SearchBlog" resultMap="blog">
    <bind name="pattern" value="'%' + title + '%'" />
    select b.id,b.title,b.type_id,t.id,t.name from myblog.t_blog b ,myblog.t_type t
    <where>
        <if test="1 == 1">
            b.type_id = t.id
        </if>
        <if test="typeId != null">
            and b.type_id = #{typeId}
        </if>
        <if test="title != null">
            and b.title like #{pattern}
        </if>
    </where>
</select>

講解:

  • bind:bind標籤可以使用OGNL表達式創建一個變量並將其綁定到上下文中
  • name屬性:爲綁定到上下文的變量名
  • value屬性:爲OGNL表達式

4. 搜索博客管理列表業務層

  • 業務層接口 在BlogService下添加:
//搜索博客管理列表
List<BlogQuery> getBlogBySearch(SearchBlog searchBlog);
  • 接口實現: 在BlogServiceImpl類中添加:
//搜索博客管理列表
@Override
public List<BlogQuery> getBlogBySearch(SearchBlog searchBlog) {
    return blogDao.searchByTitleAndType(searchBlog);
}

5. 搜索博客管理列表控制器

在BlogController類中添加:

//搜索博客管理列表
@PostMapping("/blogs/search")
public String search(SearchBlog searchBlog, Model model,
                     @RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum) {
    List<BlogQuery> blogBySearch = blogService.getBlogBySearch(searchBlog);
    PageHelper.startPage(pageNum, 10);
    PageInfo<BlogQuery> pageInfo = new PageInfo<>(blogBySearch);
    model.addAttribute("pageInfo", pageInfo);
    return "admin/blogs :: blogList";
}

6. 前後端交互

<!--搜索按鍵-->
<button  type="button" id="search-btn" class="ui mini teal basic button"><i class="search icon"></i>搜索</button>
<!--JS-->
$("#search-btn").click(function () {
      $("[name='page']").val(0);
      loaddata();
    });

7. 運行訪問

運行項目,訪問 http://localhost:8080/admin, 登錄後點擊文章管理,在標題框和分類框輸入想要查詢的文章,點擊搜索,即可查詢出想要查詢的文章

SQL參考:https://github.com/gaohan666/blog

至此,博客管理開發完成,下一篇將講述友鏈管理

【點關注,不迷路,歡迎持續關注本站!】


image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章