Example: Flashcard
The same features as ch07-jdbc-plus from spring-jdbc-book (decks, cards, tags, spaced-repetition study, smart decks, CSV import/export, statistics) built without Spring Boot.
- DB
-
Repositories use
NamedParameterJdbcTemplatedirectly. The executed SQL is visible in the code. Inserts are the exception:SimpleJdbcInsertreads the table metadata and returns the generated key, withSimplePropertySqlParameterSourcetaking the values straight off the domain record.SmartDeckRepositorystill spells its parameters out, because itsSmartConditionenum has to reach the driver asname()rather than as an enum. Row mapping goes throughDataClassRowMapper; the reflection this pair needs under a native image is a config the build generates from the domain package. - DI
-
No container;
FlashcardContextwires everything by calling constructors directly, playing the role of Spring’s ApplicationContext by hand. - Transactions
-
Instead of AOP, services call
Transactions.write()/read(), a thin wrapper aroundTransactionTemplate. The wrapped block is exactly the transaction scope. - JSON API
-
As a bonus, a JSON API (
/api/decks,/api/decks/{id}/cards) sits on the same service layer to show the framework’s REST support. Its wire format is inflashcard.web.Codecsas hand-writtenJsonWriter/JsonReaderlambdas. - Introspection
-
/_routeslists every route and/openapi.jsonis the same list as an OpenAPI 3.1 document, both built fromapp.routes(), which is what the framework exposing its routing table as data buys you. - Routing
-
There is no
Controllerinterface.FlashcardApp.registerRoutesis the whole table, and handlers arrive as anActionclass, a public method reference, or a lambda.
Run
gradle :example-flashcard:run # precompiled templates
gradle :example-flashcard:run --args=--dev # hot-reloads edited .jte files
# http://localhost:8080
The two commands are jte’s production and development modes: the first renders the template classes the build compiled, the second recompiles a template whose file changed on its next render.
The database is an H2 file (~/db/spider-silk/flashcard), so data survives restarts.
gradle :example-flashcard:nativeCompile builds the same app as a GraalVM native image.