文章目录

  • 演示工具版本
  • MySQL 数据库架构
  • 项目结构
  • Maven 文件
  • 在 application.properties 文件中配置属性
  • 创建 DAO
  • 创建 Service
  • 创建 Controller
  • 创建 Main类
  • 创建测试类
  • 测试应用程序
  • 1. 使用Eclipse
  • 2. 使用Maven命令
  • 3. 使用可执行的JAR
  • 测试
  • 参考文献
  • 源码下载

本页将介绍spring boot REST + JPA + hibernate + MySQL的例子。在这里,我们将创建一个REST应用程序,使用MySQL执行CRUD操作。Spring boot在扫描类路径中的Spring Data JPA时提供了默认的数据库配置。Spring boot使用spring-boot-starter-data-jpa 启动器来配置Spring JPA和hibernate。对于数据源,我们需要在application.properties中配置以spring.datasource.*开头的数据源属性,spring boot JPA将自动配置数据源。Spring boot 1.x首先选择Tomcat池,然后是HikariCP,最后是Commons DBCP(基于可用性)。我们不需要编写spring配置类,只需要在application.properties中配置属性就可以了。在我们的DAO类中,我们可以使用依赖性注入来获得EntityManager的实例。为了运行应用程序,我们将创建一个带有main()方法的类,它将调用SpringApplication.run()来启动嵌入Tomcat的应用程序。带有main()方法的类将被注解为@SpringBootApplication。在我们的应用程序中,在客户端我们将使用RestTemplate来消费REST的Web服务。现在请看完整的例子。

演示工具版本

  1. Java 8
  2. Spring Boot 1.5.2.RELEASE
  3. Maven 3.3
  4. MySQL 5.5
  5. Eclipse Mars

MySQL 数据库架构

找到带有初始数据的数据库架构。

Database Schema

-- Dumping database structure for concretepage
CREATE DATABASE IF NOT EXISTS `concretepage`;
USE `concretepage`;
-- Dumping structure for table concretepage.articles
CREATE TABLE IF NOT EXISTS `articles` (
  `article_id` int(5) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL,
  `category` varchar(100) NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.articles: ~3 rows (approximately)
INSERT INTO `articles` (`article_id`, `title`, `category`) VALUES
	(1, 'Java Concurrency', 'Java'),
	(2, 'Hibernate HQL ', 'Hibernate'),
	(3, 'Spring MVC with Hibernate', 'Spring');

查找给定表的JPA实体。

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 int articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public int getArticleId() {
		return articleId;
	}
	public void setArticleId(int 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;
	}
}

项目结构

springboot引入海豚调度_mysql

Maven 文件

查找示例中使用的maven文件。

pom.xml

<?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.concretepage</groupId>
	<artifactId>spring-boot-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>spring-demo</name>
	<description>Spring Boot Demo Project</description>
	<parent>
	   <groupId>org.springframework.boot</groupId>
	   <artifactId>spring-boot-starter-parent</artifactId>
	   <version>1.5.2.RELEASE</version>
	</parent>
	<properties>
	   <java.version>1.8</java.version>
	</properties>
	<dependencies>
	    <dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-web</artifactId>
	    </dependency>
	    <dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-data-jpa</artifactId>
	    </dependency>	
	    <dependency>
		    <groupId>mysql</groupId>
		    <artifactId>mysql-connector-java</artifactId>
	    </dependency>	 
    	    <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-devtools</artifactId>
                    <optional>true</optional>
            </dependency> 
	</dependencies> 
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

maven文件中配置的spring boot启动器的描述。spring-boot-starter-parent : 用于依赖关系管理的父POM。

spring-boot-starter-web: 构建Web、REST应用程序的启动器。它使用Tomcat服务器作为默认的嵌入式服务器。

spring-boot-starter-data-jpa: 具备hibernate的spring data JPA的启动程序。

spring-boot-devtools : 它提供了开发者工具。这些工具在应用开发模式中很有帮助。开发者工具的一个特点是在代码发生任何变化时自动重新启动服务器,即热部署。

spring-boot-maven-plugin : 它用于创建应用程序的可执行JAR。

在 application.properties 文件中配置属性

与数据库、hibernate和日志相关的属性需要在application.properties文件中进行配置。这些属性将被Spring boot自动读取。

application.properties

#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/concretepage
spring.datasource.username=root
spring.datasource.password=
spring.datasource.tomcat.max-wait=20000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.max-idle=20
spring.datasource.tomcat.min-idle=15

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.datasource.*开头的数据源属性将被Spring boot JPA自动读取。要改变Hibernate属性,我们将使用前缀spring.jpa.properties.*与Hibernate属性名称。在给定的数据源URL的基础上,Spring boot可以自动识别数据源驱动类。所以我们不需要配置驱动类。

在application.properties中找到配置JpaBaseConfiguration和HibernateJpaAutoConfiguration的属性。

spring.data.jpa.repositories.enabled: 它启用JPA存储库。默认值为true。

spring.jpa.database: 它的目标是要操作的数据库。默认情况下,嵌入式数据库是自动检测的。

spring.jpa.database-platform: 它用于提供要操作的数据库的名称。默认情况下,它是自动检测的。

spring.jpa.generate-ddl: 它用于在启动时初始化模式。默认情况下,该值为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。

创建 DAO

找到例子中使用的DAO来执行CRUD操作。为了注入EntityManager的实例,我们将使用@PersistenceContext。

IArticleDAO.java

