个人项目总结(一)

本文介绍SpringDataJPA的集成步骤及使用方法,包括配置、基本功能、复杂查询及自定义扩展等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringDataJp

1. 集成Spring+SpringDataJpa

1)引入相关jar包(项目所有包)

   <?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>springdatajpa</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <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>
        </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>4.2.5.RELEASE</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>
            <!-- SpringData的支持包 -->
            <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>
    
            <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>
        </dependencies>
    </project>

2)配置applicationContext.xml

 <!-- 扫描service部分的包 -->
     <context:component-scan base-package="cn.itsource.aisell.service" />
     <context:property-placeholder location="classpath:jdbc.properties" />
     <!-- 配置连接池 -->
     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
 destroy-method="close">
         <!--连接数据4个属性 -->
         <property name="driverClassName" value="${jdbc.driverClassName}" />
         <property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
         <property name="password" value="${jdbc.password}" />
         <!--maxActive: 最大连接数量 -->
         <property name="maxActive" value="150" />
         <!--minIdle: 最小空闲连接 -->
         <property name="minIdle" value="5" />
         <!--maxIdle: 最大空闲连接 -->
         <property name="maxIdle" value="20" />
<!--initialSize: 初始化连接 -->
         <property name="initialSize" value="30" />
         <!-- 用来配置数据库断开后自动连接的 -->
         <!-- 连接被泄露时是否打印 -->
         <property name="logAbandoned" value="true" />
         <!--removeAbandoned: 是否自动回收超时连接 -->
         <property name="removeAbandoned" value="true" />
         <!--removeAbandonedTimeout: 超时时间(以秒数为单位) -->
<property name="removeAbandonedTimeout" value="10" />
         <!--maxWait: 超时等待时间以毫秒为单位 1000等于60秒 -->
         <property name="maxWait" value="1000" />
         <!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. -->
         <property name="timeBetweenEvictionRunsMillis" value="10000" />
         <!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
         <property name="numTestsPerEvictionRun" value="10" />
         <!-- 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程 -->
         <property name="minEvictableIdleTimeMillis" value="10000" />
         <property name="validationQuery" value="SELECT NOW() FROM DUAL" />
     </bean>
     <!-- 集成hibernate的jpa功能 -->
     <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
         <property name="dataSource" ref="dataSource" />
         <!--待扫描的实体类包,不再需要persistence.xml了 -->
         <property name="packagesToScan" value="cn.itsource.aisell.domain" />
        <!-- 3.配置JPA的实现 -->
         <!-- private JpaVendorAdapter jpaVendorAdapter; -->
         <property name="jpaVendorAdapter">
             <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                 <!-- org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter -->
                 <!-- private boolean showSql = false;是否显示sql语句 -->
                 <property name="showSql" value="true" />
                 <!-- private boolean generateDdl = false;是否建表 -->
                 <property name="generateDdl" value="false" />
                 <!-- private String databasePlatform;原来方言 -->
                 <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
             </bean>
         </property>
     </bean>
     <!-- Jpa 事务配置 -->
     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
         <property name="entityManagerFactory" ref="entityManagerFactory" />
     </bean>
     <!-- 注解声明式事务管理 -->
     <tx:annotation-driven />
 
     <!-- Spring Data Jpa配置 ********************************************-->
     <!-- base-package:扫描的包 -->
<jpa:repositories base-package="cn.itsource.pss.repository" transaction-manager-ref="transactionManager"
                       entity-manager-factory-ref="entityManagerFactory" /><beans> 

3)准备Domain

@Entity
			@Table(name="employee")
			public class Employee extends  BaseDomain {
		    private String username;
		    private String password;
		    private String email; 
		    private Integer age;
		   //省略getter,setter与toString(注意:Alt+Insert可以自动生成) 			}

4)完成Repository的功能

package cn.itsource.pss.repository;

import cn.itsource.pss.domain.Employee; import org.springframework.data.jpa.repository.JpaRepository;

/**  * 必需继续JpaRepository<1v,2v>  *     1v:代表你要操作的是哪一个domain对象  *     2v:这个domain对象的主键的类型  */
public interface EmployeeRepository extends JpaRepository<Employee, Long> { }

2. SpringDataJpa认识使用

1) SpringDataJpa是JPA规范的再次封装底层还是使用了Hibernate的JPA技术实现,引用JPQL的查询语句
2) 简化创建 JPA 数据访问层和跨存储的持久层功能
3)ORM框架:对象关系映射(JPA)
在这里插入图片描述4) SimpleJpaRepository类实现了JpaRepository接口和JpaSpecificationExecutor接口,
在这里插入图片描述
而SpringDataJpa自动创建了一个代理类proxy,实现了我们自己写的EmployeeRepository接口,同时继承了SimpleJpaRepository类

