SpringBoot系列(四):SpringBoot整合Mybatis實現(xiàn)不一樣的CRUD
作者:
修羅debug
版權聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 by-sa 版權協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。
摘要:本文我們將回歸介紹、分享Spring Boot在企業(yè)級應用開發(fā)的過程中所體現(xiàn)出來的作用, 特別是在應用系統(tǒng)業(yè)務模塊的開發(fā)過程中,它跟Mybatis/MybatisPlus(某種持久層框架)整合所體現(xiàn)出來的“雙劍合璧”的巨大功效!在本篇文章中,我們將首先分享如何基于Spring Boot整合Mybatis實現(xiàn)基本的CRUD!
內(nèi)容:作為一款用于與數(shù)據(jù)庫打交道的持久層框架,Mybatis/MybatisPlus著實給我們的企業(yè)級應用系統(tǒng)的開發(fā)帶來了不可磨滅的作用,其高度封裝后的數(shù)據(jù)庫操作接口,即DAO API,可以為企業(yè)級應用開發(fā)過程中的底層數(shù)據(jù)庫操作帶來極大的便捷性,省去了在純生JDBC時代所需要編寫的大量樣板式的代碼的麻煩!
可以毫不夸張地講,大部分企業(yè)級應用的開發(fā)工作量,其核心業(yè)務邏輯就是在實現(xiàn)或者處理業(yè)務模塊的CRUD上,下面我們就基于前文搭建的標準企業(yè)級Spring Boot項目為奠基,整合Mybatis,并實現(xiàn)最基本的CRUD。
在開始開發(fā)之前,我們需要在數(shù)據(jù)庫創(chuàng)建一個數(shù)據(jù)庫表artile,即文章表,其數(shù)據(jù)庫建表語句DDL如下所示:
CREATE TABLE `article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '文章標題',
`user_id` int(11) DEFAULT NULL COMMENT '作者',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文章';
完了之后,采用Mybatis逆向工程生成該數(shù)據(jù)庫表對應的實體類Entity、Mapper操作接口、Mapper操作接口對應的動態(tài)Sql配置文件mapper.xml。其對應的代碼,各位小伙伴可以自行check下來進行查看。
在此之前,需要新建一個ArticleController、IArticleService接口以及ArticleService實現(xiàn)類!
一、新增與修改
(1)對于新增跟修改而言,其實主要有三點需要注意,第一點是前端提交過來的請求參數(shù)的校驗;第二點是查詢是否有新增了相同字段信息的記錄;最后一點則是直接執(zhí)行“新增邏輯”。其Controller對應的代碼如下所示:
@RestController
@RequestMapping("article")
public class ArticleController extends AbstractController{
@Autowired
public IArticleService articleService;
//新增
@RequestMapping(value = "save",method = RequestMethod.POST)
public BaseResponse save(@RequestBody @Validated Article article, BindingResult result){
String error=ValidatorUtil.checkResult(result);
if (StringUtils.isNotBlank(error)){
return new BaseResponse(StatusCode.Fail.getCode(),error);
}
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
Integer id=articleService.saveEntity(article);
response.setData(id);
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
//更新
@RequestMapping(value = "update",method = RequestMethod.POST)
public BaseResponse update(@RequestBody @Validated Article article, BindingResult result){
String error=ValidatorUtil.checkResult(result);
if (StringUtils.isNotBlank(error)){
return new BaseResponse(StatusCode.Fail.getCode(),error);
}
if (article.getId()==null || article.getId()<=0){
return new BaseResponse(StatusCode.InvalidParams);
}
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
articleService.updateEntity(article);
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
}
(2)在這里,我們開發(fā)了一個統(tǒng)一的用于“校驗前端請求參數(shù)”的校驗工具類ValidatorUtil,該工具是跟Hibernate-Validator組件一起結合使用的,主要用于校驗一些加了指定注解的參數(shù),如,上面的Article類,其實是加了一些校驗注解參數(shù)的,如下所示:
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class Article {
private Integer id;
@NotBlank(message = "文章標題不能為空")
private String title;
@NotNull
private Integer userId;
}
其中的@NotBlank等注解即可以用于校驗指定的請求參數(shù),當前端提交過來的對應的請求參數(shù)的取值為NULL或者空字符串時,則會報相應的錯誤,這些錯誤信息會被BindingResult所捕獲,而下面的ValidatorUtil即展示了其對于這些錯誤的統(tǒng)一處理方式:
/**請求參數(shù)統(tǒng)一校驗工具
* @Author:debug (SteadyJack)
* @Date: 2019/8/27 11:52
**/
public class ValidatorUtil {
//統(tǒng)一校驗處理的結果
public static String checkResult(BindingResult result){
StringBuilder sb=new StringBuilder("");
if (result!=null && result.hasErrors()){
//java8 stream寫法
result.getAllErrors().stream().forEach(error -> sb.append(error.getDefaultMessage()).append("\n"));
}
return sb.toString();
}
}
(3)從該代碼中,可以得知,校驗處理的方式主要是通過遍歷獲取其中的errors列表,然后獲取每個error對象實例的message,這個message即為注解@NotBlank上的message屬性的取值,這一點大家在自測的時候即可看到!
完了之后,就是開發(fā)相應的Service的處理邏輯,其完整源代碼如下所示:
@Override
public Integer saveEntity(Article article) throws Exception {
article.setId(null);
articleMapper.insertSelective(article);
//可以返回成功插入到數(shù)據(jù)時那條記錄對應的主鍵id
return article.getId();
}
@Override
public void updateEntity(Article article) throws Exception {
if (article.getId()!=null && article.getId()>=0){
articleMapper.updateByPrimaryKeySelective(article);
}
}
在這里,我們設置了成功插入記錄時,自動返回對應的數(shù)據(jù)庫記錄的主鍵id。接下來就可以進入自測了,如下兩張圖即可說明一切:
二、分頁列表查詢
對于分頁列表查詢,我相信對于接觸過企業(yè)級應用開發(fā)的小伙伴而言都是不陌生的,分頁列表查詢,其實其重點主要在于兩點,第一點是需要保證前端傳遞的參數(shù)具有分頁的參數(shù)pageNo、pageSize;第二點是后端在執(zhí)行完相應的分頁查詢后不僅需要將得到的列表數(shù)據(jù)返回到前端,還需要返回其他的分頁參數(shù),如netxPage,total,size等等,目的是為了方便前端做分頁插件的開發(fā)與顯示。
(1)首先是Controller的代碼:
//查詢
@RequestMapping(value = "query",method = RequestMethod.GET)
public BaseResponse query(@Validated ArticleQueryDto dto, BindingResult result){
String error=ValidatorUtil.checkResult(result);
if (StringUtils.isNotBlank(error)){
return new BaseResponse(StatusCode.Fail.getCode(),error);
}
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
response.setData(articleService.pageList(dto));
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
其中的ArticleQueryDto主要用于接收前端請求過來的參數(shù),如下所示:
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**@Author:debug (SteadyJack)
* @Date: 2019/8/27 9:41
**/
@Data
public class ArticleQueryDto implements Serializable{
@NotNull
private Integer pageNo=1;
@NotNull
private Integer pageSize=10;
//待搜索的內(nèi)容
private String search;
}
(2)接下來是Service的代碼(主要就是借助于PageHelper分頁插件來實現(xiàn)):
@Override
public PageInfo<Article> pageList(ArticleQueryDto dto) throws Exception {
PageHelper.startPage(dto.getPageNo(),dto.getPageSize());
return new PageInfo<>(articleMapper.pageSelect(dto.getSearch()));
}
最后是對應的Mapper操作接口及其對應的動態(tài)Sql的配置mapper.xml,代碼如下所示:
List<Article> pageSelect(@Param("search") String search);
對應的實際的Sql寫法如下所示:
<select id="pageSelect" resultType="com.debug.springboot.model.entity.Article" >
SELECT <include refid="Base_Column_List"/>
FROM article
<where>
<if test="search!=null and search!=''">
title LIKE CONCAT('%',#{search},'%')
</if>
</where>
</select>
(3)最后,當然是進入自測啦,下圖即可說明一切:
三、刪除
對于刪除,也沒啥好說的,值得注意的是,一般在開發(fā)刪除的時候,我們都是采用批量刪除的方式進行開發(fā)(批量當然也適合于刪除單個的邏輯?。?/span>
(1)首先是Controller對應的代碼:
//刪除
@RequestMapping(value = "delete",method = RequestMethod.POST)
public BaseResponse delete(@RequestBody DeleteDto dto){
if (dto.getIds()==null || dto.getIds().isEmpty()){
return new BaseResponse(StatusCode.InvalidParams);
}
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
articleService.deleteEntity(dto.getIds());
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
其中的DeleteDto,主要包括了待批量刪除的id列表:
import lombok.Data;
import java.io.Serializable;
import java.util.Set;
/**
* @Author:debug (SteadyJack)
* @Date: 2019/8/27 10:09
**/
@Data
public class DeleteDto implements Serializable{
private Set<Integer> ids;
}
(2)在Service中實現(xiàn)批量刪除的代碼邏輯如下所示:
@Override
public void deleteEntity(Set<Integer> ids) throws Exception {
//第一種方式
/*if (ids!=null && !ids.isEmpty()){
ids.stream().forEach(id -> articleMapper.deleteByPrimaryKey(id));
}*/
//第二種方式
if (ids!=null && !ids.isEmpty()){
articleMapper.deleteBatch(Joiner.on(",").join(ids));
}
}
在這里,Debug采用了兩種不同的方式進行實現(xiàn),一種是循環(huán)遍歷逐個刪除;一種是采用“Delete
From 表名 Where id
IN(xxx)”的sql進行刪除,為了能讓mybatis執(zhí)行這樣的批量刪除sql,我們需要將Set<Integer>
ids轉(zhuǎn)化為“id + 逗號”拼接起來的字符串格式,即Joiner.on(“,”).join(xx)即可實現(xiàn),其對應的動態(tài)sql如下所示:
void deleteBatch(@Param("ids") String ids);
對應的動態(tài)Sql:
<delete id="deleteBatch">
DELETE FROM article
WHERE id IN (${ids})
</delete>
(3)最后當然是進入自測了,一圖就足以說明一切了:
至此,基于Spring Boot整合Mybatis的分享介紹就到這里了,各位小伙伴可以將源代碼check下來,然后照著文中的介紹敲一遍、自測一遍,完了之后就基本上可以說了掌握了Spring Boot項目下Mybatis的基本使用了!
補充:
1、本文涉及到的相關的源代碼可以到此地址,check出來進行查看學習:
https://gitee.com/steadyjack/SpringBootTechnology
2、關注一下Debug的技術微信公眾號唄,最新的技術文章、技術課程以及技術專欄將會第一時間在公眾號發(fā)布哦!