详解Spring Data JPA系列之投影(Projection)的用法

本文介绍了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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
【2021年,将Spring全家桶系列课程进行Review,修复顺序等错误。进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并新增高级的Spring Security等内容,通过手把手一步步教你从零开始学会应用Spring,课件将逐步进行上传,敬请期待】 本课程是Spring案例精讲课程的第五部分Spring DataSpring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作中更进一步。 本课程聚焦Spring Data的核心知识点:Spring Data Repository、Spring Data JPA(增删改查案例、实体自动生成数据库表、增加新的Repository方法、分页、排序、@NamedQuery、@Query及其分页和排序及参数设置、@NamedEntityGragh实现多对多映射、及QueryHints等)、Spring Data JDBC(增删改查案例、@Query等)的案例介绍, 快速掌握Spring Data的核心知识,快速上手,为学习及工作做好充足的准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。 【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring Boot、Spring Cloud及Spring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验  【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作中。 【Spring全家桶课程共包含如下几门】5. 进阶篇:SpringData 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值