SpringBoot第四讲扩展和封装Spring Data JPA(一)_自定义Repository和创建自己的BaseRepository
这一讲主要介绍Spring Data JPA的封装。和设计相关的东西都是仁者见仁,智者见智的事情,如果你有更好的封装方案可以和我交流,互相学习。这一讲会讲如下一些内容
扩展Spring Data JPA实现自己的一些特殊方法
创建一个自己的BaseRepository
封装Specification来快速完成一些简单的查询操作
封装分页和排序操作。
在一些特殊时候,我们会设计到对Spring Data JPA中的方法进行重新实现,这将会面临一个问题,如果我们新创建一个实现类。如果这个实现类实现了JpaRepository接口,这样我们不得不实现该接口中的所有方法,如果不实现该接口,那意味着我们就无法使用Spring Data JPA中给我们提供的那些好用的方法。所以在扩展的时候我们需要按照如下方法进行。
Spring Data JPA 自定义方法
这些需要注意的是,接口和实现类的名称必须遵循spring data jpa的命名规范,如果要为接口StudentBaseRepository写自定义的接口,首先需要创建一个接口名称为StudentBaseRepositoryCustom,这表示是自定义接口,实现类的名称必须是StudentBaseRepositoryImpl,此时当StudentBaseRepository实现StudentBaseRepositoryCustom之后就可以使用我们自己实现的方法了,同理StudentBaseRepository也可以继承JpaRepository来获取Spring Data Jpa 给我们的方法。
StudentBaseRepositoryCustom代码如下
public interface StudentBaseRepositoryCustom {
//基于原生态的sql进行查询
List
public class StudentBaseRepositoryImpl implements StudentBaseRepositoryCustom {
@Autowired
@PersistenceContext
private EntityManager entityManager;
@Override
public List groupByStudentAsSql() {
List list = entityManager
.createNativeQuery("select address,count(*) from t_student group by address")
.getResultList();
return list;
}
@Override
public List groupByStudentAsHql() {
List list = entityManager
.createQuery("select address,count(*) from Student group by address")
.getResultList();
return list;
}
@Override
public List groupByStudentAsSpecification() {
//根据地址分组查询,并且学生数量大于3的所有地址
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery query = builder.createQuery(Object[].class);
Root root = query.from(Student.class);
query.multiselect(root.get("address"),builder.count(root.get("id")))
.groupBy(root.get("address")).having(builder.gt(builder.count(root.get("id")),3));
return entityManager.createQuery(query).getResultList();
}
}
package org.konghao.repo.base;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
import java.util.List;
/**
* Created by konghao on 2016/12/7.
*/
@NoRepositoryBean
public interface BaseRepository extends JpaRepository {
List listBySQL(String sql);
}
该接口实现了JpaRepository,这样就保证拥有了Spring Data JPA中那些比较好用的方法,然后可以自定义自己需要的方法,代码中定义了一个listBySQL的方法。需要注意的是@NoRepositoryBean,这个表示该接口不会创建这个接口的实例(我们原来定义的StudentPageRepository这些,Spring Data JPA的基础组件都会自动为我们创建一个实例对象,加上这个annotation,spring data jpa的基础组件就不会再为我们创建它的实例)。之后我们编写实现类BaseRepositoryImpl
package org.konghao.repo.base;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import javax.persistence.EntityManager;
import java.io.Serializable;
import java.util.List;
/**
* Created by konghao on 2016/12/7.
*/
public class BaseRepositoryImpl extends SimpleJpaRepository
implements BaseRepository {
private final EntityManager entityManager;
//父类没有不带参数的构造方法,这里手动构造父类
public BaseRepositoryImpl(Class domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
//通过EntityManager来完成查询
@Override
public List listBySQL(String sql) {
return entityManager.createNativeQuery(sql).getResultList();
}
}
/**
* Created by konghao on 2016/11/24.
*/
@EnableJpaRepositories(basePackages = {"org.konghao"},
repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class//指定自己的工厂类
)
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
到这里我们的整个自定义工厂的流程就结束了,我们写一个接口实现BaseRepository即可
/**
* Created by konghao on 2016/12/7.
*/
public interface StudentExtendsRepository extends BaseRepository {
/**
* 原来JPARepository的方法依然可以使用*/
List findByNameAndAddress(String name, String address);
}
测试类中的代码如下
@Test
public void testBaseRepository() {
//直接使用BaseRepository中的方法
List list = studentExtendsRepository.listBySQL("select address,count(*) from t_student group by address");
Assert.assertEquals(2,list.size());
Assert.assertEquals("km",list.get(0)[0]);
//原JpaRepository的方法依然可以使用
List list2 = studentExtendsRepository.findByNameAndAddress("bar","zt");
Assert.assertEquals(1,list2.size());
}
本篇文章重点说明什么是函数柯里化,这个语法现象的背后动机是什么,有什么样的应用场景,以及与部分应用函数(Partial Applied Function)之间的联系 1. 什么是柯里化函数
A way to write functions with multiple parameter lists. For instance
def f(x: Int)(y: Int) is a
ApplicationContext能读取多个Bean定义文件,方法是:
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[]{“bean-config1.xml”,“bean-config2.xml”,“bean-config3.xml”,“bean-config4.xml
#!/bin/bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information re
参考了
http://zhedahht.blog.163.com/blog/static/25411174201142733927831/
但是用java来实现有一个问题。
由于Java无法像C那样“传递参数的地址,函数返回时能得到参数的值”,唯有新建一个辅助类:AuxClass
import ljn.help.*;
public class BalancedBTree {
BeanUtils.copyProperties VS PropertyUtils.copyProperties
作为两个bean属性copy的工具类,他们被广泛使用,同时也很容易误用,给人造成困然;比如:昨天发现同事在使用BeanUtils.copyProperties copy有integer类型属性的bean时,没有考虑到会将null转换为0,而后面的业