有时候用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进行关联查询并返回到一个接口类上面去,我还是用了这个方法作为前奏。具体可以看之前的文章,用一个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.AbstractJpaQuery T u p l e C o n v e r t e r TupleConverter TupleConverterTupleBackedMap的东西。这一开始是让我很绝望的。
好了, 接下来,核心的地方来了。
这个是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"
}
]
}
经过后来的摸索,其实如果只是为了返回JSON,也可以直接在Repository层直接用
List
来返回,并不需要这么折腾,这里纯属瞎折腾,但是思路确实有那么一点点借鉴的意义吧。