SprigData-JPA之Query进行复杂查询并映射到自定对象(非数据库字段用@Transient注解)

场景介绍

有时候用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.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<Map<String,Object>>来返回,并不需要这么折腾,这里纯属瞎折腾,但是思路确实有那么一点点借鉴的意义吧。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值