package com.concretepage.dao;
import java.util.List;
import com.concretepage.entity.Article;
public interface IArticleDAO {
    List<Article> getAllArticles();
    Article getArticleById(int articleId);
    void addArticle(Article article);
    void updateArticle(Article article);
    void deleteArticle(int articleId);
    boolean articleExists(String title, String category);
}

ArticleDAO.java

package com.concretepage.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.Article;
@Transactional
@Repository
public class ArticleDAO implements IArticleDAO {
	@PersistenceContext	
	private EntityManager entityManager;	
	@Override
	public Article getArticleById(int articleId) {
		return entityManager.find(Article.class, articleId);
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<Article> getAllArticles() {
		String hql = "FROM Article as atcl ORDER BY atcl.articleId";
		return (List<Article>) entityManager.createQuery(hql).getResultList();
	}	
	@Override
	public void addArticle(Article article) {
		entityManager.persist(article);
	}
	@Override
	public void updateArticle(Article article) {
		Article artcl = getArticleById(article.getArticleId());
		artcl.setTitle(article.getTitle());
		artcl.setCategory(article.getCategory());
		entityManager.flush();
	}
	@Override
	public void deleteArticle(int articleId) {
		entityManager.remove(getArticleById(articleId));
	}
	@Override
	public boolean articleExists(String title, String category) {
		String hql = "FROM Article as atcl WHERE atcl.title = ? and atcl.category = ?";
		int count = entityManager.createQuery(hql).setParameter(1, title)
		              .setParameter(2, category).getResultList().size();
		return count > 0 ? true : false;
	}
}

创建 Service

找到我们例子中使用的服务类。

IArticleService.java

package com.concretepage.service;
import java.util.List;
import com.concretepage.entity.Article;
public interface IArticleService {
     List<Article> getAllArticles();
     Article getArticleById(int articleId);
     boolean addArticle(Article article);
     void updateArticle(Article article);
     void deleteArticle(int articleId);
}

ArticleService.java

package com.concretepage.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IArticleDAO;
import com.concretepage.entity.Article;
@Service
public class ArticleService implements IArticleService {
	@Autowired
	private IArticleDAO articleDAO;
	@Override
	public Article getArticleById(int articleId) {
		Article obj = articleDAO.getArticleById(articleId);
		return obj;
	}	
	@Override
	public List<Article> getAllArticles(){
		return articleDAO.getAllArticles();
	}
	@Override
	public synchronized boolean addArticle(Article article){
                if (articleDAO.articleExists(article.getTitle(), article.getCategory())) {
    	            return false;
                } else {
    	            articleDAO.addArticle(article);
    	            return true;
                }
	}
	@Override
	public void updateArticle(Article article) {
		articleDAO.updateArticle(article);
	}
	@Override
	public void deleteArticle(int articleId) {
		articleDAO.deleteArticle(articleId);
	}
}

创建 Controller

找到将暴露网络服务方法的控制器类。

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<Article> getArticleById(@PathVariable("id") Integer id) {
		Article article = articleService.getArticleById(id);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@GetMapping("articles")
	public ResponseEntity<List<Article>> getAllArticles() {
		List<Article> list = articleService.getAllArticles();
		return new ResponseEntity<List<Article>>(list, HttpStatus.OK);
	}
	@PostMapping("article")
	public ResponseEntity<Void> addArticle(@RequestBody Article article, UriComponentsBuilder builder) {
                boolean flag = articleService.addArticle(article);
                if (flag == false) {
        	    return new ResponseEntity<Void>(HttpStatus.CONFLICT);
                }
                HttpHeaders headers = new HttpHeaders();
                headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri());
                return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
	}
	@PutMapping("article")
	public ResponseEntity<Article> updateArticle(@RequestBody Article article) {
		articleService.updateArticle(article);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@DeleteMapping("article/{id}")
	public ResponseEntity<Void> deleteArticle(@PathVariable("id") Integer id) {
		articleService.deleteArticle(id);
		return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
	}	
}

我们为CRUD操作创建了以下网址。1. Create : HTTP Method: POST, URL: /user/article

2. Read : HTTP Method: GET, URL: /user/article/{id} HTTP Method: GET, URL: /user/articles

3. Update : HTTP Method: PUT, URL: /user/article

4. Delete : HTTP Method: DELETE, URL: /user/article/{id}

创建 Main类

创建一个带有main()方法的类,它将调用SpringApplication.run()来运行该应用程序。首先下载所有的JAR依赖项,然后编译项目,再启动嵌入式tomcat服务器。

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);
        }       
}

我们需要用@SpringBootApplication注解来注解这个类,它相当于@Configuration、@EnableAutoConfiguration和@ComponentScan注解。

创建测试类

找到将消费REST网络服务的客户端。我们正在使用RestTemplate与REST web服务服务器进行通信。

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}";
        HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article> 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<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article[]> 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<Article> requestEntity = new HttpEntity<Article>(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<Article> requestEntity = new HttpEntity<Article>(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<Article> requestEntity = new HttpEntity<Article>(headers);
        restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Void.class, 4);        
    }
    public static void main(String args[]) {
    	RestClientUtil util = new RestClientUtil();
        //util.getArticleByIdDemo();
    	util.getAllArticlesDemo();
    	//util.addArticleDemo();
    	//util.updateArticleDemo();
    	//util.deleteArticleDemo();
    }    
}

测试应用程序

为了测试该应用程序,首先在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测试应用程序。

springboot引入海豚调度_springboot引入海豚调度_02

参考文献

【1】Working with SQL databases【2】Spring Boot REST + JPA + Hibernate + MySQL Example

源码下载

提取码:mao4

spring-boot-rest-jpa-hibernate-mysql-example.zip