網頁

2019/5/19

Spring Boot 2 + Spring Data JPA + MySQL 8 簡單範例

本篇說明如何建立Spring Boot 2Spring Data JPAMySQL進行基本操作的專案。

首先安裝STS(Spring Tool Suite)或在Eclipse安裝STS plugin


然後電腦中要安裝好MySQL資料庫(本範例安裝版本為8.0.11),啟動,並建立一個mydb資料庫(schema)。

接著建立一個Spring Boot專案,在Eclipse功能選單選擇 File -> New -> Spring Starter Project



將專案Maven資訊填寫如下後按Next >



在SQL項下找到JPA,勾選後按Finish



預設的pom.xml內容如下,(如果你的pom.xml第一行有出現未知的錯誤,請參考Eclipse Maven pom.xml Maven Configuration Problem: Unknown

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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.abc</groupId>
    <artifactId>spring-data-jpa-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-data-jpa-demo</name>
    <description>Spring Boot With Spring Data JPA</description>

    <properties>
        <java.version>1.8</java.version>
        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version><!-- 加上這個 -->
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

因為要連接MySQL資料庫,所以要在<dependencies>中加入MySQL JDBC connector J的依賴。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

接著開啟Spring Boot預設放在src/main/resources下的application.properties設定檔,加入MySQL的datasource連線及JPA等設定如下。

以下我改用application.yml來設定。

application.yml

# DataSource配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: matt
    password: 12345
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    database-platform: org.hibernate.dialect.MySQL8Dialect
    hibernate:
      ddl-auto: update

相當於

application.properties

# DataSource配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=matt
spring.datasource.password=12345
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# hibernate 5.3.1後新增了MYSQL8Dialect
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update

接著建立以下幾個類別及介面。



  • com.abc.app.entity.Customer
  • com.abc.app.model.CustomerBo
  • com.abc.app.dao.CustomerDao
  • com.abc.app.service.CustomerService

Customer類別為ORM的實體(Entity)類,所以類別名稱上要掛@Entity,因此會與mydb.customer資料表互相映射。主鍵為掛上@Idid屬性。

Customer

package com.abc.app.entity;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Customer {

    @Id
    private Long id;
    private String name;
    private String address;

    @Override
    public String toString() {
        return String.format("Customer[id=%d, name='%s', address='%s']", id,
                name, address);
    }

    // getters and setters...
}

CustomerBo為從資料庫取回Customer實體後,負責裝載Service層處理商業邏輯時的Model類別

CustomerBo

package com.abc.app.model;

public class CustomerBo {

    private Long id;
    private String name;
    private String address;

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("id:" + id + ",");
        sb.append("name:" + name + ",");
        sb.append("address:" + address);
        return sb.toString();
    }
    
    // getters and setters...
}

CustomerDao為掛有@Repository的資料存取層,負責對資料庫進行存取,這邊繼承了Spring Data的CrudRepository,所以預設會有基本的CRUD方法可以呼叫。

CustomerDao

package com.abc.app.dao;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.abc.app.entity.Customer;

@Repository
public interface CustomerDao extends CrudRepository<Customer, Long>{

}

CustomerService為Service層,做為一般Web應用程式Controller與Dao (Repository)的中間層,本範例沒有寫Controller,而是直接在Spring Boot啟動時從SpringBootApplication類,也就是SpringDataJpaDemoApplication直接呼叫來進行測試。

CustomerService

package com.abc.app.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.abc.app.dao.CustomerDao;
import com.abc.app.entity.Customer;
import com.abc.app.model.CustomerBo;

@Service
public class CustomerService {

    @Autowired
    private CustomerDao customerDao;
    
    public void add(CustomerBo bo) {
        Customer entity = new Customer();
        entity.setId(bo.getId());
        entity.setName(bo.getName());
        entity.setAddress(bo.getAddress());
        customerDao.save(entity);
    }
    
    public CustomerBo get(long id) {
        Customer entity = customerDao.findById(id).orElse(new Customer());
        CustomerBo bo = new CustomerBo();
        bo.setId(entity.getId());
        bo.setName(entity.getName());
        bo.setAddress(entity.getAddress());
        
        return bo;
    }
    
}

