A simple Spring Boot Application to showcase the integration of Hotwire into a 'normal' Spring Boot Webapplication
- Build the JS Parts
cd src/main/js
npm install
npm run build && npm run deploy
- Run the application
./mvnw clean install spring-boot:run
Point your browser to http://localhost:8080
The little JS Code that is necessary is built in src/main/js
using snowpack, to add minimal overhead. The necessary call is wired to the build
target of npm.
Since we needed two Button Handlers for the Turbo Streams examples, this also includes a short Stimulus Usage to hook up Controllers to those Buttons. Have a peek into ConnectSSEController.js
and ConnectWebsocketController.js
if you're interested.
The deploy
target copies the JS Files (and their dependencies) to the static
path of the Spring Boot Application from where they are served (Note: since we do this, the path is added to .gitignore
to make sure we don't check in any stale JS - so all scripts wuold have to be added this way unless you write directly into the page)
In order for the demo to run properly you need to run npm run build && npm run deploy
at least once, so the necessary files are created.
The Spring app is mostly plain vanilla Spring Boot/WebMVC with Thymeleaf for rendering templates.
There are a few Configuration Files that are necessary to set up the infrastructure:
TurboStreamsViewResolverConfiguration.java
– Registers an additional Thymeleaf View Resolver for the specialized Content-Type that Turbo-Streams is using. This way the Content-Negotiation of Spring WebMVC picks according to theAccept
Header of the Client and responds with the right Content-Type automatically (i.e. we can simply return a view Name from the@Controller
and Spring/Thymeleaf will pick up the correct view and Content-Type Response)WebSocketConfiguration.java
– registers our plain vanilla Websocket Handler to the URL expected in the frontend. As we do not want complex integration, we avoid the whole STOMP / SockJS Setup and just do simple Websockets.TaskSchedulerConfiguration.java
– since we use@Scheduled
in some controllers, but do not use Stomp, we need to provide a custom Setup here, otherwise the Stomp integration fails with a missing bean.
MessagesController.java
– handles all the dynamic requests for data in the Turbo-Frames pages. It usually redirects to the origin page, when not a more detailed response is necessaryTurboStreamWebsocketHandler.java
– a minimalistic Websocket Handler that is simply used to send turbo-streams updates to the Client. In a real application you would want to provide access to this component, so other Parts of the application could provide their content to this. Also note, that in a real setup one would need to handle more than a singleWebSocketSession
TurboStreamSSEController.java
– a simple implementation of aRequestController
that uses SSE to do the communication with the client.
- Navigation with Turbo Drive is enbled (visible through the progress bar and the fact that
Originator
for any Request in the Dev-Network Panel is:turbo.js
) - Simple interaction of turbo-frames: only a part of a page is updated
- Deferred loading of content with turbo-frames
- interacting with other turbo-frames (trigger a request from a different part of the page than the one that is updated)
- breaking free from a turbo-frame (navigating from inside a frame in a way that the whole window is replaced)
- Using turbo-streams as a response to a normal form
POST
to update multiple elements on a page - Using turbo-Streams over Websockets to live-update a page (and Stimulus for the Client-Side Dynamic)
- Using turbo-Streams over Websockets to live-update a page triggered through a Custom Element
- Using turbo-Streams over SSE to live-update a page (and Stimulus for the Client-Side Dynamic)