springDataJpa入門教程(3-2)-基於EntityManager原生sql多表聯合查詢+動態條件查詢+分頁返回自定義實體類對象

springDataJpa入門教程

springDataJpa入門教程(3-2)-基於EntityManager原生sql多表聯合查詢+動態條件查詢+分頁返回自定義實體類對象

在上一節,講到了基於EntityManager原生sql多表聯合查詢+動態條件查詢+分頁,查詢的結果集是用Object數組封裝的,查詢起來不是很方便。所以這節來介紹如何將EntityManager的查詢結果封裝到自定義實體類對象中。有需要源碼的朋友,請到git上下載源碼,源碼地址:源碼下載地址。java學習交流羣:184998348,歡迎大家一起交流學習。

1.需求:根據用戶名、年齡,生日(開始時間-結束時間)、城市名稱查詢用戶分頁列表,查詢結果按照用戶創建時間排序。

實體類分別是User類、Address類,下面這兩個類的代碼:

package com.thizgroup.jpa.study.model;

import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "tb_user")
@Data//使用lombok生成getter、setter
@NoArgsConstructor//生成無參構造方法
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(name = "name",columnDefinition = "varchar(64)")
  private String name;

  @Column(name = "mobile",columnDefinition = "varchar(64)")
  private String mobile;

  @Column(name = "email",columnDefinition = "varchar(64)")
  private String email;

  @Column(name = "age",columnDefinition = "smallint(64)")
  private Integer age;

  @Column(name = "birthday",columnDefinition = "timestamp")
  private Date birthday;

  //地址
  @Column(name = "address_id",columnDefinition = "bigint(20)")
  private Long addressId;

  @Column(name = "create_date",columnDefinition = "timestamp")
  private Date createDate;

  @Column(name = "modify_date",columnDefinition = "timestamp")
  private Date modifyDate;

  @Builder(toBuilder = true)
  public User(Long id,String name, String mobile, String email, Integer age, Date birthday,
      Long addressId) {
    this.id = id;
    this.name = name;
    this.mobile = mobile;
    this.email = email;
    this.age = age;
    this.birthday = birthday;
    this.addressId = addressId;
  }
}

package com.thizgroup.jpa.study.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;

@Entity
@Table(name="tb_address")
@Data//使用lombok生成getter、setter
public class Address {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(name = "country",columnDefinition = "varchar(64)")
  private String country;

  @Column(name = "province",columnDefinition = "varchar(64)")
  private String province;

  @Column(name = "city",columnDefinition = "varchar(64)")
  private String city;

}

  1. 涉及到DTO輔助類
package com.thizgroup.jpa.study.dto;

import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo2 {

  private Long id;

  private String name;//姓名

  private int age;//年齡

  private Date birthday;//生日

  private String mobile;//電話

  private String email;//郵箱

  private String country;//國家

  private String province;//省份

  private String city;//城市

  private Date createTime;//創建時間

}

package com.thizgroup.jpa.study.dto;

import java.io.Serializable;
import java.util.List;
import lombok.Data;
import lombok.Getter;
import org.springframework.util.Assert;

@Data//使用lombok生成getter、setter
public class PageBean implements Serializable {

  @Getter
  private long totalCount;//總記錄數

  @Getter
  private int totalPages;//總頁數

  @Getter
  private int pageNumber;//第幾頁

  @Getter
  private int pageSize;//每頁條數

  public PageBean(int pageNumber, int pageSize, long totalCount) {

    pageNumber = pageNumber <0 ? 0 :pageNumber;//jpa中頁碼從0開始
    pageSize = pageSize <=0 ? 15 : pageSize;//默認取15條記錄

    //計算總頁數
    int totalPages = (int)((totalCount+pageSize-1)/pageSize);
    //計算起始頁
    if(totalPages>0){
      pageNumber = totalPages <= pageNumber ? totalPages-1 : pageNumber;
    }

    this.pageNumber = pageNumber;
    this.pageSize = pageSize;
    this.totalPages =  totalPages;
    this.totalCount = totalCount;

  }

  public PageBean(PageBean pageBean) {
    Assert.notNull(pageBean,"pagebean cannot be null");
    this.pageNumber = pageBean.getPageNumber();
    this.pageSize = pageBean.getPageSize();
    this.totalPages =  pageBean.getTotalPages();
    this.totalCount = pageBean.getTotalCount();
  }

}

package com.thizgroup.jpa.study.dto;

import java.util.List;
import lombok.Data;
import lombok.Getter;

@Data
public class PageRecord<T> extends PageBean {

  @Getter
  private List<T> data;//數據列表

  public PageRecord(int pageNumber, int pageSize, long totalCount,List<T> data) {
    super(pageNumber, pageSize, totalCount);
    this.data = data;
  }

  public PageRecord(PageBean pageBean, List<T> data){
    super(pageBean);
    this.data =data;
  }

}

直接上UserDao的代碼,

package com.thizgroup.jpa.study.dao;

import com.thizgroup.jpa.study.dto.AddressDTO;
import com.thizgroup.jpa.study.dto.PageBean;
import com.thizgroup.jpa.study.dto.PageRecord;
import com.thizgroup.jpa.study.dto.UserDTO;
import com.thizgroup.jpa.study.dto.UserInfo;
import com.thizgroup.jpa.study.dto.UserInfo2;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.hibernate.type.StandardBasicTypes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

/**
 * 用戶服務
 */
@Repository
public class UserDao {

