2022年12月29日 星期四

[Spring Boot] 實作書中範例系列文1 - 一個人有一個識別證

 

1. 下載IDE - intelliJ

2. 下載Spring Boot專案

https://start.spring.io/

選maven後,dependencies還要選Spring Web,starter的version要為2.7.1

generate

3. 使用intelliJ開啟資料夾

4. 如果沒有安裝java和maven的話,要去project上按右鍵,在project structure編輯區選擇SDK

5. 打開maven的視窗,選擇lifecycle的install進行套件下載

6. 右上角的run/debug configurations可以增加跑maven的快速下拉選單選項(選Application),並找到有@SpringBootApplication的java檔作為入口

7. 下方的Run會顯示Spring Boot跑起來的字樣

8. 此時就可以用瀏覽器的localhost:8080找到spring boot程式

9. 架設用docker架起的DB,docker-compose.yml示範如下

version: "2"

services:
  postgres:
    container_name: postgres
    image: postgres:9.6.17
    environment:
      - POSTGRES_USER=root
      - POSTGRES_PASSWORD=root
      - PGDATA=/var/lib/postgres
    volumes:
      - postgres:/var/lib/postgres
      - /usr/share/zoneinfo/Asia/Taipei:/etc/localtime
    ports:
      - "5432:5432"
    networks:
      - dev-base
  pgadmin:
    container_name: pgadmin
    image: dpage/pgadmin4:4.18
    environment:
      - PGADMIN_DEFAULT_EMAIL=root
      - PGADMIN_DEFAULT_PASSWORD=root
    volumes:
      - pgadmin:/var/lib/pgadmin
    ports:
      - "5050:80"
    networks:
      - dev-base
networks:
  dev-base:

volumes:
  pgadmin:
  postgres:


9. 架起後,讓spring boot和postgres關聯,application.properties如下(test可以換成你的DB名字)


spring.datasource.url=jdbc:postgresql://localhost:5432/test
spring.datasource.username=root
spring.datasource.password=root

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect


10. 另外,由於要使用JPA進行資料與Entity的連動,所以還要裝套件,pom.xml如下(文字貼上後,要去maven再install一次,有問題就在pom.xml檔上面按reload project)

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
		
<dependency>
	<groupId>org.postgresql</groupId>
	<artifactId>postgresql</artifactId>
	<scope>runtime</scope>
</dependency>

11. 看DB狀況(例如檢查有沒有test這個DB)

docker exec -it 66f96d012892 /bin/sh //進入postgres的container
psql -d postgres -U root //查看DB狀況
\l //看所有的DB
\c test //切換到test DB
\dt //列出所有table
11. 建立Entity(根據書中的2-8),員工的entity,並且會觸發建立table

package com.example.demo;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name="T_EMPLOYER")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="ID")
    private int id;

    @Column(name = "FIRSTNAME")
    private String firstName;
    @Column(name = "LASTNAME")
    private String lastName;
    @Column(name = "BIRTHDATE")
    private Date birthDate;
    @Column(name = "SALARY")
    private float salary;
}
create table t_employer (
	id int4 not null,
	 birthdate timestamp,
	 firstname varchar(255),
	 lastname varchar(255),
	 salary float4,
	 primary key (id)
)

12. 建立Person(參考書中2-39)

至此步驟code

package com.example.demo;
import javax.persistence.*;


@Entity
@Table (name = "T_PERSON")
@Inheritance (strategy = InheritanceType.SINGLE_TABLE)
public class Person {
    @Id
    @GeneratedValue
    @Column (name = "ID")
    private Long id;
    @Column (name = "FIRST_NAME")
    private String firstName;
    @Column (name = "LAST_NAME")
    private String lastName;
}
    create table t_person (
       id int8 not null,
        first_name varchar(255),
        last_name varchar(255),
        primary key (id)
    )

13. 建立Person與Developers(參考書中2-39),並使用single_table繼承策略

