在上一节,讲到了基于EntityManager原生sql多表联合查询+动态条件查询+分页,查询的结果集是用Object数组封装的,查询起来不是很方便。所以这节来介绍如何将EntityManager的查询结果封装到自定义实体类对象中。有需要源码的朋友,请到git上下载源码,源码地址:源码下载地址。java学习交流群:184998348,欢迎大家一起交流学习。
实体类分别是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;
}
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,欢迎大家一起交流学习。