  @Autowired
  private EntityManager entityManager;
  //使用entityManager實現多表聯合帶條件帶分頁查詢及排序
  public PageRecord<UserInfo2> findUserListByPage3(UserDTO userDTO, Pageable pageable){

    List<Object> args = new ArrayList<>();//用於封裝參數

    StringBuffer sql = new StringBuffer();
    sql.append(
        " select u.id as id,u.name as name,u.age as age,u.birthday as birthday,u.mobile as mobile,"
            + "u.email as email,a.country as country,a.province as province,a.city as city "
            + ", u.create_date as createTime"
            + " from tb_user u "
            + " left join  tb_address a on u.address_id = a.id "
            + " where 1=1 "
    );

    if(userDTO  != null){
      if(StringUtils.isNotBlank(userDTO.getName())){
        //模糊查詢
        sql.append(" and u.name like ? ");
        args.add("%"+userDTO.getName()+"%");
      }
      if(null != userDTO.getAge()){
        //精確查詢
        sql.append(" and u.age = ? ");
        args.add(userDTO.getAge());
      }
      //求生日在某個時間段範圍內的用戶
      if(null != userDTO.getStartTime()){
        //大於等於
        sql.append(" and u.birthday >= ? ");
        args.add(userDTO.getStartTime());
      }
      if(null != userDTO.getEndTime()){
        //小於等於
        sql.append(" and u.birthday <= ? ");
        args.add(userDTO.getEndTime());
      }

      if(userDTO.getAddressDTO() != null) {
        AddressDTO addressDTO = userDTO.getAddressDTO();
        //查詢某個城市的用戶
        if(StringUtils.isNotBlank(addressDTO.getCity())) {
          sql.append(" and a.city = ? ");
          args.add(addressDTO.getCity());
        }
      }

    }

    //按照創建時間倒序排序
    sql.append(" order by u.create_date desc ");

    //創建query對象
    NativeQueryImpl query = entityManager.createNativeQuery(sql.toString())
        .unwrap(NativeQueryImpl.class);

    query.setResultTransformer(Transformers.aliasToBean(UserInfo2.class));

    query.addScalar("id", StandardBasicTypes.LONG);
    query.addScalar("name",StandardBasicTypes.STRING);
    query.addScalar("age",StandardBasicTypes.INTEGER);
    query.addScalar("birthday",StandardBasicTypes.TIMESTAMP);
    query.addScalar("mobile",StandardBasicTypes.STRING);
    query.addScalar("email",StandardBasicTypes.STRING);
    query.addScalar("country",StandardBasicTypes.STRING);
    query.addScalar("province",StandardBasicTypes.STRING);
    query.addScalar("city",StandardBasicTypes.STRING);
    query.addScalar("createTime",StandardBasicTypes.TIMESTAMP);

    //設置查詢參數
    if(args.size()>0){
      for(int i=0;i<args.size();i++){
        //注意:jpa的setParameter是從1開始的
        query.setParameter(i+1,args.get(i));
      }
    }

    PageBean pageBean = findPageBean(sql.toString(), args, pageable);

    //分頁查詢
    query.setFirstResult(pageBean.getPageNumber()*pageBean.getPageSize());
    query.setMaxResults(pageBean.getPageNumber()*pageBean.getPageSize()+pageBean.getPageSize());
    List<UserInfo2> resultList = query.list();

    return new PageRecord<UserInfo2>(pageBean,resultList);
  }
}

寫個單元測試驗證一下,

package com.thizgroup.jpa.study.dao;

import com.thizgroup.jpa.study.JpaApplication;
import com.thizgroup.jpa.study.dto.PageRecord;
import com.thizgroup.jpa.study.dto.UserInfo;
import com.thizgroup.jpa.study.dto.UserInfo2;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@SpringBootTest(classes={JpaApplication.class})
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional(readOnly = false,propagation = Propagation.REQUIRED)
public class UserDaoTest {

  @Autowired
  private UserDao userDao;
    @Test
  public void findUserListByPage3Test(){
    PageRecord<UserInfo2> pageRecord = userDao
        .findUserListByPage3(null, PageRequest.of(0, 15));

    System.out.println("分頁信息:");
    System.out.println("總記錄數:"+pageRecord.getTotalCount()+",總頁數:"+pageRecord.getTotalPages());
    System.out.println("頁碼:"+(pageRecord.getPageNumber()+1)+",每頁條數:"+pageRecord.getPageSize());
    List<UserInfo2> content = pageRecord.getData();
    content = null == content? new ArrayList<>() : content;
    content.forEach(user->System.out.println(user));
  }
}

執行一下單元測試,

分頁信息:
總記錄數:3,總頁數:1
頁碼:1,每頁條數:15
UserInfo2(id=3, name=諸葛亮, age=54, birthday=2001-09-16 08:00:00.0, mobile=158989989, email=zhu@qq.com, country=中國, province=湖北, city=武漢, createTime=2019-09-06 05:50:01.0)
UserInfo2(id=1, name=張三, age=35, birthday=2008-09-16 08:00:00.0, mobile=156989989, email=hu@qq.com, country=中國, province=上海, city=上海, createTime=2019-08-06 05:50:01.0)
UserInfo2(id=2, name=狄仁傑, age=50, birthday=1988-09-16 08:00:00.0, mobile=158789989, email=di@qq.com, country=中國, province=湖北, city=武漢, createTime=2019-07-06 05:50:01.0)

好了,至此,springDataJpa基於EntityManager原生sql多表聯合查詢+動態條件查詢+分頁返回自定義實體類對象就介紹完了,有需要源碼的朋友,請到git上下載源碼,源碼地址:https://github.com/hgq0916/springdatajpa-study.git。java學習交流羣:184998348,歡迎大家一起交流學習。

上一篇:springDataJpa入門教程(3-1)-基於EntityManager原生sql多表聯合查詢+動態條件查詢+分頁
下一篇:springDataJpa入門教程(4)-Example單表動態條件查詢+分頁
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章