Getting Started
A complete Hello World in three files. JWeb is a Spring Boot library — add one dependency and write pages in pure Java. No frontend toolchain, no templates, no build step.
1. Add the Dependency
Maven — the JitPack repository plus the dependency:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.oscar-osmig</groupId>
<artifactId>Jweb</artifactId>
<version>v1.0.6</version>
</dependency>Gradle:
repositories { maven { url 'https://jitpack.io' } }
dependencies { implementation 'com.github.oscar-osmig:Jweb:v1.0.6' }2. Project Structure
Three files. Java allows one public class per file, so each of these is its own file — putting them in one file will not compile:
src/main/java/org/example/
App.java <- starts the application
Routes.java <- maps URLs to pages
pages/
HomePage.java <- the page itself3. App.java
@JWebApplication replaces @SpringBootApplication. Framework beans arrive through auto-configuration, so only your own package is scanned.
package org.example;
import com.osmig.Jweb.framework.JWebApplication;
import org.springframework.boot.SpringApplication;
@JWebApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}4. Routes.java
A @Component implementing JWebRoutes. Page routes render a Template; router routes take the request and can return anything.
package org.example;
import com.osmig.Jweb.framework.JWeb;
import com.osmig.Jweb.framework.JWebRoutes;
import com.osmig.Jweb.framework.middleware.Middlewares;
import org.example.pages.HomePage;
import org.springframework.stereotype.Component;
@Component
public class Routes implements JWebRoutes {
@Override
public void configure(JWeb app) {
app.use(Middlewares.recommended()); // security headers, request ids
app.pages("/", HomePage.class);
app.get("/hello", req -> "Hello from JWeb");
}
}5. pages/HomePage.java
A page is any class implementing Template. Elements come from El, styles from the CSS DSL — both fully type-checked.
package org.example.pages;
import com.osmig.Jweb.framework.core.Element;
import com.osmig.Jweb.framework.template.Template;
import static com.osmig.Jweb.framework.elements.El.*;
import static com.osmig.Jweb.framework.styles.CSS.*;
import static com.osmig.Jweb.framework.styles.CSSUnits.*;
import static com.osmig.Jweb.framework.styles.CSSColors.*;
public class HomePage implements Template {
@Override
public Element render() {
return div(style().maxWidth(px(700)).margin(zero, auto).padding(rem(3)),
h1(style().fontSize(rem(2)).fontWeight(700), text("Welcome")),
p(style().color(hex("#64748b")), text("Your first JWeb page."))
);
}
}6. Run It
mvn spring-boot:run
# / -> your page
# /hello -> Hello from JWebNext: a Shared Layout (optional)
Once you have more than one page, a layout gives them a common shell. It is a Template that takes the page content:
public class MainLayout implements Template {
private final Element content;
public MainLayout(Element content) { this.content = content; }
@Override
public Element render() {
return html(
head(metaCharset(), metaViewport(), title("My App")),
body(nav(a(href("/"), text("Home"))), main(content))
);
}
}
// in Routes.configure:
app.layout(MainLayout.class)
.pages("/", HomePage.class,
"/about", AboutPage.class);Configuration (optional)
Everything has a working default — set only what you need:
server:
port: 8080
jweb:
dev:
debug: false # stack traces on error pages (dev only)
data: # MongoDB, off by default
enabled: false
ai: # built-in AI, off by default
enabled: false
api-key: ${AI_API_KEY:}Skip the Setup
The CLI generates this whole structure, wired and ready to run:
jweb new myapp --package=com.mycompany.myapp
cd myapp && mvn spring-boot:run