ตัวอย่างการเขียน Spring-boot WebFlux Entity
pom.xml
...
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.3.Final</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
...
spring-boot-starter-webflux
ใช้สำหรับเขียน webfluxspring-boot-starter-data-jpa
ไว้สำหรับเขียนคำสั่ง query, method queryhibernate-core
สำหรับทำ ORM (Object Relational Mapping) ไว้เขียนพวก entity class สำหรับ mapping java class ไปยัง database table รวมถึงการ mapping พวก relation ต่าง ๆ ของ table เช่น One to One, One to Many, Many to Manypostgresql
เป็น postgresql database driverHikariCP
เป็นตัวจัดการ database connection poollombok
เป็น annotation code generator สามารถ generate code at compile time ได้ ทำให้เราไม่ต้องเขียน code บางส่วนเอง เช่น getter setter method ตัว lombox จะทำให้
AppStarter.java
@SpringBootApplication
@ComponentScan(basePackages = {"com.pamarin"})
public class AppStarter {
public static void main(String[] args) {
SpringApplication.run(AppStarter.class, args);
}
}
User.java
@Data
@Entity
@Table(name = User.TABLE_NAME)
public class User implements Serializable {
public static final String TABLE_NAME = "user";
@Id
private String id;
@Column(name = "username", nullable = false, unique = true)
private String username;
@Column(name = "password", nullable = false)
private String password;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private List<UserAuthority> userAuthorities;
public List<UserAuthority> getUserAuthorities() {
if (userAuthorities == null) {
userAuthorities = new ArrayList<>();
}
return userAuthorities;
}
}
Authority.java
@Data
@Entity
@Table(name = Authority.TABLE_NAME)
public class Authority implements Serializable {
public static final String TABLE_NAME = "authority";
@Id
private String id;
@Column(name = "name", unique = true, nullable = false)
private String name;
private String description;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "authority")
private List<UserAuthority> userAuthorities;
public List<UserAuthority> getUserAuthorities() {
if (userAuthorities == null) {
userAuthorities = new ArrayList<>();
}
return userAuthorities;
}
}
UserAuthority.java
@Data
@Entity
@Table(name = UserAuthority.TABLE_NAME)
public class UserAuthority implements Serializable {
public static final String TABLE_NAME = "user_authority";
@Data
@Embeddable
public static class UserAuthorityPK implements Serializable {
@Column(name = "user_id")
private String userId;
@Column(name = "authority_id")
private String authorityId;
}
@EmbeddedId
private UserAuthorityPK id;
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
private User user;
@ManyToOne
@JoinColumn(name = "authority_id", referencedColumnName = "id", insertable = false, updatable = false)
private Authority authority;
}
- New java class ขึ้นมา
- Implements
java.io.Serializable
- เขียน Attributes / Properties / Columns ตามที่ต้องการ ด้วย
@Column
(อย่าลืมกำหนด Constrains) - ใส่ annotation
@Entity
- ใส่ Annotation
@Table
เพื่อ map ไปยัง table ที่ต้องการ (name = ???) - กำหนด Id หรือ Primary Key ของ Table ด้วย
@Id
- กรณีที่เป็น Composite Key (Key ร่วม) จะใช้
@EmbeddedId
และ Key class จะใส่@Embeddable
- กรณีที่เป็น Composite Key (Key ร่วม) จะใช้
- ประกาศ Getter / Setter / HashCode / Equals method ซึ่งสามารถใช้
@Data
ของ lombox ช่วยได้ (มันจะ Generate ให้ Auto) - เขียน Relation
@OneToOne
คือ class นี้ map ไปยัง attribute ที่ประกาศไว้แบบ 1:1@OneToMany
คือ class นี้ map ไปยัง attribute ที่ประกาศไว้แบบ 1:M@ManyToOne
คือ class นี้ map ไปยัง attribute ที่ประกาศไว้แบบ M:1@ManyToMany
คือ class นี้ map ไปยัง attribute ที่ประกาศไว้แบบ M:N
ซึ่งกรณีนี้ Hibernate จะสร้าง table ใหม่ขึ้นมาเชื่อมกลายเป็น 3 tables และมี relation เป็นแบบ
TABLE_A
1 <-> MTABLE_C
N <-> 1TABLE_B
(TABLE_A
และTABLE_B
เป็น table ที่เรากำหนด ส่วนTABLE_C
Hibernate จะ Generate ให้)
แต่วิธีนี้ผมไม่ค่อยจะใช้สักเท่าไหร่ เห็นข้อเสียของมันคือ Table กลาง (TABLE_C
) เรา Custom เองไม่ได้ ผมจะใช้แค่@OneToMany
กับ@ManyToOne
- Join Columns (ถ้ามี)
#------------------------------------ JPA --------------------------------------
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.cache.use_second_level_cache=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.use-new-id-generator-mappings=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.proc.param_null_passing=true
spring.jpa.properties.hibernate.default_schema=*****
#------------------------------------ Hikari -----------------------------------
spring.datasource.hikari.minimumIdle=1
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.idleTimeout=30000
spring.datasource.hikari.connectionTestQuery=SELECT 1 FROM DUAL
spring.datasource.hikari.validationTimeout=3000
#------------------------------------ Postgresql -------------------------------
spring.datasource.url=jdbc:postgresql:*****
spring.datasource.username=*****
spring.datasource.password=*****
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.platform=postgres
spring.datasource.type=org.postgresql.ds.PGSimpleDataSource
spring.jpa.hibernate.ddl-auto
เป็นการบอก Hibernate ว่าให้ทำคำสั่ง DDL (Data Definition Language) อะไร ตอน Start Applicationnone
คือ ไม่ต้องทำอะไรcreate
คือ ให้ทำการสร้าง table จาก entity ที่ประกาศไว้ ตอน start applicationupdate
คือ ให้ทำการ update table ตาม entity ที่ประกาศไว้ ตอน start applicationcreate-drop
คือ ให้ create และ drop table หลังจากเลิกใช้งาน จะใช้ตอนเขียน test คือ create ใช้งานเสร็จแล้ว drop ทิ้งvalidate
คือ ให้ทำการเช็ค database schema หรือ table ว่ามีการเปลี่ยนแปลงหรือไม่ ถ้ามีการเปลี่ยนแปลง จะ error ตอน start application
ถ้าเป็นการเขียน entity ครั้งแรก (ตอน dev) ให้ใช้ create
หลังจากนั้นแนะนำให้ใช้ update
หรือ none
ส่วน production ให้เป็น none
แล้วใช้วิธี create database จาก sql script เอา ไม่ควรเปิด create
หรือ update
ตอนใช้งาน production *** ห้ามเด็ดขาด ***
cd ไปที่ root ของ project จากนั้น
$ mvn clean install
$ mvn spring-boot:run \
-Dserver.port=8080 \
-Dspring.datasource.url=jdbc:postgresql://<HOST>:<PORT>/<DATABASE_NAME>?sslmode=require \
-Dspring.datasource.username=<DATABASE_USERNAME> \
-Dspring.datasource.password=<DATABASE_PASSWORD> \
-Dspring.jpa.properties.hibernate.default_schema=<DATABASE_SCHEMA>
ให้เปลี่ยน ค่า <>
เป็นของตัวเองน่ะครับ
- HOST คือ ip หรือ domain name ของ database server
- PORT คือ port ที่ใช้
- DATABASE_NAME คือ ชื่อ database
- DATABASE_USERNAME คือ ชื่อ username ที่ login เข้าใช้งาน database
- DATABASE_PASSWORD คือ รหัสผ่านที่คู่กับ username ที่ใช้
- DATABASE_SCHEMA คือ database schema ที่่ใช้