最簡(jiǎn)單的MyBatis Plus的多表聯(lián)接、分頁(yè)查詢(xún)實(shí)現(xiàn)方法
一、前言
最近在加強(qiáng) ITAEM 團(tuán)隊(duì)的一個(gè) app 項(xiàng)目——學(xué)生教師學(xué)習(xí)交流平臺(tái)
人員組成:安卓 + 前端 + 后臺(tái)
后臺(tái) DAO 層借鑒了華工其他軟件開(kāi)發(fā)團(tuán)隊(duì),使用了新穎強(qiáng)大的 MyBatisPlus 框架,里邊有一個(gè)類(lèi)似百度貼吧的發(fā)帖子的功能:

而如果設(shè)計(jì)表,應(yīng)為
帖子表 t_post
- id
- title 標(biāo)題
- content 內(nèi)容
- xx
- user_id 用戶(hù)外鍵
用戶(hù)表 t_user
+ id
+ name 帖子發(fā)起者名字
+ xx
示例圖中紅色框中的內(nèi)容為 t_user 表的字段 name,
而要實(shí)現(xiàn)上面顯示帖子,就要用到關(guān)聯(lián)查詢(xún)了,而且帖子很多,必須用分頁(yè)查詢(xún),
那么,怎么通過(guò) MyBatisPlus 來(lái)實(shí)現(xiàn)關(guān)聯(lián)、分頁(yè)查詢(xún)呢 ?很簡(jiǎn)單,往下看。
二、需求、數(shù)據(jù)庫(kù)表設(shè)計(jì)
這是個(gè)人 app 項(xiàng)目中 v1.0 版本的部分表。

需求:顯示帖子
要帖子基本內(nèi)容如時(shí)間、帖子內(nèi)容等,即 t_question 表的內(nèi)容全部要,
同時(shí)還要發(fā)帖子的人名字,即 t_student 的字段 name
三、代碼結(jié)構(gòu)
為了寫(xiě)這篇文章,抽取了該 app 項(xiàng)目中的部分代碼,彼此相互關(guān)系如下圖

