★【Core Moshow 郑锴】★

POWERED BY MOSHOW .... CORE iWN , WE ARE LOADING THE DREAM!

SprigData-JPA之Query进行复杂查询并映射到自定对象

场景介绍

有时候用JPA的时候,想拥有mybatis如此轻松的映射,将一堆复杂场景的sql语句映射到一个java类来返回。而JPA本身是很坑的,Query之支持简单查询,复杂查询需要去构造Specification来进行复杂查询。但是=。=
我就不!!!我就要用Query进行复杂查询。来吧,ShowTime。

首先,介绍一下场景,就是有这么一个接口,参数是传入窗口号和状态,查询排队的队列。主表是一个叫做check_queue的表,需要关联wicket窗口表,facility设备表,check_register检查用户信息表。通过一个复杂的sql来查询出要的数据并展示出来,表结构就不贴出来,但是通过sql就可以体会大概的条件和场景。

数据查询预览

这里写图片描述

SELECT c.id, c.createtime, c.lastupdatetime, c.check_Wicket, c.facility_num
    , c.check_num, c.status, f.facility_name, r.name AS check_name
FROM check_queue c
    LEFT JOIN wicket w ON c.check_Wicket = w.check_Wicket
    LEFT JOIN facility f ON f.facility_num = w.facility_num
    LEFT JOIN check_register r
    ON r.check_num = c.check_num
        AND date_format(r.lastupdatetime, '%y-%m-%d') = date_format(now(), '%y-%m-%d')
WHERE c.check_Wicket = 1
    AND c.status = 0
    AND date_format(c.lastupdatetime, '%y-%m-%d') = date_format(now(), '%y-%m-%d')
ORDER BY c.lastupdatetime ASC

可以看到有个条件是**AND date_format(r.lastupdatetime, ‘%y-%m-%d’) = date_format(now(),
‘%y-%m-%d’)**,这个是mysql是查询今天的。

然后可以看到主表只有c.id, c.createtime, c.lastupdatetime, c.check_Wicket, c.facility_num, c.check_num, c.status,其他两个字段f.facility_name, r.name AS check_name是来自关联的表。

JPA常规查询并返回

之前的文章,介绍了用JPA进行关联查询并返回到一个接口类上面去,我还是用了这个方法作为前奏。具体可以看之前的文章,用一个interface来接收JPA返回的结果。
https://blog.csdn.net/moshowgame/article/details/80058270

 public interface QueueList {
     String getCheckName();
     String getFacilityName();
     int getId();
     String getCheckNum();
     String getCheckWicket();
     Timestamp getCreatetime();
     String getFacilityNum();
     Timestamp getLastupdatetime();
     String getStatus();
}

那么如果直接用JPA的Query查询,返回的数据是

{
    "errorCode": "00",
    "errorMessage": "操作成功",
    "returnObject": [
        {
            "createtime": 1526358195000,
            "id": 49,
            "lastupdatetime": 1526358195000,
            "status": "2",
            "target": {
                "createtime": 1526358195000,
                "lastupdatetime": 1526358195000,
                "check_Wicket": "1",
                "facility_name": "血压测量",
                "facility_Num": "C3",
                "id": 49,
                "status": "2",
                "check_name": "小汤154",
                "check_Num": "BY185201805140001"
            },
            "targetClass": "org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap"
        }
    ]
}

显示targetClass是个org.springframework.data.jpa.repository.query.AbstractJpaQueryTupleConverterTupleBackedMap的东西。这一开始是让我很绝望的。

封装处理

好了, 接下来,核心的地方来了。
这个是JPA映射的entity类,那两个关联的facilityName和checkName,非数据库的字段要加@Transient注解

@Entity
@Table(name="check_queue")
@NamedQuery(name="CheckQueue.findAll", query="SELECT c FROM CheckQueue c")
public class CheckQueue implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private int id;

    private String checkNum;

    private String checkWicket;

    private Timestamp createtime;

    private String facilityNum;

    private Timestamp lastupdatetime;

    private String status;
    @Transient   
    private String facilityName;
    @Transient   
    private String checkName;
}

这里要吐槽,JPA最傻的地方,就是不给你映射到这个类上面去,这才导致下文的曲线救国。如果可以,早就迎刃而解了。

那我们在Controller里面这么处理一下:

    /**
     * 排队队列
     */
    @GetMapping("/queue/{checkWicket}/{status}")
    public ApiReturnObject findQueue(@PathVariable String checkWicket,@PathVariable String status) {
        if (StringUtils.isBlank(checkWicket)|| StringUtils.isBlank(status)) {
            return ApiReturnUtil.error("操作失败,窗口号不能为空");
        }else {//####请注意,前方核心封装,请勿错过###
            //获取队列,映射到interface查询类上 
            List<QueueList> findQueue = lineQueueRepository.queryQueueList(checkWicket, status);
            //回迁到新的主数据list上
            List<CheckQueue> dataQueue = new ArrayList<CheckQueue>();
            for (QueueList item:findQueue) {
                //先把interface类的内容格式化为string,就是一些属性,然后target里面才是主数据
                String jsonStr=JSON.toJSONString(item);
                //格式化string为JSONObject,方便获取target属性
                JSONObject obj=JSON.parseObject(jsonStr);
                //从将QueueList的target的数据真正格式化到主数据类CheckQueue
                CheckQueue data=JSON.toJavaObject(JSON.parseObject(obj.getString("target")), CheckQueue.class);
                //添加到list
                dataQueue.add(data);
                data=null;
            }
            //用这个可以返回一个TupleBackedMap类型的我们写的interface
            //return ApiReturnUtil.success("操作成功",findQueue);
            //用这个可以返回我们封装的数据,请看下面封装后的效果
            return ApiReturnUtil.success("操作成功",dataQueue);
        }       
    }

下面请看本次封装后的结果。噔噔噔噔。

{
    "errorCode": "00",
    "errorMessage": "操作成功",
    "returnObject": [
        {
            "checkName": "小汤154",
            "checkNum": "BY185201805140001",
            "checkWicket": "1",
            "createtime": 1526358195000,
            "facilityName": "血压测量",
            "facilityNum": "C3",
            "id": 49,
            "lastupdatetime": 1526358195000,
            "status": "2"
        }
    ]
}
阅读更多
文章标签: spring data jpa
个人分类: Spring
所属专栏: SpringBoot2
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

SprigData-JPA之Query进行复杂查询并映射到自定对象

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