Spring Data JPA 实现多表关联查询
本文地址:https://liuyanzhao.com/6978.html
最近抽出时间来做博客,数据库操作使用的是 JPA,相对比 Mybatis 而言,JPA 单表操作非常方便,增删改查都已经写好了。但是多表操作就不如 Mybatis 那种直接写 sql 语句来得方便,JPA 的多表操作比较麻烦。
需求描述
获得文章列表,文章列表里需要显示每篇文章的分类目录列表,因为一个文章可能有多个分类,一个分类当然也可以对应多篇文章的。
下面是我用截图软件画的一个图,描述的是三张表和其主要字段。

文章表 article 和分类表 category 通过 中间表 article_category 关联
我们的需求也很简单,从数据库里查询所有文章,并给每篇文章加一个分类列表的属性。
如图像这样

代码实现
Spring Data JPA 需要的依赖和配置文件这里就不给出了,因为不是本文的重点。
实体类
1、实体类 Article.java
- package com.liuyanzhao.blog.entity;
- import javax.persistence.*;
- import java.io.Serializable;
- import java.util.Date;
- import java.util.Set;
- /**
- * @author 言曌
- * @date 2017/12/11 下午7:46
- */
- @Entity
- @Table(name = "article")
- public class Article implements Serializable {
- private static final long serialVersionUID = 7419229779731522702L;
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private Integer id;
- @Lob//text
- @Column(columnDefinition="text")
- private String title;
- @Lob //longtext
- @Column(columnDefinition="longtext")
- private String content;
- private Integer userId;
- private Integer likeCount;
- private Date createTime;
- private Date updateTime;
- private Integer status;
- @OneToMany(mappedBy = "article",cascade = CascadeType.ALL, orphanRemoval = true)
- private Set<ArticleCategory> articleCategoryList;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- public Integer getUserId() {
- return userId;
- }
- public void setUserId(Integer userId) {
- this.userId = userId;
- }
- public Integer getLikeCount() {
- return likeCount;
- }
- public void setLikeCount(Integer likeCount) {
- this.likeCount = likeCount;
- }
- public Date getCreateTime() {
- return createTime;
- }
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
- public Date getUpdateTime() {
- return updateTime;
- }
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
- public Integer getStatus() {
- return status;
- }
- public void setStatus(Integer status) {
- this.status = status;
- }
- public static long getSerialVersionUID() {
- return serialVersionUID;
- }
- public Set<ArticleCategory> getArticleCategoryList() {
- return articleCategoryList;
- }
- public void setArticleCategoryList(Set<ArticleCategory> articleCategoryList) {
- this.articleCategoryList = articleCategoryList;
- }
- }
注意 43-44 行
2、实体类 Category.java
- package com.liuyanzhao.blog.entity;
- import javax.persistence.*;
- import java.io.Serializable;
- import java.util.Set;
- /**
- * @author 言曌
- * @date 2017/12/11 下午8:16
- */
- @Entity
- @Table(name = "category")
- public class Category implements Serializable {
- private static final long serialVersionUID = 7419229779731522702L;
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private Integer id;
- private String name;
- private String key;
- private Integer status;
- @OneToMany(mappedBy = "category")
- private Set<ArticleCategory> articleCategoryList;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Integer getStatus() {
- return status;
- }
- public void setStatus(Integer status) {
- this.status = status;
- }
- public String getKey() {
- return key;
- }
- public void setKey(String key) {
- this.key = key;
- }
- public static long getSerialVersionUID() {
- return serialVersionUID;
- }
- public Set<ArticleCategory> getArticleCategoryList() {
- return articleCategoryList;
- }
- public void setArticleCategoryList(Set<ArticleCategory> articleCategoryList) {
- this.articleCategoryList = articleCategoryList;
- }
- }
注意 28-29 行
3、实体类 ArticleCategory.java
- package com.liuyanzhao.blog.entity;
- import javax.persistence.*;
- import java.io.Serializable;
- /**
- * @author 言曌
- * @date 2017/12/12 下午4:08
- */
- @Entity
- @Table(name = "article_category")
- public class ArticleCategory implements Serializable {
- private static final long serialVersionUID = 7419229779731522702L;
- @Id
- @ManyToOne
- @JoinColumn(name = "article_id")
- private Article article;
- @Id
- @ManyToOne
- @JoinColumn(name = "category_id")
- private Category category;
- public static long getSerialVersionUID() {
- return serialVersionUID;
- }
- public Article getArticle() {
- return article;
- }
- public void setArticle(Article article) {
- this.article = article;
- }
- public Category getCategory() {
- return category;
- }
- public void setCategory(Category category) {
- this.category = category;
- }
- }
注意 17-25 行
Dao 层
1、ArticleDao.java
- package com.liuyanzhao.blog.dao;
- import com.liuyanzhao.blog.entity.Article;
- import com.liuyanzhao.blog.vo.ArticleVO;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.Pageable;
- import org.springframework.data.jpa.repository.JpaRepository;
- /**
- * @author 言曌
- * @date 2017/11/28 下午3:31
- */
- public interface ArticleDao extends JpaRepository<Article, Integer> {
- //获取文章列表,按status和id降序
- Page<ArticleVO> findAllByOrderByStatusDescIdDesc(Pageable pageable);
- }
2、CategoryDao.java
- package com.liuyanzhao.blog.dao;
- import com.liuyanzhao.blog.entity.Category;
- import org.springframework.data.jpa.repository.JpaRepository;
- /**
- * @author 言曌
- * @date 2017/12/12 上午11:16
- */
- public interface CategoryDao extends JpaRepository<Category, Integer> {
- }
Service 层
1、ArticleService.java
- package com.liuyanzhao.blog.service;
- import com.liuyanzhao.blog.vo.ArticleVO;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.Pageable;
- /**
- * @author 言曌
- * @date 2017/12/9 下午4:10
- */
- public interface ArticleService {
- //获得文章列表
- Page<ArticleVO> findAll(Pageable pageable);
- }
2、ArticleServiceImpl.java
- package com.liuyanzhao.blog.service.Impl;
- import com.liuyanzhao.blog.dao.ArticleDao;
- import com.liuyanzhao.blog.service.ArticleService;
- import com.liuyanzhao.blog.vo.ArticleVO;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.Pageable;
- import org.springframework.stereotype.Service;
- import javax.transaction.Transactional;
- /**
- * @author 言曌
- * @date 2017/12/9 下午4:10
- */
- @Service("articleService")
- @Transactional
- public class ArticleServiceImpl implements ArticleService {
- @Autowired
- private ArticleDao articleDao;
- @Override
- public Page<ArticleVO> findAll(Pageable pageable) {
- Page<ArticleVO> articleVOPage = articleDao.findAllByOrderByStatusDescIdDesc(pageable);
- return articleVOPage;
- }
- }
Controller 层
ArticleController.java
- package com.liuyanzhao.blog.controller;
- import com.liuyanzhao.blog.service.ArticleService;
- import com.liuyanzhao.blog.vo.ArticleVO;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.PageRequest;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.*;
- import org.springframework.web.servlet.ModelAndView;
- /**
- * @author 言曌
- * @date 2017/11/28 下午3:33
- */
- @Controller
- public class ArticleController {
- @Autowired
- private ArticleService articleService;
- @RequestMapping(value = "/admin/article")
- public ModelAndView listUser(@RequestParam(value = "page",defaultValue = "1") Integer page,
- @RequestParam(value = "size",defaultValue = "10") Integer size) {
- ModelAndView modelAndView = new ModelAndView();
- PageRequest request = new PageRequest(page-1,size);
- Page<ArticleVO> articleVOPage = articleService.findAll(request);
- modelAndView.addObject("articleVOPage",articleVOPage);
- modelAndView.setViewName("/admin/article/list");
- return modelAndView;
- }
- }
视图层
视图层主要看表格的打印吧,分页部分和其他内容就不贴出来了
- <table class="table table-bordered">
- <tr>
- <th><input type="checkbox" id="allSelect" onclick="DoCheck()"></th>
- <th>ID</th>
- <th>作者</th>
- <th>标题</th>
- <th>分类</th>
- <th>更新时间</th>
- <th>操作</th>
- </tr>
- <c:forEach var="article" items="${articleVOPage.content}">
- <tr>
- <td><input type="checkbox" name="ids" value="${article.id}"></td>
- <td>${article.id}</td>
- <td>${article.userId}</td>
- <td><a href="">${article.title}</a></td>
- <td>
- <c:forEach var="c" items="${article.articleCategoryList}">
- <a href="">${c.category.name}</a>
- </c:forEach>
- </td>
- <td>${article.updateTime}</td>
- <td>
- <a href="${pageContext.request.contextPath}/admin/user/profile/${article.id}">
- <button type="button" class="btn btn-success btn-xs">查看</button>
- </a>
- <button type="button" class="btn btn-danger btn-xs"
- onclick="deleteUser(${article.id})">删除
- </button>
- <a href="${pageContext.request.contextPath}/admin/user/edit/${article.id}">
- <button type="button" class="btn btn-primary btn-xs">编辑</button>
- </a>
- </td>
- </tr>
- </c:forEach>
- </table>
最终效果图就是上面的

