本文介绍了Spring Data JPA系列之投影(Projection)的用法,分享给大家
在JPA的查询中,有一个不方便的地方,@Query注解,如果查询直接是
,这时候,查询的返回对象就是Customer这个完整的对象,包含所有字段,对于我们的示例并没有什么问题,但是对于比较庞大的domain类,这个查询时就比较要命,并不是所有的字段都能用到,比较头疼。另外,如果定义
这个查询结果,返回的对象是Object类型,而且无法直接转换成Customer对象,这样用起来就不是很方便。
对于这种情况,JPA提供了一种声明方式来解决,即声明一个接口类,然后直接使用这个接口类接受返回的数据即可。下面奉上代码:
如下代码 -> apply代码/**
* @author: 蔡长盟
* @email: modules@163.com
* @date: 201818-9-13
* @module: 共享空间
* @describe: 组申请详情是体类
* @version: v1.0
*/
package springdata.jpa.jpademo.test.bean;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
@Table(name = "share_group_apply_info")
@Entity
public class Apply implements Serializable {
/**
* @title: 申请记录id
* @remark:
* @date: 18-9-13
*/
@Id
@GeneratedValue(generator="system_uuid")
@GenericGenerator(name="system_uuid",strategy="uuid")
@Column(name = "apply_id")
private String applyId;
/**
* @title: email
* @remark:
* @date: 18-9-15
*/
private String email;
/**
* @title: 副标题
* @remark:
* @date: 18-9-19
*/
@Column(name = "sub_title")
private String subTitle;
/**
* @title: 活动编码
* @remark:
* @date: 18-9-13
*/
@Column(name = "apply_code")
private String applyCode;
/**
* @title: 活动主题
* @remark:
* @date: 18-9-13
*/
// @NotBlank(message = "团建主题不得为空")
private String title;
/**
* @title: 活动描述
* @remark:
* @date: 18-9-13
*/
// @NotBlank(message = "团建描述不得为空")
private String description;
/**
* @title: 活动人数
* @remark:
* @date: 18-9-13
*/
// @Min(value = 1,message = "活动参与人数不得低于1人")
@Column(name = "member_total")
private Integer memberTotal;
/**
* @title: 开始时间
* @remark:
* @date: 18-9-13
*/
// @NotBlank(message = "活动开始时间不得为空")
@Pattern(regexp = "^(((20[0-3][0-9]-(0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|(20[0-3][0-9]-(0[2469]|11)-(0[1-9]|[12][0-9]|30))) (20|21|22|23|[0-1][0-9]):[0-5][0-9]:[0-5][0-9])$",
message = "请输入正确的开始日期")
@Column(name = "start_time")
private String startTime;
/**
* @title: 结束时间
* @remark:
* @date: 18-9-13
*/
// @NotBlank(message = "活动结束时间不得为空")
@Pattern(regexp = "^(((20[0-3][0-9]-(0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|(20[0-3][0-9]-(0[2469]|11)-(0[1-9]|[12][0-9]|30))) (20|21|22|23|[0-1][0-9]):[0-5][0-9]:[0-5][0-9])$",
message = "请输入正确的结束日期")
@Column(name = "end_time")
private String endTime;
/**
* @title: 创建人openid
* @remark:
* @date: 18-9-13
*/
@Column(name = "owner_id")
private String ownerId;
/**
* @title: 场地id
* @remark:
* @date: 18-9-13
*/
// @NotBlank(message = "请选择所需共享场地")
@Column(name = "space_id")
private String spaceId;
/**
* @title: 组状态
* @remark: 团队状态 0: 未开始; 1: 进行中; 2:已结束
* @date: 18-9-13F
*/
@Column(name = "group_status")
private Integer groupStatus = 0;
/**
* @title: 审批结果
* @remark: 0:未审批; 1:审批通过; 2:审批未通过 3:审批中 4: 用户未关注,创建未成功.
* @date: 18-9-13
*/
@Column(name = "ratify_result")
private Integer ratifyResult =0;
/**
* @title: 团长名称
* @remark:
* @date: 18-9-13F
*/
// @NotBlank(message = "用户名称不得为空")
@Column(name = "owner_name")
private String ownerName;
/**
* @title: 团长电话
* @remark:
* @date: 18-9-13
*/
// @NotBlank(message = "用户电话不得为空")
@Pattern(regexp = "^[1][3|4|5|7|8][0-9]{9}$",
message = "请输入正确的电话")
@Column(name = "owner_phone")
private String ownerPhone;
@OneToOne()
@JoinColumn(name = "space_id",insertable = false,updatable = false , referencedColumnName = "space_id")
private Space space;
public Space getSpace() {
return space;
}
public void setSpace(Space space) {
this.space = space;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public String getOwnerPhone() {
return ownerPhone;
}
public void setOwnerPhone(String ownerPhone) {
this.ownerPhone = ownerPhone;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getApplyCode() {
return applyCode;
}
public void setApplyCode(String applyCode) {
this.applyCode = applyCode;
}
public Integer getMemberTotal() {
return memberTotal;
}
public void setMemberTotal(Integer memberTotal) {
this.memberTotal = memberTotal;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public String getOwnerId() {
return ownerId;
}
public void setOwnerId(String ownerId) {
this.ownerId = ownerId;
}
public Integer getGroupStatus() {
return groupStatus;
}
public void setGroupStatus(Integer groupStatus) {
this.groupStatus = groupStatus;
}
public Integer getRatifyResult() {
return ratifyResult;
}
public void setRatifyResult(Integer ratifyResult) {
this.ratifyResult = ratifyResult;
}
public String getApplyId() {
return applyId;
}
public void setApplyId(String applyId) {
this.applyId = applyId;
}
public String getSpaceId() {
return spaceId;
}
public void setSpaceId(String spaceId) {
this.spaceId = spaceId;
}
public String getSubTitle() {
return subTitle;
}
public void setSubTitle(String subTitle) {
this.subTitle = subTitle;
}
@Override
public String toString() {
return "ShareGroupApplyInfoEntity{" +
"applyId=" + applyId +
", code='" + applyCode + '\'' +
", title='" + title + '\'' +
", describe='" + description + '\'' +
", memberTotal=" + memberTotal +
", startDate=" + startTime +
", endDate=" + endTime +
", openId='" + ownerId + '\'' +
", spaceId=" + spaceId +
", groupStatus=" + groupStatus +
'}';
}
}
1、增加applyProjection接口类
package springdata.jpa.jpademo.test.projections;
/**
* @author: 蔡长盟
* @email: modules@163.com
* @date: 20182018/9/28
* @module: 类所属模块
* @describe:
* @version: v1.0
*/
public interface ApplyPro {
public String getEmail();
public String getOwnerName();
public String getOwnerPhone();
public String getTitle();
public String getDescription();
public String getApplyCode();
public Integer getMemberTotal();
public String getStartTime();
public String getEndTime();
public String getOwnerId();
public Integer getGroupStatus();
public Integer getRatifyResult();
public String getApplyId();
public String getSpaceId();
public String getSubTitle();
}
这里声明的方式是可以直接通过get+属性名,这是普通的,另外也可以通过@Value注解来实现指定字段,除了指定字段也可以做聚合展示,比如有些地方需要展示客户的全名,这里定义的getFullName()方法及注解@Value即完成这一操作。需要注意这里的@Value中的target表达式写法及拼接方法。
2、增加applyRepository方法
package springdata.jpa.jpademo.test.repository;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import springdata.jpa.jpademo.test.bean.Apply;
import springdata.jpa.jpademo.test.projections.ApplyPro;
import java.util.List;
/**
* @author: 蔡长盟
* @email: modules@163.com
* @date: 2018/9/27
* @module: 类所属模块
* @describe:
* @version: v1.0
*/
public interface ApplyRepository extends JpaRepository<Apply,String>, JpaSpecificationExecutor<Apply> {
@Query(value = "SELECT\n" +
"\tapply.apply_id AS applyId,\n" +
"\tapply.apply_code AS applyCode,\n" +
"\tapply.title\n" +
"FROM\n" +
"\tshare_group_apply_info AS apply",nativeQuery = true)
List<ApplyPro> findhaha();
}
3、增加CustomerController方法
package springdata.jpa.jpademo.test.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springdata.jpa.jpademo.test.projections.ApplyPro;
import springdata.jpa.jpademo.test.repository.ApplyRepository;
import java.util.List;
/**
* @author: 蔡长盟
* @email: modules@163.com
* @date: 20182018/9/28
* @module: 类所属模块
* @describe:
* @version: v1.0
*/
@RestController
@RequestMapping("pro")
public class ProjectionController {
@Autowired
private ApplyRepository applyRepository;
@GetMapping("1")
public List<ApplyPro> find() {
return applyRepository.findhaha();
}
}
返回值:
[
{
"description": null,
"endTime": null,
"startTime": null,
"spaceId": null,
"groupStatus": null,
"ownerPhone": null,
"title": "title",
"ratifyResult": null,
"ownerName": null,
"subTitle": null,
"applyCode": "2",
"applyId": "4028648166199b4a0166199befc90002",
"email": null,
"memberTotal": null,
"ownerId": null
},
{
"description": null,
"endTime": null,
"startTime": null,
"spaceId": null,
"groupStatus": null,
"ownerPhone": null,
"title": "title",
"ratifyResult": null,
"ownerName": null,
"subTitle": null,
"applyCode": "3",
"applyId": "4028648166199b4a066199befc90002",
"email": null,
"memberTotal": null,
"ownerId": null
},
{
"description": null,
"endTime": null,
"startTime": null,
"spaceId": null,
"groupStatus": null,
"ownerPhone": null,
"title": "title",
"ratifyResult": null,
"ownerName": null,
"subTitle": null,
"applyCode": "1",
"applyId": "4028648166194a066199befc90002",
"email": null,
"memberTotal": null,
"ownerId": null
}
]
查询关联的子对象.
以上图中的apply为例.
下为applyPro1
package springdata.jpa.jpademo.test.projections;
/**
* @author: 蔡长盟
* @email: modules@163.com
* @date: 20182018/9/28
* @module: 类所属模块
* @describe:
* @version: v1.0
*/
public interface ApplyPro1 {
String getTitle();
Space getSpace();
interface Space {
String getTitle();
}
}
下为 ApplyRepository代码
package springdata.jpa.jpademo.test.repository;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import springdata.jpa.jpademo.test.bean.Apply;
import springdata.jpa.jpademo.test.projections.ApplyPro;
import springdata.jpa.jpademo.test.projections.ApplyPro1;
import java.util.List;
/**
* @author: 蔡长盟
* @email: modules@163.com
* @date: 20182018/9/27
* @module: 类所属模块
* @describe:
* @version: v1.0
*/
public interface ApplyRepository extends JpaRepository<Apply,String>, JpaSpecificationExecutor<Apply> {
List<ApplyPro1> findBySubTitle(String title);
}
重点, pro中的space的pro名字要与该space类的类名一致(类名可以扩展该类的属性, 有兴趣可以测试)
返回值
[
{
"space": {
"title": "space1"
},
"title": "title"
},
{
"space": {
"title": "space3"
},
"title": "title"
},
{
"space": {
"title": "space2"
},
"title": "title"
}
]
这里只是做了简单示意,深入的内容需要自己去挖掘探索。不过关于Projection的资料比较少,我也是扒了不少资料才理解的差不多了,还需要多多实践。
另外spring-data-examples项目中有一些JPA的例子,可以用来学习,梳理思路。https://github.com/spring-projects/spring-data-examples/tree/master/jpa
参考:
官方文档,http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
DEMO,https://github.com/icnws/spring-data-jpa-demo
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。