public class HelloWorld {
public static void main(String[] args) throws IOException {
WebServer server = WebServer.create();
server.start((request, response) -> response.body("Hello, World"));
}
}
Access your application at:
http://localhost:8080
If you don't use Java 8, it's almost as good:
public class HelloWorld {
public static void main(String[] args) throws IOException {
WebServer server = WebServer.create();
server.start(new Application() {
public void handle(Request request, Response response) throws Exception {
response.body("Hello, World");
}
});
}
}
You can get the latest release version from Maven Central:
<dependency>
<groupId>com.vtence.molecule</groupId>
<artifactId>molecule</artifactId>
<version>0.8</version>
</dependency>
If you want the development version, grab the latest snapshot from Sonatype snapshots repositories
(https://oss.sonatype.org/content/repositories/snapshots
):
<dependency>
<groupId>com.vtence.molecule</groupId>
<artifactId>molecule</artifactId>
<version>0.9-SNAPSHOT</version>
</dependency>
To use the default web server, you also need to add Simple as a dependency:
<dependency>
<groupId>org.simpleframework</groupId>
<artifactId>simple-http</artifactId>
<version>6.0.1</version>
</dependency>
Try out the following examples (Java 6 language level):
- Hello World
- Rendering HTML
- Dynamic Routes
- Static Files
- REST
- Cookies
- Locale Negotiation
- Multipart Forms
- View Templates and Layout
- HTTP Sessions
- Filters
- Creating a Custom Middleware
- Caching and Compression
- SSL
- A Sample Application
First thing first, you need a server to run your app:
WebServer server = WebServer.create();
This will set the default web server, which is powered by Simple, to run locally on port 8080.
To start the server, give it an app:
server.start((request, response) -> response.body("Hello, World!"));
To stop the server, call the stop method:
server.stop()
You can optionally specify the interface and port to bound to when creating the server, e.g. if you want to make your server globally available:
WebServer server = WebServer.create("0.0.0.0", 8088);
Most modern webapps have nice URLs. Simple URLs are also easier to remember and more user friendly.
Molecule comes with a routing middleware that let you define your URL routes.
Routes let you map incoming requests to different applications based on the request verb and path. A route is composed of a path pattern, an optional set of verbs to match, and an application endpoint:
server.start(new DynamicRoutes() {{
get("/posts/:id").to((request, response) -> {
// retrieve a given post
});
post("/posts").to((request, response) -> {
// create a new post
});
put("/posts/:id").to((request, response) -> {
// update an existing post
});
delete("/posts/:id").to((request, response) -> {
// delete a post
});
map("/").to((request, response) -> {
// show the home page
});
}});
Routes are matched in the order they are defined. If not defined route matches, the default behaviour is to render a 404 Not Found. This can be configured to pass the control to any default application.
By default, a route matches a single verb, specified by the method you use, i.e. get, post, put, delete. That can be changed by providing the verbs as arguments to the via method:
map("/").via(GET, HEAD).to((request, response) -> {
// show the home page
});
If you don't provide any verbs, map will match on all verbs.
Route patterns can be matched exactly - they are said to be static - or can include named parameters, which are then accessible as regular request parameters on the request object:
// matches "GET /photos/18" and "GET /photos/25"
// request.parameter("id") is either '18' or '25'
get("/photos/:id", (request, response) -> {
response.body("Photo #" + request.parameter("id"));
});
You are not limited to the provided match patterns. You can easily implement your own matcher and decide exactly how to match an incoming url to an application.
To do this, use the route definition methods that accept a Matcher rather than a String.
Middlewares are a way to enhance your application with optional building blocks, using a pipeline design.
They implement functionality you tend to need across all your applications, but you don't want to build everytime. Things like access logging, authentication, compression, static files, routing, etc.
Being able to separate the processing of the request (and post-processing of the response) in different stages has several benefits:
- It separate concerns, which helps keep your design clean and application well-structured
- It let you only include the functionality you need, so your server is as small and fast as possible
- It let you plug in your own processing stages, to customize the behavior of your application
- It let you reuse and share middlewares, as elemental building blocks of application behavior
For example you could have the following separate stages of the pipeline doing:
- Capturing internal server errors to render a nice 500 page
- Monitoring, logging accesses to the server
- Authentication and authorisation, to control access to your applicatin
- Caching, returning a cached result if request has already been processed recently
- Compression, to reduce bandwith usage
- Security, to prevent attacks such as CSRF
- Processing, to actually process the request
Molecule comes with a number of middlewares (more are coming), that you can use to build your processing pipeline:
- Router (See Routing)
- Static Assets
- File Server
- Access Log
- Cookies
- Locale Negotiation
- Compression
- ETag
- Conditional Get
- Connection Scope
- Server Header
- Date Header
- Content-Length Header
- Filter Map
- Cookie Session Tracker
- Fail Safe
- Failure Monitor
- Not Found
- Http Method Override
- Layout