1、确定两个表之间的关系
1.1、r_menu 菜单表
关系:菜单表和报表是一对多关系
1.2、r_report 报表
关系:报表和菜单表是多对一关系
2、配置出实体类和数据库表的关系映射
2.1、菜单表对象实体:
package com.tc.report.dataobject;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name="r_menu")
public class Menu {
@Id
private String menuId;
private String menuName;
private String menuIcon;
/* 没有权限的菜单图标 */
private String menuNicon;
private Integer status;
private String menuPath;
}
2.2、报表对象实体:
package com.tc.report.dataobject;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.Data;
import lombok.ToString;
import com.fasterxml.jackson.annotation.JsonFormat;
@Data
@ToString
@Entity
@Table(name="r_report")
public class Report {
@Id
private String reportId;
private String reportName;
private String reportPath;
private String reportFileName;
/* 菜单id外键 */
private String menuId;
/* 0:表示启用,1:表示禁用 */
private Integer status;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date createTime;
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Date updateTime;
/**
* 多对一关系
* targetEntityClass:指定一的一方实体类字节码。
* cascade:指定要使用的级联操作 。
* fetch:指定是否采用延迟加载 。
* optional:关联是否可选。如果设置为false,则必须始终存在非空关系。
*/
@ManyToOne(targetEntity=Menu.class)
/**
* name:指定外键字段的名称。( 多的一方从表Report的menuId )
* referencedColumnName:指定引用主表的主键字段名称。( 少的一方主表menu的menuId )
* unique:是否唯一。默认值不唯一 。
* nullable:是否允许为空。默认值允许。
* insertable:是否允许插入。默认值允许。
* updatable:是否允许更新。默认值允许。
* columnDefinition:列的定义信息。
*/
@JoinColumn(name="menuId",referencedColumnName="menuId",insertable=false,updatable=false)
private Menu menu;
}
2.3、Specification条件分页关联查询:
2.3.1、vo层:
@Data
public class ReportVo extends Report{
private Integer page = 1;
private Integer limit = 10;
private String menuName;
}
2.3.2、dao层:
public interface ReportRepository extends JpaRepository<Report, String>,JpaSpecificationExecutor<Report>{
}
2.3.3、service层:
public PageResult loadAllReports(ReportVo reportVo) {
// 分页设置
Sort sort = new Sort(Sort.Direction.DESC, "updateTime");
PageRequest pageRequest = PageRequest.of(reportVo.getPage()-1, reportVo.getLimit(),sort);
// 构建动态查询
Specification<Report> specification = createSpecification(reportVo);
Page<Report> page = reportRepository.findAll(specification, pageRequest);
return new PageResult(page.getTotalElements(), page.getContent());
}
/**
* 动态条件构建 sql查询
*
* @param ReportVo
* @return
*/
@SuppressWarnings("serial")
private Specification<Report> createSpecification(ReportVo reportVo) {
return new Specification<Report>() {
@Override
public Predicate toPredicate(Root<Report> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicateList = new ArrayList<Predicate>();
// ID
if (reportVo.getReportId()!=null && !"".equals(reportVo.getReportId())) {
predicateList.add(cb.like(root.get("reportId").as(String.class), "%"+(String)reportVo.getReportId()+"%"));
}
// 报表名称
if (reportVo.getReportName()!=null && !"".equals(reportVo.getReportName())) {
predicateList.add(cb.like(root.get("reportName").as(String.class), "%"+(String)reportVo.getReportName()+"%"));
}
// 菜单id
if (reportVo.getMenuId()!=null && !"".equals(reportVo.getMenuId())) {
predicateList.add(cb.like(root.get("menuId").as(String.class), "%"+(String)reportVo.getMenuId()+"%"));
}
// 状态
if (reportVo.getStatus()!=null && !"".equals(reportVo.getStatus())) {
predicateList.add(cb.like(root.get("status").as(String.class), "%"+reportVo.getStatus()+"%"));
}
//Join代表链接查询,通过root对象获取。创建的过程中,第一个参数为关联对象的属性名称,第二个参数为连接查询的方式(left,inner,right)
//JoinType.LEFT:左外连接;JoinType.INNER:内连接;JoinType.RIGHT:右外连接
Join<Report, Menu> join = root.join("menu",JoinType.INNER);
if (reportVo.getMenuName()!=null && !"".equals(reportVo.getMenuName())) {
predicateList.add(cb.like(join.get("menuName").as(String.class), "%"+reportVo.getMenuName()+"%"));
}
return cb.and( predicateList.toArray(new Predicate[predicateList.size()]));
}
};
}
3、测试:
package com.tc.report.service;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.tc.report.TcReportApplicationTests;
import com.tc.report.VO.PageResult;
import com.tc.report.VO.ReportVo;
import com.tc.report.dataobject.Report;
public class ReportServiceTest extends TcReportApplicationTests{
@Autowired
private ReportService reportService;
@Test
public void testLoadAllReports(){
ReportVo reportVo = new ReportVo();
reportVo.setMenuName("销售");
PageResult result = reportService.loadAllReports(reportVo);
List<Report> reports = (List<Report>) result.getData();
for (Report report: reports){
System.out.println(report);
}
}
}
以上,个人整理。如有错漏之处,欢迎大家指正。谢谢!
spring-data-jpa原sql语句多表关联查询+分页+自定义数据返回封装请参考我的另一篇文章:
https://blog.csdn.net/yandype/article/details/95318828