Spring Boot整合JPA
一、POM
<?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>com.squirrel</groupId>
<artifactId>squirrel-web</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- Spring boot 父引用-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<!-- Spring boot 核心web-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
</dependencies>
</project>
二、配置文件
#监听端口号
server.port=8888
#用户会话session过期时间,以秒为单位
server.session-timeout=7200
#数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#输出日志级别
logging.level.org.springframework.web=DEBUG
#JPA
#1表结构:update自动更新,none不采取措施
spring.jpa.hibernate.ddl-auto=update
#2显示sql
spring.jpa.show-sql=true
#3让控制器输出的json字符格式更美观
spring.jackson.serialization.indent-output=true
三、启动类
package com.squirrel;
import com.squirrel.support.CustomRepositoryFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@ComponentScan(basePackages={"com.squirrel"})
@EnableJpaRepositories(repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
四、entity
package com.squirrel.entity;
import javax.persistence.*;
@Entity
public class User {
private Long id;
private String name;
private Integer age;
public User() {
super();
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
@Id
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
五、分页模糊查询方法封装
package com.squirrel.specs;
import static com.google.common.collect.Iterables.toArray;
import com.squirrel.entity.User;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.SingularAttribute;
public class CustomerSpecs {
/**
* 1.定义一个返回值为Specification的方法byAuto,这里使用的是泛型 T,所以这个Specification是可以用于任意的实体类的,
* 它接受的参数是entityManager和当前的包含值作为查询条件的实体类对象
*/
public static <T> Specification<T> byAuto(final EntityManager entityManager,final T example){
/**
* 2.获得当前实体类对象类的类型
*/
final Class<T> type = (Class<T>) example.getClass();
return new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
/**
* 3.新建Predicate列表存储构造的查询条件
*/
List<Predicate> predicates = new ArrayList<>();
/**
* 4.获取实体类的EntityType,我们可以从EntityType获取实体类的属性
*/
EntityType<T> entity = entityManager.getMetamodel().entity(type);
/**
* 5.对实体类的所有属性做循环
*/
for (Attribute<T,?> attr : entity.getDeclaredAttributes()) {
/**
* 6.获得实体类对象某一个属性的值
*/
Object attrValue = getValue(example, attr);
if(attrValue != null){
/**
* 7.当前属性值为字符类型的时候
*/
if(attr.getJavaType() == String.class) {
/**
* 8.若当前字符不为空的情况下
*/
if(!StringUtils.isEmpty(attrValue)){
/**
* 构造当前属性like(前后%)属性值查询条件,并添加到条件列表中
*/
predicates.add(cb.like(root.get(attribute(entity, attr.getName(),String.class)),panttern((String) attrValue)));
}
}else{
/**
* 10.其余情况下,构造属性和属性值equal查询条件,并添加到条件列表中
*/
predicates.add(cb.equal(root.get(attribute(entity, attr.getName(),attrValue.getClass())),attrValue));
}
}
}
/**
* 11.将条件列表转换成Predicate
*/
return predicates.isEmpty() ? cb.conjunction() : cb.and(toArray(predicates, Predicate.class));
}
/**
* 12.通过反射获得实体类对象对应属性的属性值
*/
private <T> Object getValue(T example, Attribute<T, ?> attr){
Field field = null;
try {
field = example.getClass().getDeclaredField(attr.getName());
//设置对象的访问权限,保证对private的属性的访问
field.setAccessible(true);
return ReflectionUtils.getField(field,example);
} catch (NoSuchFieldException e) {
e.printStackTrace();
return null;
}
}
/**
* 13.获得实体类的当前属性的SingularAttribute,SingularAttribute包含的是实体类的某个单独属性
*/
private <E,T> SingularAttribute<T, E> attribute(EntityType<T> entity, String fileName, Class<E> fieldClass) {
return entity.getDeclaredSingularAttribute(fileName,fieldClass);
}
};
}
/**
* 14.构造like的查询模式,即前后加%
*/
static private String panttern(String str) {
return "%" + str + "%";
}
}
package com.squirrel.support;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
@NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID> ,JpaSpecificationExecutor<T> {
Page<T> findByAuto(T example, Pageable pageable);
}
package com.squirrel.support;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import javax.persistence.EntityManager;
import java.io.Serializable;
import static com.squirrel.specs.CustomerSpecs.*;
public class CustomRepositoryImpl <T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements
CustomRepository<T,ID> {
private final EntityManager entityManager;
public CustomRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
@Override
public Page<T> findByAuto(T example, Pageable pageable) {
return findAll(byAuto(entityManager, example),pageable);
}
}
package com.squirrel.support;
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
public class CustomRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable>
extends JpaRepositoryFactoryBean<T, S, ID>{
public CustomRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager){
return new CustomRepositoryFactory(entityManager);
}
private static class CustomRepositoryFactory extends JpaRepositoryFactory{
public CustomRepositoryFactory(EntityManager entityManager){
super(entityManager);
}
@Override
@SuppressWarnings({"unchecked"})
protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager){
return new CustomRepositoryImpl<T, ID>((Class<T>) information.getDomainType(), entityManager);
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata){
return CustomRepositoryImpl.class;
}
}
}
六、DAO
package com.squirrel.dao;
import com.squirrel.entity.User;
import com.squirrel.support.CustomRepository;
import java.util.List;
public interface UserDao extends CustomRepository<User, Long> {
List<User> findByName(String name);
}
七、controller
package com.squirrel.controller;
import com.squirrel.dao.UserDao;
import com.squirrel.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("user")
public class UserController {
private final Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserDao userDao;
@RequestMapping("/getName")
public List<User> getName (){
log.info("访问/user/getName接口成功");
List<User> users = userDao.findByName("哈哈");
return users;
}
@RequestMapping("/insert")
public String insert (){
log.info("访问/user/insert接口成功");
User user = new User();
user.setName("是我");
user.setAge(18);
userDao.save(user);
return "插入成功";
}
@RequestMapping("/sort")
public List<User> sort (){
log.info("访问/user/sort接口成功");
List<User> users = userDao.findAll(new Sort(Sort.Direction.DESC,"age"));
return users;
}
@RequestMapping("/page")
public Page<User> page (){
log.info("访问/user/sort接口成功");
Page<User> userPage = userDao.findAll(new PageRequest(10, 2));
return userPage;
}
@RequestMapping("/auto")
public Page<User> auto(User user){
log.info("访问/user/auto接口成功");
Page<User> userPage = userDao.findByAuto(user, new PageRequest(0, 10));
return userPage;
}
}