Explain in detail, step-by-step, how to develop the system is out of scope. But basically you can use Spring Boot to make it easier to do the heavy lifting.
The architecture is simple:
- The server must provide a channel via WebSockets so that the client (browser) can receive updates.
- The page must have a JavaScript that subscribes to receive updates (messages) from the server.
In this tutorial you will find a simple example. On top of WebSockets, it uses a library based on the STOMP protocol for communication via text, more specifically, JSON.
Customer
The code on the client to connect, disconnect, send and receive messages looks like this:
function connect() {
var socket = new SockJS('/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function(greeting){
showGreeting(JSON.parse(greeting.body).content);
});
});
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName() {
var name = document.getElementById('name').value;
stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
}
The showGreeting
function called in the first method would be responsible for displaying the received message.
Server
You can create a controller to receive and return messages:
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(3000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
}
Unfortunately, in this tutorial example, it just sends a message and ends.
Already in this other tutorial you can find an example of how to post messages to the channel if it forms asynchronously (at any time):
@Service
public class ScheduleTask {
@Autowired
private SimpMessagingTemplate template;
// this will send a message to an endpoint on which a client can subscribe
@Scheduled(fixedRate = 5000)
public void trigger() {
// sends the message to /topic/message
this.template.convertAndSend("/topic/message", "Date: " + new Date());
}
}
The configuration (according to the second tutorial) is as follows:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// the endpoint for websocket connections
registry.addEndpoint("/stomp").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// use the /topic prefix for outgoing WebSocket communication
config.enableSimpleBroker("/topic");
// use the /app prefix for others
config.setApplicationDestinationPrefixes("/app");
}
}
Database
The examples above do not consider databases. Unfortunately, receiving database events or doing polling (continuous checking) is generally not possible or even recommended.
Ideally, your system should contain some notification API, where each new message generates a notification going to a queue. Eventually some asynchronous code can capture this message and publish to the correct channel, as in the example above where the scheduler publishes the date in the channel.
Of course you can implement this in a synchronous way, but generally this will have very negative performance impacts, so real applications do not do that.