add core view extension with JTE and Thymeleaf support
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# Architecture
|
||||
|
||||
`flash-ext-view-jte` has two layers:
|
||||
|
||||
1. **Boot-time**
|
||||
- `JteExtension` installs runtime + annotation processor.
|
||||
- `JteTargetResolver` validates handlers and resolves `@Template`.
|
||||
- Resolved targets are cached per handler class.
|
||||
|
||||
2. **Request-time**
|
||||
- Handler builds local `ViewModel`.
|
||||
- Runtime injects globals under reserved `global` namespace and merges local model.
|
||||
- jte renders template into `StringOutput`.
|
||||
|
||||
## Handler Contract
|
||||
|
||||
- Must extend `JteHandler`.
|
||||
- Must have route annotation (`@Route`, `@GET`, `@POST`, ...).
|
||||
- Must declare exactly one view annotation: `@Template`.
|
||||
|
||||
Invalid configurations fail fast at startup.
|
||||
|
||||
## Defaults
|
||||
|
||||
- `templateRoot`: `/templates`
|
||||
- `contentType`: `gg.jte.ContentType.Html`
|
||||
- `developmentMode`: `Flash.DEV`
|
||||
- `usePrecompiled`: derived from `!developmentMode` unless explicitly set
|
||||
- `binaryStaticContent`: `false`
|
||||
@@ -0,0 +1,34 @@
|
||||
# Handlers
|
||||
|
||||
Use `JteHandler` for class-based jte routes.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
- `onViewInit()` runs once at boot.
|
||||
- `render(...)` runs per request.
|
||||
|
||||
Use `onViewInit()` to cache dependencies via `require(...)`.
|
||||
|
||||
## Example
|
||||
|
||||
```java
|
||||
@GET("/dashboard")
|
||||
@Template("pages/dashboard.jte")
|
||||
public final class DashboardPage extends JteHandler {
|
||||
|
||||
private DashboardService service;
|
||||
|
||||
@Override
|
||||
protected void onViewInit() {
|
||||
service = require(DashboardService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewModel render(dev.relism.models.Request req) {
|
||||
return ViewModel.empty()
|
||||
.with("page", service.page(req));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `render(Request, Response)` when you need response access while building model variables.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Model And Globals
|
||||
|
||||
`ViewModel` is the per-request data container.
|
||||
|
||||
## POJO-First Pattern
|
||||
|
||||
Keep page state in a POJO and pass it as a single key:
|
||||
|
||||
```java
|
||||
return ViewModel.empty()
|
||||
.with("page", new HomePage("Flash + jte", "elorc"))
|
||||
.with("build", "dev");
|
||||
```
|
||||
|
||||
Then type it in template:
|
||||
|
||||
```jte
|
||||
@import com.example.HomePage
|
||||
@param HomePage page
|
||||
@param String build
|
||||
```
|
||||
|
||||
## Globals
|
||||
|
||||
Register globals in extension setup:
|
||||
|
||||
```java
|
||||
new JteExtension().addGlobal("appName", req -> "Flash")
|
||||
```
|
||||
|
||||
Globals are available under `global` namespace in templates.
|
||||
|
||||
`global` is reserved and cannot be used as local model key.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Performance Notes
|
||||
|
||||
- Runtime caches resolved targets by handler class.
|
||||
- Request path allocates only what jte rendering requires.
|
||||
- No reflection on hot path after target cache is warm.
|
||||
- `TemplateEngine` is created once and shared.
|
||||
|
||||
## Dev vs Prod
|
||||
|
||||
- Dev mode (`developmentMode=true`) uses code resolver rendering.
|
||||
- Prod mode (`usePrecompiled=true`) uses precompiled classes for startup and render speed.
|
||||
|
||||
## Content Type
|
||||
|
||||
`gg.jte.ContentType` drives both escaping mode and HTTP response content type mirror:
|
||||
|
||||
- `Html` -> context-aware HTML escaping + `text/html`
|
||||
- `Plain` -> plain output + `text/plain`
|
||||
Reference in New Issue
Block a user