在这里插入图片描述

3. JpaRepository基本功能

1)分页:

Pageable  page = new PageRequest(page,size); 			
employeeRepository.findAll(page);

2)排序:

Sort   sort   = new   Sort(Sort.Direction.DESC,"age"); 			
employeeRepository.findAll(sort);

3)分页排序:

Pageable  page = new PageRequest(page,size,sort); 			
employeeRepository.findAll(sort);

4)高级查询(继承了JpaRepository的接口中):

① List  findByUsername(String username); //根据用户名Username查询 			 
② List  findByUsernameLike(String username);//根据用户名模糊查询 			
③ List  findByUsernameLikeAndEmailLike(String username,String email);//多条件模糊查询

之所以可以用以上方法查询,是因为SpringDataJpa准备的一套规范
在这里插入图片描述在这里插入图片描述
5) 复杂的查询SpringDataJpa规范无法使用,需要自己写sql

 @Query("select o from Employee o where o.username like ?1") 		
 List<Employee> query01(String username); //按参数位置赋值 
 @Query("select o from cn.itsource.pss.domain.Employee o where  o.username like :username and o.email like :email") 			 		
 List<Employee> query03(@Param("username") String username,@Param("email")  String email);//按名称赋值

4. JpaSpecificationExecutor接口的认识

1)jpa使用paSpecificationExecutor技术完成了Criteria标准(一种比JQPL,HQL更面向对象的语言),
2)使用
Root:查询哪个表(定位到表和字段-> 用于拿到表中的字段)
* 可以查询和操作的实体的根
* Root 相当于 from Employee
* Root 相当于 from Product
CriteriaQuery:查询哪些字段,排序是什么(主要是把多个查询的条件连系起来)
CriteriaBuilder:字段之间是什么关系,如何生成一个查询条件,每一个查询条件都是什么方式
* 主要判断关系(和这个字段是相等,大于,小于like等)
Predicate(Expression):单独每一条查询条件的详细描述 整个 where xxx=xx and yyy=yy …

① 单个条件

   List<Employee> emps = employeeRepository.findAll(
                new Specification<Employee>() {
                    @Override
                    public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                        Path path = root.get("username");//拿到要做查询的字段
                        Predicate p = cb.like(path, "%1%");//like代表做模糊查询,后面就是它的条件值
                        return p;
                    }
                }
        );
        for (Employee emp : emps) {
            System.out.println(emp);
        } }

②多个条件

public void testFind02() {
    Specification spec = new Specification<Employee>() {
        @Override
        public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
            //加上第一个条件: username like '%1%'
            Path path1 = root.get("username");
            Predicate p1 = cb.like(path1, "%1%");
            //加上第二个条件: email like '%2%'
            Path path2 = root.get("email");
            Predicate p2 = cb.like(path2,"%2%");
            //加上第二个条件: age < 20
            Path path3 = root.get("age");
            Predicate p3 = cb.lt(path3, 20);
           //下面是加上or的条件的方案
           //Predicate p3 = cb.or(p1,p2);

            //把两个查询条件放到query对象中去(条件使用where)
            CriteriaQuery where = query.where(p1, p2, p3);//同样可以使用:cb.add(p1,p2,p3)
            //返回查询条件
            return where.getRestriction();
        }
    };

    List<Employee> emps = employeeRepository.findAll(spec);
    for (Employee emp : emps) {
        System.out.println(emp);
    }
}

③ 既分页有排序

	Sort sort = new Sort(Sort.Direction.DESC,"age");
	Pageable page = new  PageRequest(page,size,sort);
	employeeRepository.findAll(p,page);//p 为Predicate类型值

5. jpa-spec插件

1)主要是用于简化JpaSpecificationExecutor
2) 插件地址:(https://github.com/wenhao/jpa-spec)
3) Maven导包

<dependency>
    <groupId>com.github.wenhao</groupId>
    <artifactId>jpa-spec</artifactId>
    <version>3.2.3</version>
</dependency>
  1. 使用
 public void testSpecFind01() {
 	                Specification<Employee> spec = Specifications.<Employee>and()
     					.like("username", "%1%")
    					.build();
	                List<Employee> emps = employeeRepository.findAll(spec);
 }

6. query查询条件

1)准备一个对象Query接受前台传来的查询数据,
2)代码

