SpringDataJpa

一.什麼是SpringDataJpa前端

 

一.什麼是SpringDataJpa

  • 它是Spring的一個子框架
  • 集成Jpa,讓我們操做數據庫變得更加的簡單

二.項目導包

  • 可以看懂這裏導入了哪些包
  • 也能夠理解這些包是作什麼的
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.itsource</groupId> <artifactId>aisell</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>aisell Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <org.springframework.version>4.2.5.RELEASE</org.springframework.version> <org.hibernate.version>4.3.8.Final</org.hibernate.version> <spring-data-jpa.version>1.9.0.RELEASE</spring-data-jpa.version> <com.fasterxml.jackson.version>2.5.0</com.fasterxml.jackson.version> <org.slf4j.version>1.6.1</org.slf4j.version> </properties> <dependencies> <!-- Spring的支持包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- 上下文支持包(幫咱們集成:模板,郵件,任務調度...) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework.version}</version> <scope>test</scope> </dependency> <!-- 引入web前端的支持 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- SpringMCV上傳須要用到io包--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> <!-- 文件上傳用到的包 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <!-- SpringMVC的json支持包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${com.fasterxml.jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${com.fasterxml.jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${com.fasterxml.jackson.version}</version> </dependency> <!-- hibernate的支持包 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${org.hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${org.hibernate.version}</version> </dependency> <!-- SpringDataJpa的支持包 --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>${spring-data-jpa.version}</version> </dependency> <!-- SpringData的擴展包 --> <dependency> <groupId>com.github.wenhao</groupId> <artifactId>jpa-spec</artifactId> <version>3.1.1</version> <!-- 把全部的依賴都去掉 --> <exclusions> <exclusion> <groupId>*</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <!--lang3:工具包 java.lang.--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.5</version> </dependency> <!-- 測試包 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <!-- 這個scope 只能做用在編譯和測試時,同時沒有傳遞性。表示在運行的時候不添加此jar文件 --> <scope>provided</scope> </dependency> <!-- 日誌文件 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${org.slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${org.slf4j.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency> <!-- 代碼生成器模版技術 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.6</version> </dependency> <!-- shiro(權限框架)的支持包 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.4.0</version> <type>pom</type> </dependency> <!-- shiro與Spring的集成包 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!-- poi(操做辦公軟件)支持的jar包 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.11</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.11</version> </dependency> <!-- 圖片壓縮功能 --> <!-- 縮略圖 --> <dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.6</version> </dependency> <!-- 定時調度 --> <dependency> <groupId>quartz</groupId> <artifactId>quartz</artifactId> <version>1.5.2</version> </dependency> <!-- 郵件支持 --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.1</version> </dependency> </dependencies> <build> <finalName>aisell</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>8.1.15.v20140411</version> <configuration> <stopPort>9966</stopPort> <stopKey>foo</stopKey> <webAppConfig> <contextPath>/</contextPath> </webAppConfig> </configuration> </plugin> </plugins> </build> </project> 

三 集成SpringDataJpa

3.1 完成Spring與Jpa的集成

昨天已經詳細講解過(要求本身是能夠把它寫出來)java

3.1.1 準備db.propeties

jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///aisell jdbc.username=root jdbc.password=123456 

3.2.2 準備applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <!--掃描service層的類--> <context:component-scan base-package="cn.itsource.aisell.service" /> <!-- db.properties -> dataSource(配置數據源[鏈接池dbcp]) -> EntityManagerFactory -> dao -> service -> 事務 -> controller(集成SpringMVC) -> easyui --> <!--1.讀取db.properties, 注意:不要忘了加classpath--> <context:property-placeholder location="classpath:db.properties" /> <!--2.配置dbcp鏈接池--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- JPA:ORM規範 -> 不少框架實現了這個規範(hibernate,openjpa,toplink,...) 3.配置EntityManagerFactory對象 3.1 基本配置都是寫在Spring中(四大金剛,建表策略,方言,是否顯示SQL) 3.2 Spring來建立這個對象(準備一個domain,若是運行的時候建立了表,就表明這個對象是成功的) alt+insert -> JPA -> LocalContainerEntityManagerFactoryBean ctrl+t/f4 : 有辦法看結構 --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--掃描JPA支持的註解--> <property name="packagesToScan" value="cn.itsource.aisell.domain" /> <!-- 告訴Spring咱們使用的是哪個框架來完成JPA規範 這裏就須要咱們配置一個適配器 jpaVendorAdapter:JPA須要配置的適配器(咱們會選擇hibernate) --> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <!--方言--> <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" /> <!-- 建表策略 --> <property name="generateDdl" value="false" /> <!--是否顯示sql--> <property name="showSql" value="true" /> </bean> </property> </bean> <!--4.加上事務--> <!--4.1 準備事務管理器--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!--4.2 開啓(註解)事務支持--> <tx:annotation-driven transaction-manager="transactionManager" /> </beans> 

3.2 集成SpringDataJpa

3.2.1 準備domain(父類)

  1. BaseDomain

jpa中父類domain必須要加上:@MappedSuperclassmysql

/** * 泛化:繼承關係 * 在咱們JPA,若是要抽取一個父類,就必需加上 @MappedSuperclass * 很是明肯定的告訴JPA,這是一個用於映射的父類 */ @MappedSuperclass public class BaseDomain { @Id @GeneratedValue protected Long id; //getter,setter ... } 
  1. Employeee
@Entity @Table(name = "employee") public class Employee extends BaseDomain { private String username; private String password; private Integer age; private String email; //getter,setter ... } 

3.2.2 準備Repository接口

/** * 關於Employee對象的CRUD(分頁排序) 就寫完了 * 泛型一:對哪個實體作CRUD * 泛型二:主鍵的類型 */ public interface EmployeeRepository extends JpaRepository<Employee,Long> { ... } 

3.2.3 掃描repository

  • repository 就是我們過去的dao
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" ... xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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 "> ... <!-- 讓SpringDataJpa去掃描repository --> <jpa:repositories base-package="cn.itsource.aisell.repository" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" /> </beans> 

四.完成的CRUD功能

4.1 基本的CRUD

  • 查詢全部:employeeRepository.findAll()
  • 查詢一條數據: employeeRepository.findOne(1L)
    • 思考題: findOne與getOne的區別?
  • 添加/修改: employeeRepository.save(employee)
    • 主要看數據庫中是否有這個值
  • 刪除 : employeeRepository.delete(274L)

4.2 分頁和排序

4.2.1 排序

/** * 排序對象 * 第一個參數:排序的類型(升序仍是降序) * 第二個參數:排序的屬性 */ Sort sort = new Sort(Sort.Direction.DESC,"age"); List<Employee> list = employeeRepository.findAll(sort); list.forEach(e-> System.out.println(e)); 

4.2.2 分頁

注:這裏的分頁是從0開始的git

/** * page:第幾頁(0就是第1頁) * size:每頁條數 */ Pageable pageable = new PageRequest(0,10); //分頁對象 Page<Employee> list = employeeRepository.findAll(pageable); list.forEach(e-> System.out.println(e)); 

4.2.3 分頁+排序

Sort sort = new Sort(Sort.Direction.DESC,"age"); /** * page:第幾頁(0就是第1頁) * size:每頁條數 * sort:排序對象 */ Pageable pageable = new PageRequest(0,10,sort); //分頁對象 Page<Employee> list = employeeRepository.findAll(pageable); list.forEach(e-> System.out.println(e)); 

4.3 名稱規則(根據條件進行查詢)

詳細規則請查看文檔github

/** * 根據規範(SpringDataJpa)寫方法名,就能夠進行查詢 * @param username * @return * username =? */ //根據用戶名查詢一個員工 Employee findByUsername(String username); //用戶名模糊查詢 username like ? List<Employee> findByUsernameLike(String username); //用戶名與郵件模糊查詢 username like ? and email like ? List<Employee> findByUsernameLikeAndEmailLike(String username,String email); 

4.4 Query註解查詢

//根據用戶名獲取用戶 @Query("select o from Employee o where o.username =?1") Employee query01(String username); //用戶名與郵件模糊查詢 username like ? and email like ? @Query("select o from Employee o where o.username like ?1 and o.email like ?2") List<Employee> query02(String username,String email); // @Query("select o from Employee o where o.username like :username and o.email like :email") // List<Employee> query02(@Param("username") String username,@Param("email") String email); //直接寫原生的SQL @Query(nativeQuery=true,value="select * from employee") List<Employee> query03(); 

五.JpaSpecificationExecutor

  • 是一個JPA的規範執行者
  • JPA2.0提供的Criteria API的使用封裝
  • 須要我們的的repository繼承JpaSpecificationExecutor接口
interface EmployeeRepository extends JpaRepository<Employee,Long>,JpaSpecificationExecutor<Employee> 

5.1 最簡單的查詢

@Test
public void testJpaSpecificationExecutor01() throws Exception{ /** * 這裏的查詢咱們須要本身去定義規則:Specification */ List<Employee> list = employeeRepository.findAll(new Specification<Employee>() { /** * 這個方法就是幫我們建立規則的方法,只要把這個方法搞定,我們就能夠完成查詢了 * @param root(根) : 表明了能夠查詢和操做的實體對象的根 * 能夠幫助咱們獲取到實體對應的字段 * @param query(查詢) : 表明一個specific的頂層查詢對象 * 包含查詢的各個部分,好比select,from,where,group by ,order by 等 * 還能夠支持and ,or的功能 * @param cb :用來構建CriteriaQuery的構建器對象(至關於條件或者說條件組合) * 主要判斷關係(和這個字段是相等,大於,小於like等) * 支持 and,or的功能 * @return Predicate:代表; 闡明; 斷言 * 你把它當成 where username like ? and email like ? and age > ? ... */ @Override public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) { //1.拿到Employee中的username字段 Path usernamePath = root.get("username"); //2.加上字段的判斷關係 // 參數1:字段(表達式) 2.值 Predicate p1 = cb.like(usernamePath, "%1%"); return p1; } }); list.forEach(e-> System.out.println(e)); } 

5.2 多個條件查詢

@Test
public void testJpaSpecificationExecutor02() throws Exception{ //Specification:查詢規則 List<Employee> list = employeeRepository.findAll(new Specification<Employee>() { // root:拿到字段(表達式) cb:設置條件(>,<,=,like),and/or @Override public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) { //拿到username並設置條件 Path usernamePath = root.get("username"); Predicate p1 = cb.like(usernamePath, "%1%"); //拿到email並設置條件 Path emailPath = root.get("email"); Predicate p2 = cb.like(emailPath, "%2%"); //拿到age並設置條件 gt/lt:大於/小於 ge/le:大於等於/小等等於 Path agePath = root.get("age"); Predicate p3 = cb.gt(agePath, 18); //把條件結合起來 return cb.and(p1, p2, p3); } }); list.forEach(e-> System.out.println(e)); } 

5.3 查詢+分頁+排序

/** * 高級查詢加分頁 * @throws Exception */ @Test public void testJpaSpecificationExecutor03() throws Exception{ //建立一個分頁對象 Pageable pageable = new PageRequest(1,10); //分頁+高級查詢 Page<Employee> page = employeeRepository.findAll(new Specification<Employee>() { @Override public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Path usernamePath = root.get("username"); return cb.like(usernamePath, "%1%"); } }, pageable); page.forEach(e->System.out.println(e)); } /** * 高級查詢加分頁+排序 * @throws Exception */ @Test public void testJpaSpecificationExecutor04() throws Exception{ Sort sort = new Sort(Sort.Direction.DESC,"age"); //建立一個分頁對象 Pageable pageable = new PageRequest(0,10,sort); //分頁+高級查詢 Page<Employee> page = employeeRepository.findAll(new Specification<Employee>() { @Override public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Path usernamePath = root.get("username"); return cb.like(usernamePath, "%1%"); } }, pageable); page.forEach(e->System.out.println(e)); } 

六.jpa-spec

6.1 簡單查詢

注意:導的是:import com.github.wenhao.jpa.Specifications;web

//jpa-spec //完成我們的簡單查詢 username like ? @Test public void testJpaSpec01() throws Exception{ Specification<Employee> spec = Specifications.<Employee>and() .like("username", "%1%") .build(); List<Employee> list = employeeRepository.findAll(spec); list.forEach(e-> System.out.println(e)); } 

6.2 多條件查詢

//jpa-spec //完成我們的簡單查詢 username like ? and email like ? and age>? @Test public void testJpaSpec02() throws Exception{ Specification<Employee> spec = Specifications.<Employee>and() .like("username", "%1%") .like("email","%2%") .gt("age",18) .build(); List<Employee> list = employeeRepository.findAll(spec); list.forEach(e-> System.out.println(e)); } 

6.3 多條件+分頁

//jpa-spec //完成我們的簡單查詢 username like ? + 分頁 + 排序 @Test public void testJpaSpec03() throws Exception{ //建立排序對象 Sort sort = new Sort(Sort.Direction.DESC,"age"); //建立分頁對象 Pageable pageable = new PageRequest(0,10,sort); //規則對象(查詢條件) Specification<Employee> spec = Specifications.<Employee>and() .like("username", "%1%") .build(); //功能執行 Page<Employee> page = employeeRepository.findAll(spec, pageable); page.forEach(e-> System.out.println(e)); } 

七.Query抽取

  • Query是我們的查詢對象

7.1 BaseQuery

  • 有經驗的人都會建立父類
    • 方便擴展
    • 公共的代碼
    • 制定規範
  • 目前我們Query須要作的
    • 四個字段(currrentPage,pageSize,orderType,orderName)
    • 讓每一個子類都有一個:createSpec()
    • 建立一個order對象
    • 解決了傳過來的是當前頁從1開始(SpringDataJpa是從0開始計算)
/** * 父類的做用: * 1.提供一些公共的屬性的方法(少寫代碼) * 2.對子類造成相應的規範 * 3.爲了之後代碼的擴展性 */ public abstract class BaseQuery { //分頁 -> 當前第幾頁 private int currentPage=1; //分頁 -> 每頁條數 private int pageSize=10; //排序 -> 排序的類型 true(DESC)/false(ASC) private boolean orderType; //排序 -> 排序的字段 -> 若是這個字段爲null,就表明不排序 private String orderName; //建立排序對象 public Sort createSort(){ if(StringUtils.isNotBlank(orderName)){ //orderName有值才作排序 Sort sort = new Sort(orderType?Sort.Direction.DESC:Sort.Direction.ASC,orderName); return sort; } return null; } //要求只要繼承了我,就必需有一個方法叫:createSpec() public abstract Specification createSpec(); public int getJpaPage() { return currentPage-1; } //getter,setter.... } 

7.2 EmployeeQuery

  • 設置當前對應的Domain的特有查詢字段
  • 實現 createSpec()
/** * 員工查詢 */ public class EmployeeQuery extends BaseQuery { //用戶名 private String username; //郵件 private String email; //年齡 private Integer age; //查詢的規則應該在查詢對象中來建立 @Override public Specification createSpec(){ Specification<Employee> specification = Specifications.<Employee>and() .like(StringUtils.isNotBlank(username), "username", "%" + username + "%") .like(StringUtils.isNotBlank(email), "email", "%" + email + "%") .gt(age != null, "age", age) .build(); return specification; } //getter,setter... } 

7.3 測試spring

/** * 有Query的查詢 * @throws Exception */ @Test public void testJpaSpec04() throws Exception{ //之後我們的查詢數據是從前臺傳過來的,就會生成EmployeeQuery對象 EmployeeQuery query = new EmployeeQuery(); // query.setUsername("1"); // query.setEmail("2"); // query.setAge(18); query.setOrderName("age"); query.setOrderType(true); //建立排序對象 Sort sort = query.createSort(); //建立分頁對象(分頁對象從前臺傳過來) Pageable pageable = new PageRequest(query.getJpaPage(),query.getPageSize(),sort); //規則對象(查詢條件) Specification<Employee> spec = query.createSpec(); //功能執行 Page<Employee> page = employeeRepository.findAll(spec, pageable); page.forEach(e-> System.out.println(e)); }
相關文章
相關標籤/搜索