Spring Data JPA 实现多表关联查询的更多相关文章
- SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法
软件152 尹以操 首先谢谢大佬的简书文章:http://www.jianshu.com/p/45ad65690e33# 这篇文章中讲的是spring中使用spring data jpa,使用了xml ...
- 【hql】spring data jpa中 @Query使用hql查询 问题
spring data jpa中 @Query使用hql查询 问题 使用hql查询, 1.from后面跟的是实体类 不是数据表名 2.字段应该用实体类中的字段 而不是数据表中的属性 实体如下 hql使 ...
- spring data jpa 使用方法命名规则查询
按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写.框架在进行方法名解析时,会先把方法名多余的前缀 ...
- 使用Spring Data JPA的Specification构建数据库查询
Spring Data JPA最为优秀的特性就是可以通过自定义方法名称生成查询来轻松创建查询SQL.Spring Data JPA提供了一个Repository编程模型,最简单的方式就是通过扩展Jpa ...
- spring data jpa 使用JPQL的方式查询
用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询 @Que ...
- Spring Data JPA 复杂/多条件组合查询
1: 编写DAO类或接口 dao类/接口 需继承 public interface JpaSpecificationExecutor<T> 接口: 如果需要分页,还可继承 public ...
- Spring data Jpa 分页从1开始,查询方法兼容 Mybatis,分页参数兼容Jqgrid
废话少说 有参数可以设置 在org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties 中 /** * Whethe ...
- 【spring data jpa】带有条件的查询后分页和不带条件查询后分页实现
一.不带有动态条件的查询 分页的实现 实例代码: controller:返回的是Page<>对象 @Controller @RequestMapping(value = "/eg ...
- spring data jpa之Auditing 表的创建时间,更新时间自动生成策略
java实际编程中,几乎每一张表都会有createTime和updateTime字段,spring的优秀之处在于只要用几个注解,就帮我们解决该类问题,具体实现: 1,实体类添加注解: @EntityL ...
随机推荐
- 自主搭建CNN训练时遇到的问题
1.训练太慢 用nimibatch代替fullbatch https://www.cnblogs.com/guoyaohua/p/8724433.html 2.过拟合 最直接的解决过拟合问题的办法是增 ...
- sql 多表查询结果验证
1.笛卡尔积 定义: 设A,B为集合,用A中元素为第一元素,B中元素为第二元素构成的有序对,所有这样的有序对组成的集合 ,叫做A与B的笛卡尔积,记作AxB. 上面有一个很关键的词为“有序”,因此,我们 ...
- AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service
一般情况下我们会将项目所用到的controller/directive/filter/sercive预先加载完再初始化AngularJS模块,但是当项目比较复杂的情况下,应该是打开对应的界面才加载对应 ...
- linux学习笔记-6.权限
1.创建a.txt和b.txt文件,将他们设为其拥有者和所在组可写入,但其他以外的人则不可写入 chmod ug+w,o-w a.txt b.txt 2.创建c.txt文件所有人都可以写和执行 chm ...
- Mac 下的 .app文件如何生成.dmg ?
安装 Node.js最新版. 安装方法不赘述. 安装 create-dmg: sudo npm install --global create-dmg 注意这里 sudo不能少. 终端切换到 .app ...
- Spring(完成毕业设计后的简单回顾)
最近刚刚做完了毕业设计,在开发时用的是spring框架,做的时候踩了好多坑,又把当初的笔记给翻了翻,做一次简单的回顾 # 1.Spring是什么? 是一个开源的.用于简化企业级应用开发的应用开发框架. ...
- nginx+uwsgi+flask 服务器配置
注:每个机器,软件版本可能不一样,虽然网上有很多类似的帖子,但是我在搭建的时候遇到了不少的坑,此文仅供参考. 请求流程: 1.安装uwsgi uwsgi是一个应用服务器,非静态文件的网络请求就必须通过 ...
- Windows 10官方原版ISO制作方法
其实市面上的ISO原版都是这样的方法制作成光盘,然后再打包出来供人们下载的. 1.下载Windows 10安装程序工具: https://www.microsoft.com/zh-cn/softwar ...
- HDU 4821 String(2013长春现场赛I题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4821 字符串题. 现场使用字符串HASH乱搞的. 枚举开头! #include <stdio.h ...
- 在eclipse中查看Android源码
声明:高手跳过此文章 当我们在eclipse中开发android程序的时候.往往须要看源码(可能是出于好奇,可能是读源码习惯),那么怎样查看Android源码呢? 比方以下这样的情况 图1 如果我们想 ...