- 1. 演示工具版本
- 2. 项目中使用的 Maven 文件
- 3. CrudRepository 接口
- 4. 使用 CrudRepository 的步骤
- 4.1 创建一个扩展 CrudRepository 的接口
- 4.2 JPA 存储库的自动检测
- 4.3 实例化并使用 CrudRepository
- a. Create and Update:
- b. Read:
- c. Delete:
- 5. 自定义存储库方法
- 6. 在 CrudRepository 上使用 @Transactional 注解
- 7. 在 application.properties 文件中配置属性
- 8. Spring Boot REST + Spring Boot Data CrudRepository + JPA + Hibernate + MySQL CRUD 完整示例
- 9. 使用 RestTemplate 的测试代码
- 10. 测试应用程序
- 1. 使用Eclipse
- 2. 使用Maven命令
- 3. 使用可执行的JAR
- 测试
- 参考文献
- 源码下载
本页将介绍Spring Boot CrudRepository的例子。Spring Boot Data默认启用JPA仓库支持。
CrudRepository为特定类型的存储库提供通用的CRUD *** 作。CrudRepository是一个Spring数据接口,要使用它,我们需要通过扩展CrudRepository来创建我们的接口。
Spring在运行时自动提供CrudRepository实现类。它包含的方法有:save, findById, delete, count等。
如果该仓库接口的包与@SpringBootApplication注释的类相同或为其子包,Spring Boot就会自动检测我们的仓库。
当Spring Boot在类路径中扫描Spring Data JPA时,它提供了默认的数据库配置。
Spring Boot使用spring-boot-starter-data-jpa 启动器来配置spring JPA。
对于数据源,我们需要在application.properties中配置以spring.datasource.*开头的数据源属性。
在Spring Boot 2.0版本中,默认的数据库池技术已经从Tomcat Pool切换到HikariCP。在Spring Boot中,首先是HikariCP,然后是Tomcat Pooling,最后是Commons DBCP2(基于可用性)。
在这个页面上,我们将为CRUD *** 作创建一个Spring Boot Rest Web服务。CRUD *** 作将由CrudRepository执行。
现在请看完整的例子。
1. 演示工具版本- Java 9
- Spring 5.0.5.RELEASE
- Spring Boot 2.0.1.RELEASE
- Maven 3.5.2
- MySQL 5.5
- Eclipse Oxygen
找到我们的例子中使用的pom.xml。
3. CrudRepository 接口4.0.0 com.concretepage spring-boot-demo0.0.1-SNAPSHOT jar spring-demo Spring Boot Demo Project org.springframework.boot spring-boot-starter-parent2.0.1.RELEASE 9 org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-data-jpamysql mysql-connector-java6.0.5 javax.xml.bind jaxb-api2.3.0 org.springframework.boot spring-boot-devtoolstrue org.springframework.boot spring-boot-maven-plugin
CrudRepository是一个接口,扩展了Spring data的Repository接口。
CrudRepository为特定类型的存储库提供通用的CRUD *** 作。它有通用的方法用于CRUD *** 作。
为了使用CrudRepository,我们必须创建我们的接口并扩展CrudRepository。
我们不需要实现我们的接口,它的实现将在运行时被自动创建。找到一些CrudRepository的方法。
S save(S entity): 保存和更新当前实体并返回该实体。
Optional
Iterable
long count(): 返回数据的数量。
void delete(T entity): 删除指定的实体。
boolean existsById(ID primaryKey): 检查指定id的实体是否存在。
CrudRepository的扩展接口是PagingAndSortingRepository,它提供了额外的方法来使用分页和排序的抽象来检索实体。
4. 使用 CrudRepository 的步骤Spring boot默认启用JPA仓库支持。为了在我们的Spring data应用程序中使用CrudRepository,我们需要创建一个实现CrudRepository的接口,然后就可以使用它了。让我们逐步讨论如何在Spring data应用程序中使用CrudRepository。
4.1 创建一个扩展 CrudRepository 的接口在我们的例子中,我们将对文章数据进行CRUD *** 作来演示。所以我将为文章创建一个扩展CrudRepository的接口,如下所示。
public interface ArticleRepository extends CrudRepository { }
我们不需要创建它的实现类。Spring会在运行时自动创建其实现类。
4.2 JPA 存储库的自动检测如果该接口的包与@SpringBootApplication注释的类相同或为其子包,Spring boot可以自动检测我们的存储库,如果不是,我们需要使用@EnableJpaRepositories与@SpringBootApplication注释。让我们通过例子来理解。
假设我们在com.concretepage包中有一个用@SpringBootApplication注释的类,如下所示。
package com.concretepage; ------ @SpringBootApplication public class MyApplication { ------ }
现在,如果我们有一个存储库ArticleRepository,并且它存放在com.concretepage包或其子包中,如com.concretepage.repository,那么Spring boot将自动检测到我们的存储库,所以不需要使用@EnableJpaRepositories注解。
如果我们为仓库选择的包既不是相同的包,也不是用@SpringBootApplication注解的类的包的子包,那么Spring boot将无法默认检测仓库类。在这种情况下,我们需要使用@EnableJpaRepositories注解和@SpringBootApplication。使用@EnableJpaRepositories,我们将配置资源库类所在的包名。假设我们的资源库类的包是com.cp.repository,我们将使用@EnableJpaRepositories如下。
package com.concretepage; ------ @SpringBootApplication @EnableJpaRepositories("com.cp.repository") public class MyApplication { ------ }
如果我们想配置特定的类,那么我们需要使用@EnableJpaRepositories注解的basePackageClasses属性。假设我们在com.cp.repository包中有一个ArticleRepository类,那么我们可以使用basePackageClasses配置repository,如下所示。
package com.concretepage; ----- import com.cp.repository.ArticleRepository; @SpringBootApplication @EnableJpaRepositories(basePackageClasses= {ArticleRepository.class}) public class MyApplication { ------ }4.3 实例化并使用 CrudRepository
为了实例化我们扩展了CrudRepository的ArticleRepository,我们可以使用依赖注入。
public class ArticleService { @Autowired private ArticleRepository articleRepository; ------ }
现在我们准备使用CrudRepository的方法。找到它的一些方法的例子。
a. Create and Update:Article savedArticle = articleRepository.save(article);b. Read:
Article obj = articleRepository.findById(articleId).get(); Iterable articles = articleRepository.findAll();c. Delete:
articleRepository.delete(article);5. 自定义存储库方法
CrudRepository提供了通用的CRUD *** 作方法,如果我们想在扩展了CrudRepository的接口中添加自定义方法,我们可以通过以下方式添加。
a. 我们可以用find...By、read...By、query...By、count...By和get...By开始我们的查询方法名称。在By之前,我们可以添加表达式,如Distinct。在By之后,我们需要添加我们实体的属性名称。
b. 为了在一个以上的属性基础上获得数据,我们可以在创建方法名称时使用And和Or将属性名称连接起来。
c. 如果我们想为我们的方法使用完全自定义的名称,我们可以使用@Query注解来编写查询。
查找使用上述场景的示例方法名称的代码段。
public interface ArticleRepository extends CrudRepository { List findByTitle(String title); List findDistinctByCategory(String category); List findByTitleAndCategory(String title, String category); @Query("SELECT a FROM Article a WHERe a.title=:title and a.category=:category") List fetchArticles(@Param("title") String title, @Param("category") String category); }
上述方法的实现类将由Spring在运行时自动创建。
6. 在 CrudRepository 上使用 @Transactional 注解CrudRepository的CRUD方法默认是事务性的。它们在运行时被@Transactional注解和实现类的默认设置所注解。对于读 *** 作,readOnly标志被设置为true。
要覆盖任何CrudRepository方法的默认事务性设置,我们需要在我们的接口中覆盖该方法,并使用所需的配置用@Transactional注解。找到这个例子。
public interface ArticleRepository extends CrudRepository { @Override @Transactional(timeout = 8) Iterable findAll(); }
在这里,我们将超时配置为8秒,以便在findAll()方法中执行没有readOnly标志的查询。
7. 在 application.properties 文件中配置属性数据源、JPA属性和日志等需要在位于Spring boot应用程序类路径中的application.properties文件中进行配置。这些属性将被Spring boot自动读取。
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/concretepage spring.datasource.username=root spring.datasource.password=cp spring.datasource.hikari.connection-timeout=20000 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.maximum-pool-size=12 spring.datasource.hikari.idle-timeout=300000 spring.datasource.hikari.max-lifetime=1200000 spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect spring.jpa.properties.hibernate.id.new_generator_mappings = false spring.jpa.properties.hibernate.format_sql = true logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
Spring-boot-starter-jdbc和spring-boot-starter-data-jpa默认解决HikariCP依赖,spring.datasource.type属性默认值为HikariDataSource。
以spring.datasource.*开头的数据源属性将被Spring boot的JPA自动读取。
要改变Hibernate属性,我们将使用前缀spring.jpa.properties.*与Hibernate属性名称。
在给定的数据源URL的基础上,Spring boot可以自动识别数据源驱动类。所以我们不需要配置驱动类。
spring.data.jpa.repositories.enabled: 它启用JPA存储库。默认值为true。
spring.jpa.database: 它以要 *** 作的数据库为目标。默认情况下,自动检测嵌入式数据库。
spring.jpa.database-platform: 它用于提供要 *** 作的数据库的名称。默认情况下,它是自动检测的。
spring.jpa.generate-ddl: 它用于在启动时初始化schema。默认情况下,该值为false。
spring.jpa.hibernate.ddl-auto: 它是用于嵌入式数据库的DDL模式。默认值是 create-drop。
spring.jpa.hibernate.naming.implicit-strategy: 它是Hibernate 5隐式命名策略的完全限定名。
spring.jpa.hibernate.naming.physical-strategy:它是Hibernate 5物理命名策略的完全限定名。
spring.jpa.hibernate.use-new-id-generator-mappings: 它被用于Hibernate IdentifierGenerator的AUTO、TABLE和SEQUENCE。
spring.jpa.open-in-view: 默认值为true。它将JPA的EntityManager绑定到线程,用于请求的整个处理。
spring.jpa.properties.*: 它设置了额外的本地属性,以便在JPA提供者上设置。
spring.jpa.show-sql: 它可以启用SQL语句的日志记录。默认值是false。
8. Spring Boot REST + Spring Boot Data CrudRepository + JPA + Hibernate + MySQL CRUD 完整示例项目结构
找到我们例子中使用的MySQL数据库表。
Database Table
CREATE DATAbase IF NOT EXISTS `concretepage`; USE `concretepage`; CREATE TABLE IF NOT EXISTS `articles` ( `article_id` bigint(5) NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL, `category` varchar(100) NOT NULL, PRIMARY KEY (`article_id`) ) ENGINE=InnoDB; INSERT INTO `articles` (`article_id`, `title`, `category`) VALUES (1, 'Java Concurrency', 'Java'), (2, 'Spring Boot Getting Started', 'Spring Boot'), (3, 'Lambda expressions Java 8 Example', 'Java 8');
现在找到完整的代码。
ArticleRepository.java
package com.concretepage.repository; import java.util.List; import org.springframework.data.repository.CrudRepository; import com.concretepage.entity.Article; public interface ArticleRepository extends CrudRepository { List findByTitle(String title); List findDistinctByCategory(String category); List findByTitleAndCategory(String title, String category); }
Article.java
package com.concretepage.entity; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="articles") public class Article implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="article_id") private long articleId; @Column(name="title") private String title; @Column(name="category") private String category; public long getArticleId() { return articleId; } public void setArticleId(long articleId) { this.articleId = articleId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } }
IArticleService.java
package com.concretepage.service; import java.util.List; import com.concretepage.entity.Article; public interface IArticleService { List getAllArticles(); Article getArticleById(long articleId); boolean addArticle(Article article); void updateArticle(Article article); void deleteArticle(int articleId); }
ArticleService.java
package com.concretepage.service; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.concretepage.entity.Article; import com.concretepage.repository.ArticleRepository; @Service public class ArticleService implements IArticleService { @Autowired private ArticleRepository articleRepository; @Override public Article getArticleById(long articleId) { Article obj = articleRepository.findById(articleId).get(); return obj; } @Override public List getAllArticles(){ List list = new ArrayList<>(); articleRepository.findAll().forEach(e -> list.add(e)); return list; } @Override public synchronized boolean addArticle(Article article){ List list = articleRepository.findByTitleAndCategory(article.getTitle(), article.getCategory()); if (list.size() > 0) { return false; } else { articleRepository.save(article); return true; } } @Override public void updateArticle(Article article) { articleRepository.save(article); } @Override public void deleteArticle(int articleId) { articleRepository.delete(getArticleById(articleId)); } }
ArticleController.java
package com.concretepage.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.util.UriComponentsBuilder; import com.concretepage.entity.Article; import com.concretepage.service.IArticleService; @Controller @RequestMapping("user") public class ArticleController { @Autowired private IArticleService articleService; @GetMapping("article/{id}") public ResponseEntity getArticleById(@PathVariable("id") Integer id) { Article article = articleService.getArticleById(id); return new ResponseEntity(article, HttpStatus.OK); } @GetMapping("articles") public ResponseEntitygetAllArticles() { List list = articleService.getAllArticles(); return new ResponseEntity
(list, HttpStatus.OK); } @PostMapping("article") public ResponseEntity
addArticle(@RequestBody Article article, UriComponentsBuilder builder) { boolean flag = articleService.addArticle(article); if (flag == false) { return new ResponseEntity (HttpStatus.CONFLICT); } HttpHeaders headers = new HttpHeaders(); headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri()); return new ResponseEntity (headers, HttpStatus.CREATED); } @PutMapping("article") public ResponseEntity updateArticle(@RequestBody Article article) { articleService.updateArticle(article); return new ResponseEntity(article, HttpStatus.OK); } @DeleteMapping("article/{id}") public ResponseEntity deleteArticle(@PathVariable("id") Integer id) { articleService.deleteArticle(id); return new ResponseEntity (HttpStatus.NO_CONTENT); } }
MyApplication.java
package com.concretepage; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }9. 使用 RestTemplate 的测试代码
RestClientUtil.java
package com.concretepage.client; import java.net.URI; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import com.concretepage.entity.Article; public class RestClientUtil { public void getArticleByIdDemo() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/article/{id}"; HttpEntity10. 测试应用程序requestEntity = new HttpEntity (headers); ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article.class, 1); Article article = responseEntity.getBody(); System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle() +", Category:"+article.getCategory()); } public void getAllArticlesDemo() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/articles"; HttpEntity requestEntity = new HttpEntity (headers); ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article[].class); Article[] articles = responseEntity.getBody(); for(Article article : articles) { System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle() +", Category: "+article.getCategory()); } } public void addArticleDemo() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/article"; Article objArticle = new Article(); objArticle.setTitle("Spring REST Security using Hibernate"); objArticle.setCategory("Spring"); HttpEntity requestEntity = new HttpEntity(objArticle, headers); URI uri = restTemplate.postForLocation(url, requestEntity); System.out.println(uri.getPath()); } public void updateArticleDemo() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/article"; Article objArticle = new Article(); objArticle.setArticleId(1); objArticle.setTitle("Update:Java Concurrency"); objArticle.setCategory("Java"); HttpEntity requestEntity = new HttpEntity(objArticle, headers); restTemplate.put(url, requestEntity); } public void deleteArticleDemo() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); RestTemplate restTemplate = new RestTemplate(); String url = "http://localhost:8080/user/article/{id}"; HttpEntity requestEntity = new HttpEntity(headers); restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Void.class, 4); } public static void main(String args[]) { RestClientUtil util = new RestClientUtil(); //util.getArticleByIdDemo(); //util.addArticleDemo(); //util.updateArticleDemo(); //util.deleteArticleDemo(); util.getAllArticlesDemo(); } }
为了测试该应用程序,首先在MySQL中创建表,如例子中给出的。现在我们可以通过以下方式运行REST网络服务。
1. 使用Eclipse使用页面末尾的下载链接下载项目的源代码。
将该项目导入eclipse。
使用命令提示符,进入项目的根文件夹并运行。
mvn clean eclipse:eclipse
然后在eclipse中刷新该项目。点击Run as -> Java Application来运行主类MyApplication。
Tomcat服务器将被启动。
2. 使用Maven命令下载项目的源代码。使用命令提示符进入项目的根文件夹并运行命令。
mvn spring-boot:run
Tomcat服务器将被启动。
3. 使用可执行的JAR使用命令提示符,转到项目的根文件夹并运行该命令。
mvn clean package
我们将在目标文件夹中得到可执行的spring-boot-demo-0.0.1-SNAPSHOT.jar。以下列方式运行这个JAR。
java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar
Tomcat服务器将被启动。
测试现在我们已经准备好测试这个应用程序了。要运行客户端,在eclipse中进入RestClientUtil类,点击Run as -> Java Application。
我们也可以用Postman测试应用程序。
【1】Accessing Data with JPA
【2】Spring Boot REST + JPA + Hibernate + MySQL Example
【3】Spring Data CrudRepository Example
【4】Spring Boot CrudRepository Example
提取码:mao4
spring-boot-crudrepository-example.zip
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)