Skip to content

Commit d8359fa

Browse files
authored
Merge pull request #753 from fabiotadashi/KTLN-609/ktor-thymeleaf
Ktln 609/ktor thymeleaf
2 parents 8451b90 + 5ed9458 commit d8359fa

File tree

15 files changed

+454
-1
lines changed

15 files changed

+454
-1
lines changed

kotlin-ktor/build.gradle.kts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ description = "Example usage of Gradle plugin to generate GraphQL Kotlin Client"
44

55
val graphQLKotlinVersion = "7.0.1"
66
val ktorVersion = "2.3.5"
7+
val logbackVersion = "1.4.14"
8+
val kotlinTestUnit = "1.9.10"
9+
val seleniumVersion = "4.16.1"
710

811
repositories {
912
mavenCentral()
@@ -18,16 +21,21 @@ dependencies {
1821
implementation("io.ktor", "ktor-server-core", ktorVersion)
1922
implementation("io.ktor", "ktor-server-netty", ktorVersion)
2023
implementation("io.ktor", "ktor-server-websockets", ktorVersion)
24+
implementation("io.ktor","ktor-server-status-pages", ktorVersion)
25+
implementation("io.ktor", "ktor-server-thymeleaf-jvm", ktorVersion)
2126
implementation("io.ktor", "ktor-client-auth", ktorVersion)
2227
implementation("io.ktor", "ktor-client-websockets", ktorVersion)
2328
implementation("io.ktor", "ktor-serialization-jackson", ktorVersion)
2429
implementation("io.ktor", "ktor-client-content-negotiation", ktorVersion)
2530

31+
implementation("ch.qos.logback","logback-classic", logbackVersion)
2632

2733
testImplementation("io.ktor", "ktor-client-mock", ktorVersion)
2834
testImplementation("io.ktor", "ktor-server-tests", ktorVersion)
2935
testImplementation("io.ktor", "ktor-serialization-kotlinx-json", ktorVersion)
30-
testImplementation("org.jetbrains.kotlin", "kotlin-test-junit", "1.9.10")
36+
testImplementation("org.jetbrains.kotlin", "kotlin-test-junit", kotlinTestUnit)
37+
testImplementation("org.seleniumhq.selenium", "selenium-java", seleniumVersion)
38+
3139
}
3240

3341
plugins {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.baeldung.thymeleaf.data
2+
3+
import io.ktor.http.*
4+
5+
object DataHolder {
6+
7+
fun getStudentList() = studentsList
8+
9+
fun findStudentById(id: String?) = getStudentList().first { student -> student.id == id }
10+
11+
fun updateGrades(studentId: String?, parameters: Parameters) {
12+
findStudentById(studentId)
13+
.gradeList.forEach { grade ->
14+
grade.apply {
15+
gradeValue = parameters[grade.id]?.let { GradeValue.valueOf(it) }
16+
}
17+
}
18+
}
19+
20+
private val studentsList = listOf(
21+
Student(
22+
id = "1",
23+
firstName = "Michael",
24+
lastName = "Smith",
25+
gradeList = createGradeList()
26+
),
27+
Student(
28+
id = "2",
29+
firstName = "Mary",
30+
lastName = "Johnson",
31+
gradeList = createGradeList()
32+
),
33+
Student(
34+
id = "3",
35+
firstName = "John",
36+
lastName = "Doe",
37+
gradeList = createGradeList()
38+
),
39+
)
40+
41+
private fun createGradeList() = listOf(
42+
Grade(id = "1", subject = "Reading"),
43+
Grade(id = "2", subject = "Writing"),
44+
Grade(id = "3", subject = "Science"),
45+
Grade(id = "4", subject = "Mathematics"),
46+
)
47+
48+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.baeldung.thymeleaf.data
2+
3+
data class Grade (
4+
val id: String,
5+
val subject: String,
6+
var gradeValue: GradeValue? = GradeValue.EMPTY
7+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.baeldung.thymeleaf.data
2+
3+
enum class GradeValue(val displayValue: String) {
4+
5+
A("A"),
6+
A_PLUS("A+"),
7+
A_MINUS("A-"),
8+
B("B"),
9+
B_PLUS("B+"),
10+
B_MINUS("B-"),
11+
C("C"),
12+
C_PLUS("C+"),
13+
C_MINUS("C-"),
14+
D("D"),
15+
D_PLUS("D+"),
16+
D_MINUS("D-"),
17+
F("F"),
18+
EMPTY("")
19+
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.baeldung.thymeleaf.data
2+
3+
data class Student(
4+
val id: String,
5+
val firstName: String,
6+
val lastName: String,
7+
val gradeList: List<Grade>,
8+
) {
9+
val fullName: String
10+
get() = "$firstName $lastName"
11+
12+
val hasAllGrades: Boolean
13+
get() = gradeList.firstOrNull { grade -> grade.gradeValue == GradeValue.EMPTY} == null
14+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.baeldung.thymeleaf.server
2+
3+
import com.baeldung.thymeleaf.server.plugins.configureRouting
4+
import com.baeldung.thymeleaf.server.plugins.configureStatusPages
5+
import com.baeldung.thymeleaf.server.plugins.configureTemplating
6+
import io.ktor.server.engine.*
7+
import io.ktor.server.netty.*
8+
9+
fun main() {
10+
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
11+
configureTemplating()
12+
configureRouting()
13+
configureStatusPages()
14+
}.start(wait = true)
15+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.baeldung.thymeleaf.server.plugins
2+
3+
import com.baeldung.thymeleaf.data.DataHolder
4+
import com.baeldung.thymeleaf.data.GradeValue
5+
import io.ktor.server.application.*
6+
import io.ktor.server.request.*
7+
import io.ktor.server.response.*
8+
import io.ktor.server.routing.*
9+
import io.ktor.server.thymeleaf.*
10+
11+
fun Application.configureRouting() {
12+
routing {
13+
get("/") {
14+
call.respond(ThymeleafContent("index", mapOf("studentList" to DataHolder.getStudentList())))
15+
}
16+
get("/report-card/{id}") {
17+
call.respond(
18+
ThymeleafContent("report-card",
19+
mapOf(
20+
"student" to DataHolder.findStudentById(call.parameters["id"]),
21+
"gradeOptionList" to GradeValue.entries
22+
)
23+
)
24+
)
25+
}
26+
post("/report-card/{id}") {
27+
val parameters = call.receiveParameters()
28+
DataHolder.updateGrades(call.parameters["id"], parameters)
29+
call.respondRedirect("/", false)
30+
}
31+
}
32+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.baeldung.thymeleaf.server.plugins
2+
3+
import io.ktor.http.*
4+
import io.ktor.server.application.*
5+
import io.ktor.server.plugins.statuspages.*
6+
import io.ktor.server.response.*
7+
import io.ktor.server.thymeleaf.*
8+
9+
fun Application.configureStatusPages() {
10+
install(StatusPages) {
11+
status(HttpStatusCode.NotFound) { call, _ ->
12+
call.respond(ThymeleafContent("error404", mapOf("message" to "Sorry! Page was not found.")))
13+
}
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.baeldung.thymeleaf.server.plugins
2+
3+
import io.ktor.server.application.*
4+
import io.ktor.server.thymeleaf.*
5+
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver
6+
7+
fun Application.configureTemplating() {
8+
install(Thymeleaf) {
9+
setTemplateResolver(ClassLoaderTemplateResolver().apply {
10+
prefix = "templates/"
11+
suffix = ".html"
12+
characterEncoding = "utf-8"
13+
})
14+
}
15+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html >
2+
<html xmlns:th="http://www.thymeleaf.org">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Error</title>
6+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
7+
rel="stylesheet"
8+
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
9+
crossorigin="anonymous">
10+
</head>
11+
<body>
12+
<div class="container">
13+
<h2>Error</h2>
14+
<p th:text="${message}" />
15+
</div>
16+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
17+
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
18+
crossorigin="anonymous"/>
19+
</body>
20+
</html>

0 commit comments

Comments
 (0)