package com.example.demo;
import javax.persistence.*;


@Entity
@Table (name = "T_PERSON")
@Inheritance (strategy = InheritanceType.SINGLE_TABLE)
public class Person {
    @Id
    @GeneratedValue
    @Column (name = "ID")
    private Long id;
    @Column (name = "FIRST_NAME")
    private String firstName;
    @Column (name = "LAST_NAME")
    private String lastName;
}
package com.example.demo;
import javax.persistence.*;
@Entity
@Access(AccessType.PROPERTY)
public class Developer extends Person {
    private String programmingLanguage;
    @Column(name = "PROG_LANG")
    public String getProgrammingLanguage () {
        return programmingLanguage;
    }
    public void setProgrammingLanguage (String programmingLanguage) {
        this.programmingLanguage = programmingLanguage;
    }
}
Hibernate: 
    
    alter table t_person 
       add column dtype varchar(31) not null
Hibernate: 
    
    alter table t_person 
       add column prog_lang varchar(255)
test-# \d t_person
             Table "public.t_person"
   Column   |          Type          | Modifiers 
------------+------------------------+-----------
 id         | bigint                 | not null
 first_name | character varying(255) | 
 last_name  | character varying(255) | 
 dtype      | character varying(31)  | not null
 prog_lang  | character varying(255) | 
Indexes:
    "t_person_pkey" PRIMARY KEY, btree (id)

14. 為了減少寫getter和setter的時間,導入套件lombok(pom.xml)

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>

15. 建立IdCard與BooleanConverter與修改Person

至此步驟code

package com.example.demo;

import lombok.Data;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "T_ID_CARD")
@Data
public class IdCard {
    private Long id;
    private String idNumber;
    private Date issueDate;
    private boolean valid;
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    @Column (name ="ID")
    public Long getId() {
        return id;
    }
    @Column (name ="ID_NUMBER")
    public String getIdNumber() {
        return idNumber;
    }
    @Column (name="ISSUE_DATE")
    @Temporal (TemporalType.TIMESTAMP)
    public Date getIssueDate() {
        return issueDate;
    }
    @Column (name="VALID")
    @Convert (converter = BooleanConverter.class)
    public boolean isValid() {
        return valid;
    }
    // setter methods
    @Override
    public String toString() {
        return "IdCard [id=" + id + "idNumber=" + idNumber + "issueDate=" + issueDate + ", valid=" + valid + "]";
    }
}
package com.example.demo;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter
public class BooleanConverter implements AttributeConverter<Boolean, Integer> {
    @Override
    public Integer convertToDatabaseColumn(Boolean aBoolean) {
        if (Boolean.TRUE.equals(aBoolean)) {
            return 1;
        } else {
            return -1;
        }
    }
    @Override
    public Boolean convertToEntityAttribute (Integer value){
        if (value == null) {
            return Boolean.FALSE;

        } else {
            if (value == 1) {
                return Boolean.TRUE;
            } else {
                return Boolean.FALSE;
            }
        }
    }
}
package com.example.demo;
import javax.persistence.*;

@Entity
@Table (name = "T_PERSON")
@Inheritance (strategy = InheritanceType.SINGLE_TABLE)
public class Person {
    ...

    @OneToOne
    @JoinColumn(name = "ID_CARD_ID")
    private IdCard idCard;

    public IdCard getIdCard () {
        return idCard;
    }
    public void setIdCard (IdCard idCard) {
        this.idCard = idCard;
    }
}
Hibernate: 
    
    create table t_id_card (
       id  bigserial not null,
        id_number varchar(255),
        issue_date timestamp,
        valid int4,
        primary key (id)
    )
Hibernate: 
    
    alter table t_person 
       add column id_card_id int8
Hibernate: 
    
    alter table t_person 
       add constraint FKlp5262lkfpjcpimic9kvnnkj8 
       foreign key (id_card_id) 
       references t_id_card

沒有留言:

張貼留言