参考文档:https://blog.csdn.net/xiao_xuwen/article/details/53579353
在一些特殊时候,我们会设计到对Spring Data JPA中的方法进行重新实现,这将会面临一个问题,如果我们新创建一个实现类。如果这个实现类实现了JpaRepository接口,这样我们不得不实现该接口中的所有方法,如果不实现该接口,那意味着我们就无法使用Spring Data JPA中给我们提供的那些好用的方法。所以在扩展的时候我们需要按照如下方法进行。
这些需要注意的是,接口和实现类的名称必须遵循spring data jpa的命名规范,如果要为接口StudentBaseRepository
写自定义的接口,首先需要创建一个接口名称为StudentBaseRepositoryCustom
,这表示是自定义接口,实现类的名称必须是StudentBaseRepositoryImpl
,此时当StudentBaseRepository
实现StudentBaseRepositoryCustom
之后就可以使用我们自己实现的方法了,同理StudentBaseRepository
也可以继承JpaRepository
来获取Spring Data Jpa 给我们的方法。(以上为参考信息)
1.项目结构
2. pom文件修改
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 6 <groupId>com.lch</groupId> 7 <artifactId>springboot04</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 <packaging>jar</packaging> 10 11 <name>springboot04</name> 12 <description>Demo project for Spring Boot</description> 13 14 <parent> 15 <groupId>org.springframework.boot</groupId> 16 <artifactId>spring-boot-starter-parent</artifactId> 17 <version>2.0.2.RELEASE</version> 18 <relativePath/> <!-- lookup parent from repository --> 19 </parent> 20 21 <properties> 22 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 23 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 24 <java.version>1.8</java.version> 25 </properties> 26 27 <dependencies> 28 <dependency> 29 <groupId>org.springframework.boot</groupId> 30 <artifactId>spring-boot-starter-data-jpa</artifactId> 31 </dependency> 32 <dependency> 33 <groupId>org.springframework.boot</groupId> 34 <artifactId>spring-boot-starter-web</artifactId> 35 </dependency> 36 37 <dependency> 38 <groupId>mysql</groupId> 39 <artifactId>mysql-connector-java</artifactId> 40 </dependency> 41 42 <dependency> 43 <groupId>org.springframework.boot</groupId> 44 <artifactId>spring-boot-starter-test</artifactId> 45 <scope>test</scope> 46 </dependency> 47 <!-- 对象转json依赖包 --> 48 <!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib --> 49 <dependency> 50 <groupId>net.sf.json-lib</groupId> 51 <artifactId>json-lib</artifactId> 52 <version>2.4</version> 53 <!--不加下面这一项会报错,是因为json-lib支持版本是jdk1.5,所以要指定下版本--> 54 <classifier>jdk15</classifier> 55 </dependency> 56 57 58 </dependencies> 59 60 <build> 61 <plugins> 62 <plugin> 63 <groupId>org.springframework.boot</groupId> 64 <artifactId>spring-boot-maven-plugin</artifactId> 65 </plugin> 66 </plugins> 67 </build> 68 69 70 </project>
修改完毕,在IDEA 工具栏 依次点击view , toolwindows, maven projects 打开maven管理窗口,点击刷新按钮,下载pom文件配置的依赖jar包
3. 数据库配置文件:连接本机mysql数据库
1 spring.datasource.url=jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true 2 spring.datasource.username=root 3 spring.datasource.password=root 4 spring.datasource.driver-class-name=com.mysql.jdbc.Driver 5 6 spring.jpa.properties.hibernate.hbm2ddl.auto=update 7 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 8 spring.jpa.show-sql= true 9 #关闭thymeleaf的缓存,不然在开发过程中修改页面不会立刻生效需要重启,生产可配置为true 10 spring.thymeleaf.cache=false
4. 实体类映射数据库表,主键策略使用 GenerationType.AUTO ,即由hibernate选择主键策略
1 package com.lch.springboot04.domain; 2 3 import javax.persistence.*; 4 5 /** 6 * 实体类映射数据库表 7 */ 8 @Entity 9 @Table(name="user_test") 10 public class User { 11 @Id 12 @GeneratedValue(strategy = GenerationType.AUTO) //hibernate选择主键策略 13 private Long id; 14 15 @Column(nullable = false) 16 private String password; 17 //name="username" 设置userName属性映射到数据库的username字段,而不是默认的user_name 18 @Column(name = "username", nullable = false) 19 private String userName; 20 21 @Column(nullable = false) 22 private int age; 23 24 public Long getId() { 25 return id; 26 } 27 28 public void setId(Long id) { 29 this.id = id; 30 } 31 32 public String getPassword() { 33 return password; 34 } 35 36 public void setPassword(String password) { 37 this.password = password; 38 } 39 40 public String getUserName() { 41 return userName; 42 } 43 44 public void setUserName(String userName) { 45 this.userName = userName; 46 } 47 48 public int getAge() { 49 return age; 50 } 51 52 public void setAge(int age) { 53 this.age = age; 54 } 55 56 public User() { 57 } 58 59 public User(String password, String userName, int age) { 60 this.password = password; 61 this.userName = userName; 62 this.age = age; 63 } 64 }
5. 在 repository 包下 自定义原生sql 查询接口
1 package com.lch.springboot04.repository; 2 3 import org.springframework.data.jpa.repository.JpaRepository; 4 import org.springframework.data.repository.NoRepositoryBean; 5 6 import java.io.Serializable; 7 import java.util.List; 8 import java.util.Map; 9 10 /** 11 * 原生sql 查询接口 12 * @param <T> 13 * @param <ID> 14 */ 15 @NoRepositoryBean 16 public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID> { 17 18 List<T> listBySql(String sql); 19 20 List listObjectBySql(String sql); 21 22 <S> List<S> listBySql(String sql,Class<T> clazz); 23 24 List<Map<String,Object>> listMapBySql(String sql); 25 26 Object getObjectBySql(String sql); 27 28 int executeSql(String sql); 29 30 }
6. 在repo包下建立 UserRepository ,继承BaseRepository
1 package com.lch.springboot04.repo; 2 3 import com.lch.springboot04.domain.User; 4 import com.lch.springboot04.repository.BaseRepository; 5 6 public interface UserRepository extends BaseRepository<User,Long> { 7 }
7. 在repo包下建base包,建BaseRepositoryImpl 类 和 BaseRepositoryFactoryBean 类
1 package com.lch.springboot04.repo.base; 2 3 import com.lch.springboot04.repository.BaseRepository; 4 import org.hibernate.SQLQuery; 5 import org.hibernate.criterion.CriteriaSpecification; 6 import org.springframework.data.jpa.repository.support.SimpleJpaRepository; 7 8 import javax.persistence.EntityManager; 9 import java.io.Serializable; 10 import java.util.List; 11 import java.util.Map; 12 13 public class BaseRepositoryImpl<T, ID extends Serializable> 14 extends SimpleJpaRepository<T, ID> 15 implements BaseRepository<T, ID> { 16 17 private final EntityManager entityManager; 18 private Class<T> clazz; 19 20 public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) { 21 super(domainClass, entityManager); 22 this.clazz = domainClass; 23 this.entityManager = entityManager; 24 } 25 26 @Override 27 public List<T> listBySql(String sql) { 28 return entityManager.createNamedQuery(sql, clazz).getResultList(); 29 } 30 31 @Override 32 public List listObjectBySql(String sql) { 33 return entityManager.createNativeQuery(sql).getResultList(); 34 } 35 36 @Override 37 public <S> List<S> listBySql(String sql, Class<T> clazz) { 38 return entityManager.createNativeQuery(sql, clazz).getResultList(); 39 } 40 41 @Override 42 public List<Map<String, Object>> listMapBySql(String sql) { 43 return entityManager.createNativeQuery(sql).unwrap(SQLQuery.class).setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP).list(); 44 } 45 46 @Override 47 public Object getObjectBySql(String sql) { 48 List<Object[]> list = entityManager.createNativeQuery(sql).getResultList(); 49 if (list != null && list.size() > 0 && list.get(0) != null) { 50 return list.get(0); 51 } 52 return null; 53 } 54 55 @Override 56 public int executeSql(String sql) { 57 return entityManager.createNativeQuery(sql).executeUpdate(); 58 } 59 }
1 package com.lch.springboot04.repo.base; 2 3 import org.springframework.data.jpa.repository.JpaRepository; 4 import org.springframework.data.jpa.repository.support.JpaRepositoryFactory; 5 import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; 6 import org.springframework.data.repository.core.RepositoryInformation; 7 import org.springframework.data.repository.core.RepositoryMetadata; 8 import org.springframework.data.repository.core.support.RepositoryFactorySupport; 9 10 import javax.persistence.EntityManager; 11 import java.io.Serializable; 12 13 /** 14 * 参考 https://www.tianmaying.com/tutorial/spring-jpa-custom-all 15 * @param <R> 16 * @param <T> 17 * @param <I> 18 */ 19 public class BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> 20 extends JpaRepositoryFactoryBean<R, T, I> { 21 22 public BaseRepositoryFactoryBean(Class<? extends R> repositoryInterface) { 23 super(repositoryInterface); 24 } 25 26 @Override 27 protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { 28 return new BaseRepositoryFactory(entityManager); 29 } 30 31 private static class BaseRepositoryFactory<T,I extends Serializable> extends JpaRepositoryFactory { 32 private final EntityManager entityManager; 33 34 public BaseRepositoryFactory(EntityManager entityManager) { 35 super(entityManager); 36 this.entityManager = entityManager; 37 } 38 39 @Override 40 protected Object getTargetRepository(RepositoryInformation information) { 41 return new BaseRepositoryImpl<T,I>((Class<T>) information.getDomainType(),entityManager); 42 } 43 44 @Override 45 protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { 46 return BaseRepositoryImpl.class; 47 } 48 } 49 50 }
8. 建立config包,编写配置类
1 package com.lch.springboot04.config; 2 3 import com.lch.springboot04.repo.base.BaseRepositoryFactoryBean; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 6 7 /** 8 * 配置类,不配置,会报错,找不到bean 9 */ 10 @Configuration 11 //指定自己的工厂类 12 @EnableJpaRepositories(basePackages = {"com.lch.springboot04"}, 13 repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class) 14 public class RepositoryConfig { 15 }
9. service层 ,注入 UserRepository 实例,这里实现查询所有user, 以 List<Map<String, Object>> 格式返回数据
1 package com.lch.springboot04.service; 2 3 import com.lch.springboot04.repo.UserRepository; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Service; 6 7 import java.util.List; 8 import java.util.Map; 9 10 @Service 11 public class UserService { 12 @Autowired 13 UserRepository userRepository; 14 15 public List<Map<String, Object>> getAll() { 16 String sql = "select * from user"; 17 return userRepository.listMapBySql(sql); 18 } 19 20 }
10.controller层
1 package com.lch.springboot04.controller; 2 3 import com.lch.springboot04.service.UserService; 4 import net.sf.json.JSONArray; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.web.bind.annotation.RequestMapping; 7 import org.springframework.web.bind.annotation.RestController; 8 9 import java.util.List; 10 import java.util.Map; 11 12 13 @RestController 14 @RequestMapping("/user") 15 public class UserController { 16 17 @Autowired 18 UserService userService; 19 20 @RequestMapping("/index") 21 public String index(){ 22 return "success"; 23 } 24 @RequestMapping("/getall") 25 public String getAll(){ 26 List<Map<String, Object>> users = userService.getAll(); 27 return JSONArray.fromObject(users).toString(); 28 } 29 30 }
JSONArray.fromObject(users).toString(); 把list 转换为json数组返回给请求调用者。
11.springboot 启动类,不用动
1 package com.lch.springboot04; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 @SpringBootApplication 7 public class Springboot04Application { 8 public static void main(String[] args) { 9 SpringApplication.run(Springboot04Application.class, args); 10 } 11 }
启动项配置
配好之后启动项目,启动完成,会显示所使用的端口号
访问 http://localhost:8080/user/getall 结果如下:(数据库中事先有数据)