轉載:https://blog.csdn.net/Cs_hnu_scw/article/details/80786161
(一)讓我們來搭建Spring Data的開發環境(還是和上面一樣哦!)
步驟:
1:在pom,xml文件中添加Spring Data的相關依賴
<!-- spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.8.0.RELEASE</version>
</dependency>
<!-- 配置hibernate的實體管理依賴-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.6.Final</version>
</dependency>
2:編寫JavaBean實體。(我這裏就不用上面的student,而用一個新的teacher來演示,便於大家進行查看,而且我們不需要提前在數據庫中創建表哦,當我們沒有的時候,這個是會自動創建表的呢!方便不?)
package com.hnu.scw.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @ Author :scw
* @ Date :Created in 下午 8:37 2018/6/22 0022
* @ Description:編寫一個老師實體類
* @ Modified By:
* @Version: $version$
*/
@Entity
public class Teacher {
//配置表的id,並且是使用自增
@Id
@GeneratedValue
private Integer id;
//設置列的長度爲15,並且不能爲空
@Column(length = 15 ,nullable = false)
private String name ;
private String classNumber ;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassNumber() {
return classNumber;
}
public void setClassNumber(String classNumber) {
this.classNumber = classNumber;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
", classNumber='" + classNumber + '\'' +
'}';
}
}
表結構如下:
3:編寫Spring 和Spring Data的相關配置文件(我命名爲springdatacontext.xml),放在resource文件目錄下。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置數據源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql:///springdata" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<!--配置entityManagerFactory 用於管理實體的一些配置-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan" value="com.hnu.scw"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy" >org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.dialect" >org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql" >true</prop>
<prop key="hibernate.format_sql" >true</prop>
<!--配置是否實體自動生成數據表-->
<prop key="hibernate.hbm2ddl.auto" >update</prop>
</props>
</property>
</bean>
<!--配置事務管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--配置支持事務註解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--配置spring data-->
<jpa:repositories base-package="com.hnu.scw" entity-manager-factory-ref="entityManagerFactory"/>
<!--配置spring的掃描包-->
<context:component-scan base-package="com.hnu.scw"/>
</beans>
進入我們真正的使用了哦!!!!!!重點來了~~~~~
4:編寫我們需要進行操作實體的Dao層接口-------------------重點,,好好看這接口的內容!
package com.hnu.scw.repository;
import com.hnu.scw.model.Teacher;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.RepositoryDefinition;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* @ Author :scw
* @ Date :Created in 下午 9:17 2018/6/22 0022
* @ Description:基於Spring Data接口的dao層開發接口
* @ Modified By:
* @Version: $version$
*/
//有兩種方式,要麼用註解要麼用繼承
//@RepositoryDefinition(domainClass = Teacher.class ,idClass = Integer.class)
public interface TeacherRepository extends Repository<Teacher , Integer> {
//===============使用springdata默認方式=============================
/**
* 根據名字查詢老師
* @param name
* @return
*/
Teacher findByName(String name);
/**
* 根據班級名稱進行查詢老師(這裏用到模糊匹配like)
* @param classNumber
* @return
*/
List<Teacher> findByclassNumberLike(String classNumber);
}
重點分析一波:
(1)首先,我們這個接口是需要繼承Repository這個接口
(2)泛型參數:第一個是我們制定這個接口所需要進行操作的實體JavaBean
第二個是我們實體JavaBean中主鍵的類型。(因爲我這主鍵是id,用的Integer類型)
(3)繼承的Repository這個接口有什麼用?讓我們看看源碼分析一下
什麼?????這個接口啥都沒有呀。。。對的,這個接口是什麼都沒有,就類似Serializable接口一樣,就是一個空接口,專業點說就是標記接口。。那麼,這個到底有什麼用呢?
大家,,認真看認真看!!!!!!!!!()
第一點:Repository是一個空接口,即是一個標記接口。
第二點:若我們定義的接口繼承了Repository,則該接口會被IOC容器識別爲一個Repository Bean,納入到IOC容器中,進而可以在該接口中定義滿足一定規範的方法。IOC容器中實際存放了繼承了Repository的接口的實現類,而這個實現類由spring幫助完成 。在applicationContext.xml中我們配置了springdata:這裏的base-package指定了Repository Bean所在的位置,在這個包下的所有的繼承了Repository的接口都會被IOC容器識別並納入到容器中,如果沒有繼承Repository則IOC容器無法識別。
第三點:我們也可以通過註解的方式替代繼承Repository接口@RepositoryDefinition(domainClass=需要處理的實體類的類型,IdClass=主鍵的類型)。
第四點:看看它有哪些子類:
那這些子類都有什麼用呢?別急,這在我後面都會提到哦!!!!
5:好了,我們來進行單元測試吧!
注意:阿,爲什麼不需要寫接口的實現類嗎?是不是博文你忘記說了呀。。。。。不不不不,咱們就是不寫,你先按照我上面的接口定義兩個方法就可以了。(不過,你要保證你的實體和我的是一樣的teacher哦!要不然肯定不行的)
package com.hnu.scw;
import com.hnu.scw.model.Teacher;
import com.hnu.scw.repository.TeacherRepository;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
/**
* @ Author :scw
* @ Date :Created in 下午 8:41 2018/6/22 0022
* @ Description:${description}
* @ Modified By:
* @Version: $version$
*/
public class SpringDataTest {
//用於加載spring配置文件
private ApplicationContext context = null;
//用於操作老師實體的接口
@Autowired
private TeacherRepository teacherRepository = null;
@Before
public void getContext(){
context = new ClassPathXmlApplicationContext("springdatacontext.xml");
//通過類名進行注入
teacherRepository = context.getBean(TeacherRepository.class);
}
/**
* 直接執行這個測試方法,然後就再去看一下數據庫就會發生對應實體中的內容到數據庫中了
*/
@Test
public void testCreateTableAuto(){
}
/**
* 測試springdata中的findByName方法(沒有任何的實現,這就是springdata的強大)
*/
@Test
public void testSpringDataFindName(){
Teacher teacher = teacherRepository.findByName("哈哈");
System.out.println(teacher);
}
/**
* 測試使用springdata進行模糊匹配
*/
@Test
public void testSpringDataLike(){
List<Teacher> teachers = teacherRepository.findByclassNumberLike("%班班%");
for (Teacher teacher:teachers) {
System.out.println(teacher);
}
}
}
溫馨提示:當我們直接上面的代碼後,就會發現,竟然竟然能夠進行數據操作耶,但是我並沒有寫實現類,這是爲什麼爲什麼爲什麼呢?
好的,咱們的重點來了,好好看看~~~~
知識點1:爲什麼只需要在接口中寫方法名稱,而不需要寫實現類就可以進行數據庫的操作?
解析:是否還記得我們的接口是繼承的Respository這個接口呢?是的,這個就是它的強大的地方。一切的一切都是歸根於它。這個原因我在上面已經說過了哦。
知識點2:在接口中方法名稱是隨便寫的嗎?有沒有什麼規範呢?
解析:這個當然不能隨便寫了,而且我們要實現我們想要的操作,我們必須滿足Spring Data定義的規範。
我來分析一下我寫的示例的方法,爲什麼這樣命名就可以實現我們想要的操作了。
第一:
首先:findBy就表示我們要進行查詢操作,所以,如果你需要進行查詢操作,那你就就需要前綴是findBy
其次:Name :這個也不是隨便的哦。如果我們想根據實體類中的名字屬性進行查詢,那麼就是Name,如果是想根據班級,那麼我們就要寫classNumber。當然,裏面的參數的命名就是隨便的啦,參數名字就沒什麼影響了
最後:Teacher返回類型:這個沒什麼特別,我們查詢的就是這個實體的數據,當然就是返回這個類型的對象啦。
第二:
首先:findBy這個和上面解釋一樣,我就不多說。
其次:classNumber這個也不多說,因爲,我是要進行這個屬性的模糊查詢呀!
最後:Like:這個可是很重要的哦。這後綴就代表是進行模糊匹配啦。所以,如果你要進行模糊匹配就要Like結束方法名。
OK,如果這樣,那我數據庫操作麻煩起來的話,那麼方法名不是特別長,特別難記了,而且好多規範都不知道,怎麼辦呢?彆着急呀,下面我就來給你介紹一下,有哪些命令的規範。。(其實嘛,後面當然有解決辦法啦~哈哈)
關鍵字 方法命名 sql where字句
And findByNameAndPwd where name= ? and pwd =?
Or findByNameOrSex where name= ? or sex=?
Is,Equals findById,findByIdEquals where id= ?
Between findByIdBetween where id between ? and ?
LessThan findByIdLessThan where id < ?
LessThanEquals findByIdLessThanEquals where id <= ?
GreaterThan findByIdGreaterThan where id > ?
GreaterThanEquals findByIdGreaterThanEquals where id > = ?
After findByIdAfter where id > ?
Before findByIdBefore where id < ?
IsNull findByNameIsNull where name is null
isNotNull,NotNull findByNameNotNull where name is not null
Like findByNameLike where name like ?
NotLike findByNameNotLike where name not like ?
StartingWith
findByNameStartingWith where name like '?%'
EndingWith findByNameEndingWith where name like '%?'
Containing findByNameContaining where name like '%?%'
OrderBy findByIdOrderByXDesc where id=? order by x desc
Not findByNameNot where name <> ?
In findByIdIn(Collection<?> c) where id in (?)
NotIn findByIdNotIn(Collection<?> c) where id not in (?)
True
findByAaaTue
where aaa = true
False findByAaaFalse where aaa = false
IgnoreCase findByNameIgnoreCase where UPPER(name)=UPPER(?)
咳咳咳咳,這麼多,記不住,怎麼辦?那麼,我就教你進一步的優化~畢竟先苦後甜嘛~~~~
(二)通過@Query註解來優化Spring Data接口中的方法
我們在上面已經看到了,一般接口定義方法的名字是比較麻煩的,當然,如果Spring Data只能做到這樣的程度,那就也太low了,所以如果解決上面的方法呢?很簡單,通過註解就可以解決了。
1:示例代碼:(這個還是寫在上面接口中即可,請注意我代碼裏面的註釋)
//==============使用query註解開發==============================================
/**
* 通過query註解進行開發模糊匹配(利用索引參數的方法)
* @param classNumber
* @return
*/
@Query("select t from Teacher t where t.classNumber like %?1%")
List<Teacher> queryTeacher(String classNumber);
/**
* 通過老師的名字來進行查詢數據
* @param name
* @return
*/
@Query("select t from Teacher t where t.name = ?1")
Teacher queryTeacherByName(String name );
/**
* 通過老師的名字來進行查詢數據(利用命名參數的方法,注意query註解的寫法不一樣的)
* @param name
* @return
*/
@Query("select t from Teacher t where t.name = :name")
Teacher queryTeacherByName2(@Param("name") String name );
/**
* 使用原生的SQL語句進行操作(注意from這時候用的就是數據庫的表名,而不是實體類名)
* 必須添加nativeQuery = true,因爲默認是false的
* @return
*/
@Query(nativeQuery = true , value = "select count(1) from teacher")
long countTeacherNumber();
2:編寫單元測試;
/**
* 測試使用springdata中的query註解進行開發模糊查詢
*/
@Test
public void testQueryTeacher(){
List<Teacher> teachers = teacherRepository.queryTeacher("班班");
for (Teacher teacher:teachers) {
System.out.println(teacher);
}
}
/**
* 測試通過佔位符進行操作查詢
*/
@Test
public void testQueryTeacherByName(){
Teacher teacher = teacherRepository.queryTeacherByName("哈哈");
System.out.println(teacher);
}
/**
* 測試通過別名進行操作查詢
*/
@Test
public void testQueryTeacherByName2(){
Teacher teacher = teacherRepository.queryTeacherByName2("哈哈");
System.out.println(teacher);
}
/**
* 測試使用原生的SQL語句進行開發
*/
@Test
public void testCountTeacherNumber(){
long number = teacherRepository.countTeacherNumber();
System.out.println("數據總條數爲:" + number);
}
(三)如何使用Spring Data進行刪除更新的數據庫操作
我們之前都是寫的查詢操作,那麼如果進行更新和刪除操作,是不是也是一樣的?
然而,請注意,並不是的,而且特別要注意下面兩點:
(1)對於更新和刪除操作,必須在接口的方法上面添加@Modifying註解,這樣就用於標識這是一個修改的操作
(2)必須在調用這個接口方法的地方(一般就是service層)使用事務,即用@Transactional註解進行標識。
示例代碼:
1:編寫接口方法:
//================進行springdata的更新刪除的處理======================
/**
* 根據老師表的id進行修改對應數據的老師名字
* 必須要添加@Modifying註解,並且要在調用的方法上添加事務註解@Transactional
* @param name
* @param id
*/
@Modifying
@Query("update Teacher t set t.name = ?1 where t.id = ?2")
void updateTeacherById(String name , Integer id);:
2:編寫service層代碼
package com.hnu.scw.service;
import com.hnu.scw.model.Teacher;
import com.hnu.scw.repository.TeacherCrudRespository;
import com.hnu.scw.repository.TeacherRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
/**
* @ Author :scw
* @ Date :Created in 下午 5:29 2018/6/23 0023
* @ Description:編寫springdata相關的service層代碼
* @ Modified By:
* @Version: $version$
*/
@Service
public class SpringDataService {
@Autowired
private TeacherRepository teacherRepository;
@Autowired
private TeacherCrudRespository teacherCrudRespository;
/**
* 根據id進行修改老師的名字
* @param name
* @param id
*/
@Transactional
public void updateTeacher(String name , Integer id){
teacherRepository.updateTeacherById(name , id);
}
}
3:單元測試代碼:
package com.hnu.scw.service;
import com.hnu.scw.model.Teacher;
import com.hnu.scw.repository.TeacherRepository;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
/**
* @ Author :scw
* @ Date :Created in 下午 5:27 2018/6/23 0023
* @ Description:測試service層的方法
* @ Modified By:
* @Version: $version$
*/
public class SpringDataServiceTest {
//用於加載spring配置文件
private ApplicationContext context = null;
@Autowired
private SpringDataService springDataService = null ;
@Before
public void getContext(){
context = new ClassPathXmlApplicationContext("springdatacontext.xml");
//通過類名進行注入
springDataService = context.getBean(SpringDataService.class);
}
/**
* 測試springdata的更新操作的方法
* 注意點:接口必須添加@Modifying註解
* 調用層service必須有事務註解@Transactional
*/
@Test
public void testUpdateTeacher(){
springDataService.updateTeacher("呵呵" , 1);
}
}:
Spring Data的進階
根據我們上面的內容,已經學會了基本的Spring Data的操作。那麼,它就這麼點技能麼?當然不是,請看下面的內容。
(一)接口繼承CrudRespository接口
說明: CrudRepository 接口繼承於 Repository 接口,並新增了簡單的增、刪、查等方法。
主要的方法如下:
示例代碼:
package com.hnu.scw.repository;
import com.hnu.scw.model.Teacher;
import org.springframework.data.repository.CrudRepository;
/**
* @ Author :scw
* @ Date :Created in 下午 5:38 2018/6/23 0023
* @ Description:通過繼承CrudRespository接口(因爲可以快速進行crud相關的方法開發)
* @ Modified By:
* @Version: $version$
*/
public interface TeacherCrudRespository extends CrudRepository<Teacher , Integer>{
}
示例單元測試類:大家就可以根據我上面貼的方法進行隨便編寫就好了啦。就不多寫測試方法了~~~~~~
(二)接口繼承JpaRespository接口
說明:JpaRepository支持接口規範方法名查詢。意思是如果在接口中定義的查詢方法符合它的命名規則,就可以不用寫實現了。這個我在前面就說了有哪些命名規則的哦~
主要的接口如下:
示例代碼:
package com.hnu.scw.repository;
import com.hnu.scw.model.Teacher;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @ Author :scw
* @ Date :Created in 下午 5:59 2018/6/23 0023
* @ Description:測試繼承JpaRepository接口的方法
* @ Modified By:
* @Version: $version$
*/
public interface TeacherJpaRepository extends JpaRepository<Teacher ,Integer>{
}
單元測試代碼:
package com.hnu.scw;
import com.hnu.scw.model.Teacher;
import com.hnu.scw.repository.TeacherJpaRepository;
import com.hnu.scw.repository.TeacherPagingAndSortRespository;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @ Author :scw
* @ Date :Created in 下午 6:00 2018/6/23 0023
* @ Description:測試繼承Respositoty接口的相關的操作
* @ Modified By:
* @Version: $version$
*/
public class JpaRespositotyTest {
//用於加載spring配置文件
private ApplicationContext context = null;
//用於操作老師實體的接口
@Autowired
private TeacherJpaRepository teacherJpaRepository = null;
@Before
public void getContext(){
context = new ClassPathXmlApplicationContext("springdatacontext.xml");
//通過類名進行注入
teacherJpaRepository = context.getBean(TeacherJpaRepository.class);
}
/**
* 測試JpaRepository接口中相關的查找數據的方法
*/
@Test
public void testJpaFind(){
//查詢id=20的數據
Teacher oneTeacher = teacherJpaRepository.findOne(20);
System.out.println(oneTeacher);
//判斷id=100的數據是否存在於數據庫中
boolean exists = teacherJpaRepository.exists(100);
System.out.println("數據存在嗎?" + exists);
}
}
(三)接口繼承PagingAndSortRespository接口
說明:這個接口主要就是實現了分頁和排序的方法。。。所以,分頁很重要哦~
方法接口如下:
接口示例代碼:
package com.hnu.scw.repository;
import com.hnu.scw.model.Teacher;
import org.springframework.data.repository.PagingAndSortingRepository;
/**
* @ Author :scw
* @ Date :Created in 下午 5:48 2018/6/23 0023
* @ Description:通過繼承PagingAndSortRespository接口來快速進行分頁開發
* @ Modified By:
* @Version: $version$
*/
public interface TeacherPagingAndSortRespository extends PagingAndSortingRepository<Teacher ,Integer>{
}
單元測試代碼:
package com.hnu.scw;
import com.hnu.scw.model.Teacher;
import com.hnu.scw.repository.TeacherPagingAndSortRespository;
import com.hnu.scw.repository.TeacherRepository;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
/**
* @ Author :scw
* @ Date :Created in 下午 5:49 2018/6/23 0023
* @ Description:測試PagingAndSortRespository接口的分頁方法
* @ Modified By:
* @Version: $version$
*/
public class PagingAndSortRespositoryTest {
//用於加載spring配置文件
private ApplicationContext context = null;
//用於操作老師實體的接口
@Autowired
private TeacherPagingAndSortRespository teacherPagingAndSortRespository = null;
@Before
public void getContext(){
context = new ClassPathXmlApplicationContext("springdatacontext.xml");
//通過類名進行注入
teacherPagingAndSortRespository = context.getBean(TeacherPagingAndSortRespository.class);
}
/**
* 測試通過繼承PagingAndSortRespository進行分頁的相關開發
* 相當的方便
*/
@Test
public void testPagingTeacher(){
PageRequest pageRequest = new PageRequest(0, 5);
Page<Teacher> page = teacherPagingAndSortRespository.findAll(pageRequest);
System.out.println("查詢的總頁數:" + page.getTotalPages());
System.out.println("查詢的總數據條數:" + page.getTotalElements());
System.out.println("查詢的當前頁數:" + (page.getNumber() + 1));
System.out.println("查詢的數據的內容:" + page.getContent());
System.out.println("查詢的當前頁的數據條數:" + page.getNumberOfElements());
}
/**
* 測試分頁和排序的方法
*/
@Test
public void testPagingAndSortTeacher(){
//按照id的降序進行排序
Sort.Order sortOrder = new Sort.Order(Sort.Direction.DESC, "id");
//構建排序對象
Sort sort = new Sort(sortOrder);
//把分頁和排序對象放入參數
PageRequest pageRequest = new PageRequest(0, 5 , sort);
Page<Teacher> page = teacherPagingAndSortRespository.findAll(pageRequest);
System.out.println("查詢的總頁數:" + page.getTotalPages());
System.out.println("查詢的總數據條數:" + page.getTotalElements());
System.out.println("查詢的當前頁數:" + (page.getNumber() + 1));
System.out.println("查詢的數據的內容:" + page.getContent());
System.out.println("查詢的當前頁的數據條數:" + page.getNumberOfElements());
}
}
(四)接口繼承JpaSpecificationExcutor接口
說明:不屬於Repository體系,實現一組 JPA Criteria 查詢相關的方法。Specification:封裝 JPA Criteria 查詢條件。通常使用匿名內部類的方式來創建該接口的對象。
主要接口方法如下:主要就是條件過濾,比如我們在分頁的時候需要一些條件,這樣就可以更好的進行分頁處理。
示例代碼如下:(用於實現分頁和過濾的作用)
package com.hnu.scw.repository;
import com.hnu.scw.model.Teacher;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
/**
* @ Author :scw
* @ Date :Created in 下午 6:04 2018/6/23 0023
* @ Description:繼承JpaSpecificationExecutorRepository接口
* @ Modified By:
* @Version: $version$
*/
public interface TeacherJpaSpecificationExecutorRepository extends PagingAndSortingRepository<Teacher , Integer> ,JpaSpecificationExecutor<Teacher >{
}
單元測試如下:
package com.hnu.scw;
import com.hnu.scw.model.Teacher;
import com.hnu.scw.repository.TeacherJpaSpecificationExecutorRepository;
import com.hnu.scw.repository.TeacherRepository;
import jdk.nashorn.internal.runtime.Specialization;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.*;
/**
* @ Author :scw
* @ Date :Created in 下午 6:11 2018/6/23 0023
* @ Description:繼承JpaSpecificationExecutor接口的方法
* @ Modified By:
* @Version: $version$
*/
public class JpaSpecificationExecutorTest {
//用於加載spring配置文件
private ApplicationContext context = null;
//用於操作老師實體的接口
@Autowired
private TeacherJpaSpecificationExecutorRepository teacherJpaSpecificationExecutorRepository = null;
@Before
public void getContext(){
context = new ClassPathXmlApplicationContext("springdatacontext.xml");
//通過類名進行注入
teacherJpaSpecificationExecutorRepository = context.getBean(TeacherJpaSpecificationExecutorRepository.class);
}
/**
* 進行測試JpaSpecificationExecutor這個接口的相關方法
* 實現查詢第一頁的前五條數據根據id升序排序,並且id要大於20
*/
@Test
public void testJpaSpecificationExecutor(){
//設置分頁要進行過濾的條件
Specification specification = new Specification<Teacher>(){
@Override
public Predicate toPredicate(Root<Teacher> root,
CriteriaQuery<?> criteriaQuery,
CriteriaBuilder criteriaBuilder) {
Path path = root.get("id");
//設置過濾條件爲id大於20 ,其中的gt就是表示大於
Predicate predicate = criteriaBuilder.gt(path , 20);
return predicate;
}
};
//按照id的降序進行排序
Sort.Order sortOrder = new Sort.Order(Sort.Direction.ASC, "id");
//構建排序對象
Sort sort = new Sort(sortOrder);
PageRequest pageRequest = new PageRequest(0, 5 , sort);
//把分頁和排序對象以及過濾對象放入參數
Page<Teacher> page = teacherJpaSpecificationExecutorRepository.findAll(specification ,pageRequest);
System.out.println("查詢的總頁數:" + page.getTotalPages());
System.out.println("查詢的總數據條數:" + page.getTotalElements());
System.out.println("查詢的當前頁數:" + (page.getNumber() + 1));
System.out.println("查詢的數據的內容:" + page.getContent());
System.out.println("查詢的當前頁的數據條數:" + page.getNumberOfElements());
}
}
讓我給你總結總結Spring Data
(1)上面就是關於Spring Data相關的一些處理操作,總體來說還是比較容易掌握的。
(2)我們在使用任何的框架或者插件的時候,我們都需要想個問題,我們爲什麼要用這個而不用其他的?那麼其他的又有什麼缺點,而我們用的又有什麼好處呢?這些都是該思考的東西,而不要只是進行學習,而不會其原理。
(3)Spring Data剛開始接觸可能還是需要個過程,畢竟它的接口比較多,操作數據庫的方法也比較靈活,所以,還是需要多進行練習的。
(4)Spring Data相比通用Mapper插件來說,其減少了xml文件的編寫,而是用更加靈活的註解和方法命名規範來進行處理,但是他們各自有好處,不能說哪個完全不好,完全看開發需求和場景來決定的。
(5)這裏講解的只是入門,當然是需要各位進行不斷擴展的哦~~~~~歡迎進行交流
(6)最後,我把項目的源碼放到百度雲網方便各位進行學習:
鏈接:https://pan.baidu.com/s/1Cc2MP6zM-NWDKQbNqpRfVA 密碼:5hur