博客地址:ONESTARの客棧
源碼領取方式一:
- 掃一掃文末二維碼,關注公衆號【編程日刊】,後臺回覆【博客】,即可領取源碼
源碼領取方式二:
以jpa爲持久層源碼地址:https://github.com/oneStarLR/myblog-jpa
以mybatis爲持久層源碼地址:https://github.com/oneStarLR/myblog-mybaits
歡迎給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
至此,博客管理開發完成,下一篇將講述友鏈管理
【點關注,不迷路,歡迎持續關注本站!】