5.JpaSpecificationExecutor接口
这个接口支持多条件查询,同时支持分页与排序。
看下图,会发现JpaSpecificationExecutor接口并没有继承自任何的接口。
我们要新新建一个dao:
package com.haiexijun.dao; import com.haiexijun.pojo.Users; import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; //继承自JpaSpecificationExecutor接口,这个接口传入一个泛型(要查询的表对应的实体类)。 //这个接口不能单独使用,需要配合着jpa中的其他接口一起使用 @Repository public interface UserDao01 extends JpaSpecificationExecutor<Users>, JpaRepository<Users,Integer> { }
(1)单条件查询:
/** * 需求:根据用户姓名查询数据 */ @Test @Transactional @Rollback(value = false) public void test15(){ Specification<Users> spec=new Specification<Users>() { /** * * @param root :根对象。封装了查询条件的对象 * @param query :定义了基本的查询,一般不使用 * @param criteriaBuilder :创建一个查询的条件 * @return Predicate:定义了查询条件 */ @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { Predicate pre= criteriaBuilder.equal(root.get("userName"),"张三"); return pre; } }; List<Users> list= userDao01.findAll(spec); System.out.println(list); }
(2)多条件查询
方式一:
/** * 多条件查询 方式一 * * 需求,要求根据用户的姓名以及年龄查询数据 */ @Test @Transactional @Rollback(value = false) public void test16(){ Specification<Users> spec=new Specification<Users>() { @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { List<Predicate> list=new ArrayList<Predicate>(); list.add(criteriaBuilder.equal(root.get("userName"),"张三")); list.add(criteriaBuilder.equal(root.get("userAge"),26)); //有几个条件就传入几个predicate对象 Predicate[] arr=new Predicate[list.size()]; return criteriaBuilder.and(list.toArray(arr)); } }; List<Users> list = userDao01.findAll(spec); System.out.println(list); }
方式二:
/** * 多条件查询 方式二 * * 需求,要求根据用户的姓名或者年龄查询数据 */ @Test @Transactional @Rollback(value = false) public void test17(){ Specification<Users> spec=new Specification<Users>() { @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { return criteriaBuilder.or(criteriaBuilder.equal(root.get("userName"),"张三"),criteriaBuilder.equal(root.get("userAge"),27)); } }; List<Users> list = userDao01.findAll(spec); System.out.println(list); }
多条件查询的分页查询:
/** * 需求:查询姓张的用户,并做分页处理 */ @Test @Transactional @Rollback(value = false) public void test18(){ //条件 Specification<Users> spec=new Specification<Users>() { @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { return criteriaBuilder.like(root.get("userName").as(String.class),"张%"); } }; //分页 Pageable pageable=PageRequest.of(0,2); Page<Users> page= userDao01.findAll(spec,pageable); System.out.println("总条数:"+page.getTotalElements()); System.out.println("总页数:"+page.getTotalPages()); System.out.println(page.getContent()); }
多条件查询的排序操作:
/** * 需求:查询姓张的用户,并按用户年龄降序排序 */ @Test @Transactional @Rollback(value = false) public void test19(){ //条件 Specification<Users> spec=new Specification<Users>() { @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { return criteriaBuilder.like(root.get("userName").as(String.class),"张%"); } }; //排序 Sort sort=Sort.by(Sort.Direction.DESC,"userAge"); List<Users> list=userDao01.findAll(spec,sort); System.out.println(list); }
多条件查询的分页加排序操作:
/** * 需求:查询姓张的用户,做分页处理,然后按用户年龄降序排序 */ @Test @Transactional @Rollback(value = false) public void test20(){ //排序 Sort sort=Sort.by(Sort.Direction.DESC,"userAge"); //分页 Pageable pageable=PageRequest.of(0,2,sort); //查询条件 Specification<Users> spec=new Specification<Users>() { @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { return criteriaBuilder.like(root.get("userName").as(String.class),"张%"); } }; Page<Users> page=userDao01.findAll(spec,pageable); System.out.println("总条数:"+page.getTotalElements()); System.out.println("总页数:"+page.getTotalPages()); System.out.println(page.getContent()); }
6.用户自定义Repository接口
我们在开发的时候,如果觉得他给的接口不足以满足需求的话,我们也可以自己去定义自己的Repository接口。
具体可以如下:
在repositoey包下面创建我们自己定义的Reposity接口,里面定义方法:
package com.haiexijun.repository; import com.haiexijun.pojo.Users; public interface UsersRepository { public Users findUserById(Integer userId); }
然后我们定义自己的Dao类实现这个接口:
package com.haiexijun.dao; import com.haiexijun.pojo.Users; import com.haiexijun.repository.UsersRepository; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @Repository public class UserDaoImpl implements UsersRepository { @PersistenceContext(name = "entityManagerFactory") private EntityManager em; @Override public Users findUserById(Integer userId) { return this.em.find(Users.class,userId); } }
我们也可以定义测试方法来调用一下这个dao:
/** * 测试自定义Repository */ @Test @Transactional @Rollback(value = false) public void test21(){ Users user= userDao.findUserById(5); System.out.println(user); }
7.关联映射的操作
(1) 一对一的关联关系
案例需求:用户与角色的一对一的联级关系
用户一方,角色一方。
案例具体的步骤如下:
分别创建两个实体类Users实体类和Roles实体类:
Users
package com.haiexijun.pojo; import javax.persistence.*; import java.io.Serializable; @Entity @Table(name = "t_users") public class Users implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY)//自增 @Column(name = "userid") private Integer userId; @Column(name = "username") private String userName; @Column(name = "userage") private Integer userAge; //dao具体要操作那个表,就对那个表的实体类添加CascadeType //通过cascade = CascadeType.PERSIST来进行级联操作,使Users表在更新的同时也能更新到Roles表 @OneToOne(cascade = CascadeType.PERSIST) //JoinColumn的作用就是维护一个外键 @JoinColumn(name = "roleid") private Roles roles; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getUserAge() { return userAge; } public void setUserAge(Integer userAge) { this.userAge = userAge; } public Roles getRoles() { return roles; } public void setRoles(Roles roles) { this.roles = roles; } @Override public String toString() { return "Users{" + "userId=" + userId + ", userName='" + userName + '\'' + ", userAge=" + userAge + ", roles=" + roles + '}'; } }
Roles
package com.haiexijun.pojo; import javax.persistence.*; @Entity @Table(name = "t_roles") public class Roles { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "roleid") private Integer roleId; @Column(name = "rolename") private String roleName; @OneToOne(mappedBy = "roles") private Users users; public Integer getRoleId() { return roleId; } public void setRoleId(Integer roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Users getUsers() { return users; } public void setUsers(Users users) { this.users = users; } @Override public String toString() { return "Roles{" + "roleId=" + roleId + ", roleName='" + roleName + '\'' + '}'; } }
之后会分别在两个实体类里面添加@OneToOne注解。在通过@JoinColumn(name = “roleid”)注解在任一个实体中定义好外键。
下面编写一个测试方法来具体演示如何操作:
/** * 测试一对一的关联操作 */ @Test @Transactional @Rollback(value = false) public void test22(){ //创建角色 Roles roles=new Roles(); roles.setRoleName("管理员"); //创建用户 Users users=new Users(); users.setUserAge(30); users.setUserName("毛不易"); //建立关系 users.setRoles(roles); roles.setUsers(users); //保存数据 usersDao.save(users); }
这样,我们就完成了根据一对一关联关系来操作了数据。
下面我们在来写一个方法来测试一下通过一对一关联关系的查询操作:
@Test @Transactional @Rollback(value = false) public void test23(){ Users users=usersDao.findByUserId(7); System.out.println("用户信息"+users); Roles roles=users.getRoles(); System.out.println(roles); }