SpringBoot+SpringDataJPA如何实现自定义查询[多表,多条件,分页,自定义sql封装]
举个例子:我们要在已经搭建好了的JPA环境下实现联合多表,多条件,多排序条件,分页查询一个表格数据,下面的表格

返回类MyJSON:
public class MyJSON {
private String code;
private String msg;
private Object data;
private Object extraData;
private Integer total;
public MyJSON(){
super();
}
public MyJSON(String code,String msg){
this.code=code;
this.msg=msg;
}
public MyJSON(String code, Object data) {
this.code = code;
this.data = data;
}
public MyJSON(String code, Object data, Integer total) {
this.code = code;
this.data = data;
this.total = total;
}
public MyJSON(String code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public MyJSON(String code) {
this.code = code;
}
public MyJSON(String code, String msg, Object data, Integer total) {
this.code = code;
this.msg = msg;
this.data = data;
this.total = total;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
public Object getExtraData() {
return extraData;
}
public void setExtraData(Object extraData) {
this.extraData = extraData;
}
}
Code类:
public class Code {
public static final String SUCCESS="200";//查询结果成功
public static final String ERROR="201";//出错
public static final String SERVER_ERROR="202";//服务出错
public static final String SESSION_TIMEOUT="203";//session过期
}
MOrderModel:实体类
//lombok自行百度,其中的@Data大概作用就是省去get、set方法
import lombok.Data; @Data
public class MOrderModel {
private int orderId;//订单id
private Integer cusId;//顾客id
private String nickName;//顾客昵称
private String createTime;//下单时间
public MOrderModel() {
}
public MOrderModel(int orderId, Integer cusId, String nickName,String createTime) {
this.orderId = orderId;
this.cusId = cusId;
this.nickName = nickName;
this.createTime = createTime;
}
}
DataUtil:作用就是对从前端传过来需要排序的键值对的封装,返回字符串 “ order by AA desc,BB desc,CC asc ”,自己写order by也可以,接收map如:<"AA","desc">、<"BB","desc">、<"CC","asc">
import java.util.Map;
public class DataUtil {
public static String orderby(Map<String,String> sortOrderMap){
String queryOrder="";
if(sortOrderMap.size()!=0){
queryOrder+=" order by ";
}
for(Map.Entry<String, String> entry : sortOrderMap.entrySet()) {
queryOrder+=" "+entry.getKey()+" "+entry.getValue()+", ";
}
if(sortOrderMap.size()!=0){
queryOrder.substring(0,queryOrder.lastIndexOf(","));
}
return queryOrder;
}
}
Controller:
@PostMapping("findOrderList")
@ResponseBody
public MyJSON findOrderList(MOrderModel order, Integer pageIndex, Integer pageSize, String sortField, String sortOrder){
Map<String,String> sortMap=new HashMap<>();
if(StringUtils.isNotEmpty(sortField) && StringUtils.isNotEmpty(sortOrder)){
sortMap.put(sortField,sortOrder);
}
Page<MOrderModel> commodityPage=orderService.findDataList(order,pageIndex,pageSize,sortMap);
if(commodityPage!=null){
List<MOrderModel> list=commodityPage.getContent();
Object orderModel=list.get(0);
return new MyJSON(Code.SUCCESS,list,Integer.parseInt(commodityPage.getTotalElements()+""));
}else{
return new MyJSON(Code.ERROR);
}
}
ServiceImpl:
参数:
order:需要传过来的多条件查询
pageIndex:0开始的页码
pageSize:每页的条数
sortOrderMap是前端传过来的需要排序的表格列名及排序方向的键值对(多组合排序)
@Autowired
private MOrderRepository orderRepository;
public Page<MOrderModel> findDataList(MOrderModel order, Integer pageIndex, Integer pageSize,Map<String,String> sortOrderMap) {
Pageable pageable=PageRequest.of(pageIndex,pageSize);
StringBuffer querySql=new StringBuffer();
querySql.append("select * from order o " +
"where o.id=:id");//
querySql.append(DataUtil.orderby(sortOrderMap));//这里直接用封装好的order by
StringBuffer countSql=new StringBuffer();
countSql.append("select count(*) " +
"from order o " +
"where o.id=:id");
Map<String,Object> params=new HashMap<>();//封装参数
params.put("id",order.getId());
try {
Page<MOrderModel> page = orderRepository.findDataList(querySql.toString(), countSql.toString(), params, entityManager, pageable, MOrderModel.class);
return page;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
MOrderRepository: 只需要继承一下自定义的BaseRepository就可以了,主要代码在BaseRepository中
import com.mercury.admin.entity.MOrder;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface MOrderRepository<T> extends JpaSpecificationExecutor<MOrder>, JpaRepository<MOrder,Integer>,BaseRepository { }
BaseRepository :
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository; import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Repository
public interface BaseRepository { default <T> Page<T> findDataList(String querySql, String countSql, Map<String,Object> params, EntityManager entityManager, Pageable pageable,Class<T> clazz) throws IllegalAccessException, InstantiationException {
Query listQuery=entityManager.createNativeQuery(querySql);
listQuery.setFirstResult((int) pageable.getOffset());
listQuery.setMaxResults(pageable.getPageSize());
listQuery.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);//自动映射成map[稍微影响一点查询效率,但是封装后比较方便查看对应的字段,不需要再使用Object[] obj,obj[0],obj[1]...的方式]
for (Map.Entry<String, Object> entry : params.entrySet()) {//加入参数
listQuery.setParameter(entry.getKey(), entry.getValue());
}
Query countQuery=entityManager.createNativeQuery(countSql);
for (Map.Entry<String, Object> entry : params.entrySet()) {
countQuery.setParameter(entry.getKey(), entry.getValue());
}
List<Map<String,Object>> list= listQuery.getResultList();//由于上面已经将结果映射成了map所以这里直接转化成Map没问题
List<T> resultList=new ArrayList<>();
for(Map<String,Object> map:list){//遍历map将map转化为实体类bean
T bean=clazz.newInstance();//实例化T,可能会抛出两个异常IllegalAccessException、InstantiationException
for(Map.Entry<String,Object> entry:map.entrySet()){//格式化Timestamp为String类型,数据库中日期类型为Timestamp,在这里需要转化一下,直接在前端使用
if(entry.getValue() instanceof Timestamp){
try {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date=sdf.parse(entry.getValue()+"");
String dateStr = sdf.format(date);
map.put(entry.getKey(),dateStr);
} catch (ParseException e) {
e.printStackTrace();
} }
}
BeanMap.create(bean).putAll(map); resultList.add(bean);
}
BigInteger count=(BigInteger) countQuery.getSingleResult();
return new PageImpl<>(resultList, pageable, count.longValue());
}
}
SpringBoot+SpringDataJPA如何实现自定义查询[多表,多条件,分页,自定义sql封装]的更多相关文章
- sqlserver查询所有表的行数的sql语句
原文:sqlserver查询所有表的行数的sql语句 select object_name(id),rowcnt from sysindexes where indid<2 and object ...
- 从数据库中查询所有表及所有字段的SQL语句
从数据库中查询所有表及所有字段的SQL语句 由于一个小项目的需要,近日完成一个从数据库中查询所有表及所有字段的方法,其实用两条SQL语句就可以完成. Sql Server版:列出当前DB中所有表:se ...
- Sharding-Jdbc 自定义分库分表-复合分片算法自定义实现
Sharding-JDBC中的分片策略有两个维度,分别是: 数据源分片策略(DatabaseShardingStrategy) 表分片策略(TableShardingStrategy) 其中,数据源分 ...
- 几种常见数据库查询判断表和字段是否存在sql
1.MSSQL Server 表:select COUNT(*) from dbo.sysobjectsWHEREname= 'table_name': 字段:select COUNT(*) ...
- C# MongoDB 查询,分组,聚合,排序,条件,分页
先下载个C#的驱动.MongoDB提供各种主流与非主流预言的开发驱动. C# Driver 下载地址:这里 CSharp Driver Tutorial:这里 下载文件安装或者解压缩包 如果您是安装, ...
- 自定义MVC框架之工具类-分页类的封装
以前写过一个MVC框架,封装的有点low,经过一段时间的沉淀,打算重新改造下,之前这篇文章封装过一个验证码类. 这次重新改造MVC有几个很大的收获 >全部代码都是用Ubuntu+Vim编写,以前 ...
- MySQL查询数据表中数据记录(包括多表查询)
MySQL查询数据表中数据记录(包括多表查询) 在MySQL中创建数据库的目的是为了使用其中的数据. 使用select查询语句可以从数据库中把数据查询出来. select语句的语法格式如下: sele ...
- 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效
数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...
- sql中对查询出来的数据进行分页
当sql中存储的数据量比较大时,在web中 数据显示时都会对数据进行分页,分页不会在客户端进行分页,而是在数据库查询过程中进行了分页. sql代码: DECLARE @pageindex INT; - ...
随机推荐
- NW.js打包一个桌面应用
1.安装nw(可以到官网:https://nwjs.io下载) npm install nw -g 2.创建一个最最简单的nw应用 在nwjs文件夹中 新建index.html和package.jso ...
- Linux下编写-makefile-详细教程(跟我一起写-Makefile-Markdown整理版)
目录 概述 关于程序的编译和链接 Makefile 介绍 Makefile的规则 一个演示例子 make是怎样工作的 makefile中使用变量 让make自己主动推导 另类风格的makefile 清 ...
- 022.掌握Pod-Pod升级和回滚
一 deploymentPod升级和回滚 1.1 deployment升级 若Pod是通过Deployment创建的,可以在运行时修改Deployment的Pod定义(spec.template)或镜 ...
- 如何在后台封装el-tree所需要的数据格式
背景 最近遇到了一个分层级展示指标的需求,前端使用el-tree树形组件,要求按官方文档的格式提供数据. 数据格式: id: 1, label: '一级 1', children: id: 4, la ...
- href=”javascript:void(0);
href=”javascript:void(0);”这个的含义是,让超链接去执行一个js函数,而不是去跳转到一个地址,而void(0)表示一个空的方法,也就是不执行js函数. 为什么要使用href=” ...
- JSON——IT技术人员都必须要了解的一种数据交换格式
JSON作为目前Web主流的数据交换格式,是每个IT技术人员都必须要了解的一种数据交换格式.尤其是在Ajax和REST技术的大行其道的当今,JSON无疑成为了数据交换格式的首选! 今天大家就和猪哥一起 ...
- Spring Boot 2.X(十八):集成 Spring Security-登录认证和权限控制
前言 在企业项目开发中,对系统的安全和权限控制往往是必需的,常见的安全框架有 Spring Security.Apache Shiro 等.本文主要简单介绍一下 Spring Security,再通过 ...
- PHP中接口与抽象类的异同点有哪些
接口与抽象类的相同点: 1.抽象类和接口都有抽象方法 2.抽象类和接口不能创建实例对象 3.抽象类和接口使用意义相同(定义一种规范) 接口与抽象类的不同点: 1.接口中的方法必须全要是抽象方法(不能用 ...
- 像黑客一样写博客–Pelican快速搭建静态博客
"像黑客一样写博客",通过文本编辑器(Markdown编辑器)即可实现写博客,而且是静态的,很神奇吧,这里的方案是Pelican. 为啥叫 Pelican 这么奇怪的名字 &quo ...
- python中return和print的区别
之前遇到这个问题,就试着对比几种不同的结果,总结啦一下return和print的区别. 总结: return的作用之一是返回计算的值print的作用是输出数据到控制端 在第一个结果中什么都没有输出:在 ...