iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
Modern Web

使用 Kotlin 快速開發 Web 程式 -- Vaadin系列 第 8

vok-orm 關聯性資料的新增/查詢 (上篇) -- d08

本節重點

  • 延續先前己建立的學生資料範例,今天加上學生成績。

    1. 建立成績資料
    2. 在顯示單筆學生資料頁StudentView.kt上加上新增及顯示成績畫面
    3. Refactor 時加入 VoK karibu-dsl 套件特色 (下篇)
  • vok-orm和許多orm使用方式類似,在這篇文裡不會特別詳細解說,倘若未曾使用過任何jpa、orm,看這篇文章時可先忽略霧裡看花的部份,日後會專篇介紹。

第二個資料表

  • 新增學生成績 entify,開新檔 Grade.kt
data class Grade(
    override var id: Long? = null,
    var student_id: Long? = null,
    val description: String? = null,
    var english: Double? = null,
    var math: Double? = null,
    var mandarin:Double? = null,
    var pe: Double? = null
): KEntity<Long>{
    companion object: Dao<Grade, Long>(Grade::class.java)
    val student: Student?
        get() = student_id?.let { Student.getById(student_id!!)} ?: null
}
  • 建立資料表 Grade,請開新檔 V02__CreateGrade.sql (命名規格請參考d04)
create TABLE Grade(
    id bigint auto_increment PRIMARY KEY,
    mandarin DOUBLE NOT NULL,
    description VARCHAR(50) NOT NULL,
    english DOUBLE NOT NULL,
    math DOUBLE NOT NULL,
    pe DOUBLE NOT NULL,
    student_id bigint not null REFERENCES Student(id)
)

在這張資料表裡除了自動編號的 primary key id外,還有一個 foreign key student_id,由於使用 H2 database,所以程式重啟時,兩個.sql都會執行。倘若使用的是其他資料庫如 MySQL,則 FlyWay 只會執行尚未被執行的.sql。

  • 接著在顯示學生資料畫面上加上編輯畫面,請打開StudentView.kt
        :
        : 

    private lateinit var student: Student
    private lateinit var gradeDiv: Div
    private val gradeBinder = beanValidationBinder<Grade>()
    private lateinit var addGradeButton: Button
    private val root = ui {
        verticalLayout {
        :
        :
        :
            h2("成績")
            gradeDiv = div()
            p("新增成績")

            textField("學期"){
                bind(gradeBinder).bind(Grade::description)
                placeholder = "第一學期"
            }
            numberField("國文"){
                bind(gradeBinder).bind(Grade::mandarin)
            }
            numberField("英文"){
                bind(gradeBinder).bind(Grade::english)
            }
            numberField("數學"){
                bind(gradeBinder).bind(Grade::math)
            }
            numberField("體育"){
                bind(gradeBinder).bind(Grade::pe)
            }
            addGradeButton = button("新增"){
                onLeftClick { addGrade() }
            }
            editLink = routerLink(VaadinIcon.EDIT,null)
        }
    }

gradeDiv = div() 表示在畫面上新增空的DIV區塊

  • 驗證儲存
    private fun addGrade() {
        val grade = Grade()
        if (gradeBinder.validate().isOk && gradeBinder.writeBeanIfValid(grade)){
            grade.student_id = student.id
            grade.save()
            refreshGrades()
            gradeBinder.readBean(Grade())
        }
    }
  • 新增成功後更新畫面
    private fun refreshGrades() {
        gradeDiv.removeAll()
        student.grades.fetch().forEach {
            gradeDiv.html("<p>" +
                    "<strong>學期:</strong>${it.description} " +
                    "<strong>國文:</strong>${it.mandarin} " +
                    "<strong>英文:</strong>${it.english} " +
                    "<strong>數學:</strong>${it.math} " +
                    "<strong>體育:</strong>${it.pe}" +
                    "</p>")
        }
    }

清空DIV區塊,查詢這位學生所有成績後再逐一顯示,這裡插入div區塊使用的是html,在VoK裡,對dom的操作也極為容易。

  • 在 data class Student 加上grads屬性。請打開Student.kt
    val grades : DataLoader<Grade>
        get() = Grade.dataLoader.withFilter {
            Grade::student_id eq id
        }

當有人讀取grads時,下條件查詢資料來源 Grade

  • 最後,記得要在Grade.kt加上欄位驗證資訊
    @field:NotNull
    var student_id: Long? = null,

    @field:NotNull
    @field:Size(min = 4)
    var description: String? = null,

    @field:NotNull
    @field:DecimalMin(value = "0.0")
    @field:DecimalMax(value = "100.0")
    var english: Double? = null,
    
    :
    :
    (略)

執行結果 :

https://ithelp.ithome.com.tw/upload/images/20210923/20138680MdrMDOMbpp.png

本日Source Code已上傳 GitHub


上一篇
自訂 Vaadin 組件 / Grid 擴充功能 -- day07
下一篇
vok-orm 關聯性資料的新增/查詢 (下篇) + Vaadin 自訂樣式 - d09
系列文
使用 Kotlin 快速開發 Web 程式 -- Vaadin30

尚未有邦友留言

立即登入留言