public void testSpecFindByQuery() {
    //创建模块一个Query对象
    EmployeeQuery baseQuery = new EmployeeQuery();
//下面的都是测试的条件,可以任何放开进行测试
    //baseQuery.setUsername("1");
    //baseQuery.setAge(20);
    //baseQuery.setEmail("2");
    //baseQuery.setOrderByName("username");
    //baseQuery.setOrderByType("DESC");
    //baseQuery.setCurrentPage(2);
    //baseQuery.setPageSize(5);

	//like(条件boolean值,字段,值)
	//StringUtils.isNotBlank(baseQuery.getUsername()):判断参数不为空且不为空字符串
    Specification<Employee> spec = Specifications.<Employee>and()
            .like(StringUtils.isNotBlank(baseQuery.getUsername()), "username","%"+baseQuery.getUsername()+"%")
            .like(StringUtils.isNotBlank(baseQuery.getEmail()), "email","%"+baseQuery.getEmail()+"%")
            .lt(baseQuery.getAge()!=null, "age",baseQuery.getAge())
            .build();
    //这里确定是否需要排序
    Sort sort = null;
    if(baseQuery.getOrderByName()!=null){
        Sort.Direction desc = "DESC".equals(baseQuery.getOrderByType())?Sort.Direction.DESC:Sort.Direction.ASC;
        sort = new Sort(desc,baseQuery.getOrderByName());
    }
    Pageable pageable = new PageRequest(baseQuery.getJpaPage(), baseQuery.getPageSize(),sort);

    Page<Employee> page = employeeRepository.findAll(spec, pageable);
    for (Employee emp : page) {
        System.out.println(emp);
    }
}

7.SpringDataJpa扩展

在这里插入图片描述

1)创建一个BaseRepository接口,继承JpaSpectfifcationExecutor,JpaRepository接口。接口中可以定义自己的方法。
SimpleJpaRepository类实现了JpaSpectfifcationExecutor,JpaRepository接口,SpringDataJpa自动创建的实现类继承
SimpleJpaRepository类和EmployeeRepository接口,而BaseRepository中的方法没有实现,所以应该创建一个BaseRepostoryImpl
来实现BaseRepository接口并继承SimpleJpaRepository

2)代码
BaseRepository:

@NoRepositoryBean
public abstract interface BaseRepository<T,ID extends Serializable> 
        extends JpaRepository<T,ID>,JpaSpecificationExecutor<T> {
    //根据Query拿到分页对象(分页)
    Page findPageByQuery(BaseQuery baseQuery);

    //根据Query拿到对应的所有数据(不分页)
    List<T> findByQuery(BaseQuery baseQuery);

    //根据jpql与对应的参数拿到数据
    List findByJpql(String jpql, Object... values);

}		

BaseRepositoryImpl:

 public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {
    private final EntityManager entityManager;
    //必需要实现父类的这个构造器
    public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }
    @Override
    public Page findPageByQuery(BaseQuery baseQuery) {
        //第一步:拿到所有高级查询条件
        Specification spec = baseQuery.specification();
        //第二步:拿到排序的值
        Sort sort = baseQuery.sort();
        //第三步:根据条件查询分页数据并且返回
        Pageable pageable = new PageRequest(baseQuery.getNewcurrentPage(), baseQuery.getPageSize(),sort);
        Page<T> page = super.findAll(spec, pageable);
        return page;
    }
    @Override
    public List<T> findByQuery(BaseQuery baseQuery) {
        //第一步:拿到所有高级查询条件
        Specification spec = baseQuery.specification();
        //第二步:拿到排序的值
        Sort sort = baseQuery.sort();
        //第三步:拿到数据返回
        return findAll(spec, sort);
    }
    @Override
    public List findByJpql(String jpql, Object... values) {
        //第一步:创建Query对象
        Query query = entityManager.createQuery(jpql);
        //第二步:把值设置到Query对象中去
        if (values!=null) {
            for (int i = 0; i < values.length; i++) {
                query.setParameter(i + 1, values[i]);
            }
        }
        //第三步:返回数据
        return query.getResultList();
    }
}

同时还要告诉SpringDataJpa在创建对象是不使用SimpleJpaRepository,而使用自己写的BaseRepositoryImpl
① 先创建一个BaseRepositoryFactoryBean类

public class BaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T,S,ID> {
    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new MyRepositoryFactory<T,ID>(entityManager); //注:这里创建是我们的自定义类
    }

    //继承JpaRepositoryFactory后,把返回的对象修改成我们自己的实现
    private static  class MyRepositoryFactory<T,ID extends Serializable>   extends JpaRepositoryFactory {
        private final EntityManager entityManager;
        /**
         * Creates a new {@link JpaRepositoryFactory}.
         *
         * @param entityManager must not be {@literal null}
         */
        public MyRepositoryFactory(EntityManager entityManager) {
            super(entityManager);
            this.entityManager = entityManager;
        }
        //这里返回最后的功能对象
        @Override
        protected Object getTargetRepository(RepositoryInformation information) {
            return new BaseRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager);
        }
        //确定功能对象的类型
        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseRepositoryImpl.class;
        }
    }
}

② 在applicationContext.xml中配置
在这里插入图片描述
③ EmployeeRepository继承BaseRepositoryImpl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值