A Java 8 web application using lightweight frameworks and ReactJS for the UI
A Java 8 process with an embedded rest-api and web application, where the web application user interface is constructed using the React JavaScript components via the Nashorn engine with access to Java services.
SparkJava and Guava keep the overall dependencies lightweight (not even a single spring library here).
- SparkJava - A minimalist Java 8 web application framework
- Retrofit - A type-safe REST client for Java
- ReactJS - A Javascript library for building user interfaces
- Bootstrap-Admin-Theme - A web dashboard courtesy of Vincent Gabriel
- JMustache - A Java template engine
Also using Quava and a choice of Gradle or Maven for Java builds.
Make sure you have JDK 1.8.0_05-b13
or above.
command | description |
---|---|
gradle build |
to compile and run the tests |
mvn clean install |
to compile and run the tests |
grunt watch |
compile jsx into js resource (from src/main/jsx into src/main/js ) |
DemoService |
Start Web Application http://localhost:4545 |
Alternatively run the gradle installApp
command to create a runnable distribution package in build/install/sparkjava-retrofit-react
and run the appropriate script in the bin
folder.
These dials are using a JavaScript charting library but are rendered using ReactJS with data from Java:
These tables are rendered using ReactJS with data from Java, one table uses a Java service with direct access to the data store, the other Java service calls the rest-api from within Java to obtain the same data:
the ?skip=2&limit=4
parameters on the request URL are passed into ReactJS and back to Java services
The rest-api provides a simple (yet richer than the usual todo list) task
data model encapsulated behind a TaskService interface (the typical Data-Access-Object pattern). For the purpose of this exercise the tasks are seeded from a small sample of data and kept in-memory. There are only a couple of read operations defined as the main focus is to render data. However, this Data-Access-Object implementation could be swapped out for any Java based database or messaging connection and enriched to include fully functional CRUD (create, read, update, delete) functionality.
The first version of Bootstrap-Admin-Theme is purely a static copy of the original with the dashboard sidebar changed to provide the menu of demonstration links. Useful for showing how rich static content can be rendered easily with SparkJava.
The second version is the Dashboard content rendered by ReactJS, with a minimal HTML template to keep the surrounding page <script>
and <head>
tags separate.
Npm is used to download JavaScript packages. Grunt is used to compile jsx
and to create a bundle.js of all Javascript needed for Nashorn. This keeps the Java Nashorn loading code simple.
Java to setup Nashorn
nashorn = (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn");
...
Bindings bindings = new SimpleBindings();
bindings.put("JavaTaskService", taskService);
nashorn.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
...
nashorn.eval(new InputStreamReader(this.getClass().getResourceAsStream("/webapp/bundle.min.js")));
There are three steps above:
- Create the Nashorn JavaScript engine instance
- Inject any Java services you want your JavaScript to access
- Load the pre-created bundle.js
Creating the Nashorn engine instance is simple enough, although there is a little bit of nashorn-polyfill to be aware of (this gets included in the bundle.js).
The ability to use 'Dependency Injection' into your JavaScript makes it possible to access any Java services you have while rendering a page. There may need to be some data type conversions but this is a very powerful option and avoids trying to find JavaScript drivers for everything.
JavaScript to call back into Java services
loadTaskDataFromJavaDirectly: function () {
return Java.from(JavaTaskService.getTaskList(this.props.skip, this.props.limit));
},
Lastly we leverage npm
and grunt
to create a bundle.js containing ReactJS and any other libraries you wish to have access to. Note: this bundle.js is a simple Grunt concatenation bundle using uglify
, not a webpack
or browserify
bundle.
Calling the rest-api will perform all operations in Java; the rest-api converts the incoming endpoint into calls to the data-access-object. However, the web application calls take the following route:
java8
SparkJava calls a rendering function in the Nashorn JavaScript engine with properties from the Java process (mapped from the request query parameters)nashorn
starts rendering the component graph usingReact.renderToString
nashorn
calls any Java services for data at the time of renderingjava8
service can do anything Java can do and return results to the React component renderernashorn
completes and returns the rendered content tojava8
java8
maps thetitle
andcontent
into a HTML template and returns the response
This entire project is one big test so the only unit tests focus on testing the rest-api using Retrofit. Retrofit allows you to define a simple interface for your rest-api and leave the plumbing up to the Retrofit library. A real gem!
Example Java Retrofit RESTful api interface (See
RestfulService
for full version)
public interface RestfulService {
@GET("/api/v1/tasks")
RestResponse<List<Task>> getTasks(
@Query("skip") int skip,
@Query("limit") int limit
);
}
Example Java test using Retrofit (See
RestfulControllerTest
)
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("http://localhost:4545")
.build();
RestfulService taskService = restAdapter.create(RestfulService.class);
RestResponse<List<Task>> response = taskService.getTasks(1,4);
List<Task> tasks = response.content;
This project was built and tested on a Mac laptop, using Chrome, with JDK 1.8.0_05-b13
. It has not been tested/built on any Windows or Linux platforms but should work providing you have a Java 8 installed.