本範例直接在SpringDataJpaDemoApplication呼叫CustomerService來測試。在Spring Boot的進入點SpringDataJpaDemoApplication.main()方法中將內容修改如下。

SpringDataJpaDemoApplication

package com.abc.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import com.abc.app.model.CustomerBo;
import com.abc.app.service.CustomerService;

@SpringBootApplication
public class SpringDataJpaDemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = 
                SpringApplication.run(SpringDataJpaDemoApplication.class, args); // 取得Spring Context

        CustomerService customerService = context.getBean(CustomerService.class); // 取得CustomerService的bean

        CustomerBo bo1 = new CustomerBo();
        bo1.setId(10001L);
        bo1.setName("John");
        bo1.setAddress("No. 7, Yixin St., Hualien City, Hualien County 970, Taiwan (R.O.C.)");
        customerService.add(bo1); // 新增

        CustomerBo bo2 = customerService.get(10001L); // 查詢
        System.out.println(bo2); 
    }

}

接著啟動Spring Boot應用程式,Spring Data JPA便會依照實體類,也就是Customer的設定幫我們在mydb資料庫建立好對映的customer資料表,並新增一筆資料,然後再查詢出來。


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)

2019-05-19 15:30:25.247  INFO 13420 --- [           main] c.abc.app.SpringDataJpaDemoApplication   : Starting SpringDataJpaDemoApplication on matt-PC with PID 13420 (D:\MyProject\spring-boot\workspace\spring-data-jpa-demo\target\classes started by matt in D:\MyProject\spring-boot\workspace\spring-data-jpa-demo)
2019-05-19 15:30:25.250  INFO 13420 --- [           main] c.abc.app.SpringDataJpaDemoApplication   : No active profile set, falling back to default profiles: default
2019-05-19 15:30:25.776  INFO 13420 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2019-05-19 15:30:25.833  INFO 13420 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 50ms. Found 1 repository interfaces.
2019-05-19 15:30:26.245  INFO 13420 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2019-05-19 15:30:26.902  INFO 13420 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2019-05-19 15:30:26.950  INFO 13420 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
 name: default
 ...]
2019-05-19 15:30:27.008  INFO 13420 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.3.9.Final}
2019-05-19 15:30:27.011  INFO 13420 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2019-05-19 15:30:27.168  INFO 13420 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2019-05-19 15:30:27.344  INFO 13420 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL8Dialect
2019-05-19 15:30:28.448  INFO 13420 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-05-19 15:30:28.779  INFO 13420 --- [           main] c.abc.app.SpringDataJpaDemoApplication   : Started SpringDataJpaDemoApplication in 3.861 seconds (JVM running for 4.702)
id:10001,name:John,address:No. 7, Yixin St., Hualien City, Hualien County 970, Taiwan (R.O.C.)
2019-05-19 15:30:29.010  INFO 13420 --- [       Thread-3] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2019-05-19 15:30:29.019  INFO 13420 --- [       Thread-3] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2019-05-19 15:30:29.027  INFO 13420 --- [       Thread-3] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

在MySQL Workbench檢查mydb.customer確實有一筆剛剛新增的資料。



完成後的專案目錄結構。



若文章對您有幫助還幫忙點個廣告鼓勵,謝謝您的支持。


5 則留言:

  1. 想問一下若是直接對entity存取會有什麼樣的問題嗎@@?

    回覆刪除
  2. 不會有什麼問題,只是習慣上Service層和Dao層會切開

    回覆刪除
  3. 請問在services中
    entity.setId(bo.getId());
    entity.setName(bo.getName());
    entity.setAddress(bo.getAddress());


    IED一直跑出cannot resolve method setId in 'Customer'
    setName setAddress這些方法也是
    這些物件方法都無法被解析

    回覆刪除
  4. @ronidog Customer, CustomerBo中的 // getters and setters... 代表省略的意思,你需要在你的程式中補上,我這邊沒有寫出來。

    回覆刪除
  5. 感謝大大回達這麼迅速 我太菜了@@

    回覆刪除