四、代碼實(shí)現(xiàn)
1、代碼已經(jīng)放到 github 上了,若對(duì)本文的代碼有疑問(wèn)可以去 github 上查看詳情:
https://github.com/larger5/MyBatisPlus_page_tables.git
2、entity、mapper、service、controller 使用了 MyBatisPlus 的代碼生成器,自動(dòng)生成大部分基礎(chǔ)的代碼,操作方法見(jiàn)之前的文章:
在 SpringBoot 中引入 MyBatisPlus 之 常規(guī)操作
1.實(shí)體
① Question
// import 省略
@TableName("t_question")
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "問(wèn)答主鍵id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "學(xué)生外鍵id")
@TableField("student_id")
private Integer studentId;
@ApiModelProperty(value = "問(wèn)題內(nèi)容")
private String content;
@ApiModelProperty(value = "問(wèn)題發(fā)布時(shí)間,發(fā)布的時(shí)候后臺(tái)自動(dòng)生成")
private Date date;
@ApiModelProperty(value = "問(wèn)題懸賞的積分")
private Integer value;
// getter、setter 省略
}
② Student
// import 省略
@TableName("t_student")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "學(xué)生主鍵id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "學(xué)生名稱(chēng)")
private String name;
@ApiModelProperty(value = "學(xué)生密碼")
private String password;
@ApiModelProperty(value = "學(xué)生積分?jǐn)?shù)")
private Integer points;
@ApiModelProperty(value = "學(xué)生郵件地址")
private String email;
@ApiModelProperty(value = "學(xué)生手機(jī)號(hào)碼")
private String phone;
@ApiModelProperty(value = "學(xué)生學(xué)號(hào)")
private String num;
@ApiModelProperty(value = "學(xué)生真實(shí)姓名")
@TableField("true_name")
private String trueName;
// getter、setter 省略
}
2.mapper
① StudentMapper
// import 省略
public interface StudentMapper extends BaseMapper<Student> {
}
② QuestionMapper
// import 省略
public interface QuestionMapper extends BaseMapper<Question> {
/**
*
* @param page 翻頁(yè)對(duì)象,可以作為 xml 參數(shù)直接使用,傳遞參數(shù) Page 即自動(dòng)分頁(yè)
* @return
*/
@Select("SELECT t_question.*,t_student.`name` FROM t_question,t_student WHERE t_question.student_id=t_student.id")
List<QuestionStudentVO> getQuestionStudent(Pagination page);
}
3、service
① StudentService
// import 省略
public interface StudentService extends IService<Student> {
}
② QuestionService
// import 省略
public interface QuestionService extends IService<Question> {
Page<QuestionStudentVO> getQuestionStudent(Page<QuestionStudentVO> page);
}
4、serviceImpl
① StudentServiceImpl
// import 省略
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
}
② QuestionServiceImpl
// 省略 import
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {
@Override
public Page<QuestionStudentVO> getQuestionStudent(Page<QuestionStudentVO> page) {
return page.setRecords(this.baseMapper.getQuestionStudent(page));
}
}
5、controller
// 省略 import
@RestController
@RequestMapping("/common")
@EnableSwagger2
public class CommonController {
@Autowired
QuestionService questionService;
@Autowired
StudentService studentService;
@GetMapping("/getAllQuestionByPage/{page}/{size}")
public Map<String, Object> getAllQuestionByPage(@PathVariable Integer page, @PathVariable Integer size) {
Map<String, Object> map = new HashMap<>();
Page<Question> questionPage = questionService.selectPage(new Page<>(page, size));
if (questionPage.getRecords().size() == 0) {
map.put("code", 400);
} else {
map.put("code", 200);
map.put("data", questionPage);
}
return map;
}
@GetMapping("/getAllQuestionWithStudentByPage/{page}/{size}")
public Map<String, Object> getAllQuestionWithStudentByPage(@PathVariable Integer page, @PathVariable Integer size) {
Map<String, Object> map = new HashMap<>();
Page<QuestionStudentVO> questionStudent = questionService.getQuestionStudent(new Page<>(page, size));
if (questionStudent.getRecords().size() == 0) {
map.put("code", 400);
} else {
map.put("code", 200);
map.put("data", questionStudent);
}
return map;
}
}
6、MyBatisPlus 配置
// 省略 import
@EnableTransactionManagement
@Configuration
@MapperScan("com.cun.app.mapper")
public class MybatisPlusConfig {
/**
* 分頁(yè)插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* 打印 sql
*/
@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
//格式化sql語(yǔ)句
Properties properties = new Properties();
properties.setProperty("format", "true");
performanceInterceptor.setProperties(properties);
return performanceInterceptor;
}
}
7、關(guān)聯(lián)查詢(xún) VO 對(duì)象
// import 省略
public class QuestionStudentVO implements Serializable {
@ApiModelProperty(value = "問(wèn)答主鍵id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "學(xué)生外鍵id")
@TableField("student_id")
private Integer studentId;
private String name;
@ApiModelProperty(value = "問(wèn)題內(nèi)容")
private String content;
@ApiModelProperty(value = "問(wèn)題發(fā)布時(shí)間,發(fā)布的時(shí)候后臺(tái)自動(dòng)生成")
private Date date;
@ApiModelProperty(value = "問(wèn)題懸賞的積分")
private Integer value;
// getter、setter 省略
五、測(cè)試接口

1、沒(méi)有關(guān)聯(lián)的分頁(yè)查詢(xún)接口
http://localhost/common/getAllQuestionByPage/1/2
① json 輸出
{
"code": 200,
"data": {
"total": 10,
"size": 2,
"current": 1,
"records": [
{
"id": 1,
"studentId": 3,
"content": "唐代,渝州城里,有一個(gè)性格開(kāi)朗、樂(lè)觀(guān)的小伙子,名叫景天。",
"date": 1534497561000,
"value": 5
},
{
"id": 2,
"studentId": 1,
"content": "雪見(jiàn)從小父母雙亡,由爺爺唐坤撫養(yǎng)成人。",
"date": 1533201716000,
"value": 20
}
],
"pages": 5
}
}
② sql 執(zhí)行

2、多表關(guān)聯(lián)、分頁(yè)查詢(xún)接口
http://localhost/common/getAllQuestionWithStudentByPage/1/2
① json 輸出
{
"code": 200,
"data": {
"total": 10,
"size": 2,
"current": 1,
"records": [
{
"id": 1,
"studentId": 3,
"name": "vv",
"content": "唐代,渝州城里,有一個(gè)性格開(kāi)朗、樂(lè)觀(guān)的小伙子,名叫景天。",
"date": 1534497561000,
"value": 5
},
{
"id": 2,
"studentId": 1,
"name": "cun",
"content": "雪見(jiàn)從小父母雙亡,由爺爺唐坤撫養(yǎng)成人。",
"date": 1533201716000,
"value": 20
}
],
"pages": 5
}
}
② sql 執(zhí)行

六、小結(jié)
寫(xiě)本文的原因:
①網(wǎng)上有做法不合時(shí)宜的文章(自定義page類(lèi)、配置版)②官方文檔使用的是配置版的,筆者采用注解版的
| MyBatis 配置版 | MyBatis 注解版 |
|---|---|
| ① 動(dòng)態(tài) sql 靈活、② xml 格式的 sql,可拓展性好 | ① 少一個(gè)設(shè)置,少一個(gè)錯(cuò)誤爆發(fā)點(diǎn)、② 代碼清晰優(yōu)雅 |
當(dāng)然,智者見(jiàn)智仁者見(jiàn)仁
參考資料:
MyBatisPlus 官方文檔:分頁(yè)插件:方式一 、傳參區(qū)分模式【推薦】
到此這篇關(guān)于最簡(jiǎn)單的MyBatis Plus的多表聯(lián)接、分頁(yè)查詢(xún)實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)MyBatis Plus多表聯(lián)接、分頁(yè)查詢(xún)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MapStruct @Mapping注解之處理映射中的Null值方式
這篇文章主要介紹了MapStruct @Mapping注解之處理映射中的Null值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
Java訪(fǎng)問(wèn)者設(shè)計(jì)模式詳細(xì)講解
大多數(shù)情況下你不需要訪(fǎng)問(wèn)者模式,但當(dāng)一旦需要訪(fǎng)問(wèn)者模式時(shí),那就是真的需要它了,這是設(shè)計(jì)模式創(chuàng)始人的原話(huà)??梢钥闯鰬?yīng)用場(chǎng)景比較少,但需要它的時(shí)候是不可或缺的,這篇文章就開(kāi)始學(xué)習(xí)最后一個(gè)設(shè)計(jì)模式——訪(fǎng)問(wèn)者模式2022-11-11
Kotlin傳遞可變長(zhǎng)參數(shù)給Java可變參數(shù)實(shí)例代碼
這篇文章主要介紹了Kotlin傳遞可變長(zhǎng)參數(shù)給Java可變參數(shù)實(shí)例代碼,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
FeignClient支持運(yùn)行時(shí)動(dòng)態(tài)指定URL方式
在實(shí)際開(kāi)發(fā)中,我們經(jīng)常通過(guò)FeignClient接口調(diào)用三方API,當(dāng)面對(duì)不同的環(huán)境對(duì)應(yīng)不同的地址時(shí),可以通過(guò)配置文件和占位符來(lái)切換,但在同一個(gè)環(huán)境中需要調(diào)用不同地址的相同接口時(shí),這種方法就失效了,此時(shí),可以通過(guò)實(shí)現(xiàn)RequestInterceptor接口來(lái)動(dòng)態(tài)切換地址2024-11-11
java把字符串寫(xiě)入文件里的簡(jiǎn)單方法分享
這篇文章主要介紹了java把字符串寫(xiě)入到文件里的簡(jiǎn)單方法,這是跟一個(gè)外國(guó)朋友學(xué)的代碼,需要的朋友可以參考下2014-03-03
詳解Java8中CompletableFuture類(lèi)的使用
Java?8中引入了CompletableFuture類(lèi),它是一種方便的異步編程工具,可以處理各種異步操作,本文將詳細(xì)介紹CompletableFuture的使用方式,希望對(duì)大家有所幫助2023-04-04

