Hallo, dear reader. This post is actually my attempt to following an existing tutorial that was made by Gürkan UÇAR which tutorial can be seen at here. You can also find the working github here.
And my final result from following the tutorial can be seen at my github repository. In this post I would like to focus on how to build the server side service so let's start cooking!
Prerequisite
- Java version of 17.
- Visual Studio Code extension for Spring Initializr.
Initializing Java Spring Boor project with Maven
- Open your Visual Studio Code.
- To create new project, usually I hit ctrl+shift+paltogether, chooseSpring Initializr: Create Maven Project.  
- We're going to use Spring Boot Version of 3.2.0.  
- We choose Javaas the language.  
- 
For the dependencies, you can seet at my POM.xml. If you can't find it, that's fine because you can add it manually later, once your project is generated. <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.tujuhsembilan</groupId> <artifactId>socketio</artifactId> <version>0.0.1-SNAPSHOT</version> <name>socketio</name> <description>Demo project for Spring Boot</description> <properties> <java.version>17</java.version> <netty-socketio.version>1.7.17</netty-socketio.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.corundumstudio.socketio</groupId> <artifactId>netty-socketio</artifactId> <version>${netty-socketio.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
10. Choose where you want to save the project.
## Creating project skeleton
1. Open `src\main\java\com\{your_group_id}\{your_artifact_id}`. Mine is `src\main\java\com\tujuhsembilan\socketio`.
2. Now I would suggest you to create few new packages like this:
    ```
    src/
        └── main/
            └── java/
                └── com/
                    └── tujuhsembilan/
                        └── socketio/
                            ├── configuration/
                            ├── constants/
                            ├── controller/
                            ├── enums/
                            ├── model/
                            ├── repository/
                            ├── service/
                            └── socket/
Configuring application.properties
Usually, you can find application.properties at src\main\resources\application.properties. You can copy paste these lines to application.properties. Don't forget to make sure that the port for socket is free to use and more importantly, change the host to your IPv4 address.
socket-server.port=8086 // you can change this to port that is free to use
socket-server.host=191.167.1.28 // change this to your IPv4 address
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:database
Creating configurations
- 
Open configuration package. Create a new class called SocketIOConfig.java. This is the content of the class:package com.tujuhsembilan.socketio.configuration; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.corundumstudio.socketio.SocketIOServer; @Configuration public class SocketIOConfig { @Value("${socket-server.host}") private String host; @Value("${socket-server.port}") private Integer port; @Bean public SocketIOServer socketIOServer() { com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration(); config.setHostname(host); config.setPort(port); return new SocketIOServer(config); } }
2. Still in the same package, create another new class called `ServerCommandLineRunner.java`. This is the content:
    ```
    package com.tujuhsembilan.socketio.configuration;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.stereotype.Component;
    import com.corundumstudio.socketio.SocketIOServer;
    import lombok.RequiredArgsConstructor;
    @Component
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class ServerCommandLineRunner implements CommandLineRunner {
        private final SocketIOServer server;
        @Override
        public void run(String... args) throws Exception {
            server.start();
        }
    }
Creating model
We only need a model called Message. Open your model package. Create a new file called Message.java. This is the content:
package com.tujuhsembilan.socketio.model;
import java.time.LocalDateTime;
import java.util.UUID;
import com.tujuhsembilan.socketio.enums.MessageType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Builder
@Getter
@Setter
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Message {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;
    @Column 
    @Enumerated(EnumType.STRING)
    private MessageType messageType;
    @Column
    private String room;
    @Column
    private String username;
    @Column
    private String message;
    @Column
    private LocalDateTime createdAt;
}
Creating enums
As you might notice, we not yet have enums for messageType in the model. Hence, we need to create one. Open enums package, create a new class called MessageType.java and copy paste this:
package com.tujuhsembilan.socketio.enums;
public enum MessageType {
    SERVER, CLIENT
}
Now the Message model should be working fine.
Creating constants
Now, before moving further, let's create some constants. Open constants package. Create a new file called Constants.js and below is the content:
package com.tujuhsembilan.socketio.constants;
public class Constants {
public static final String WELCOME_MESSAGE = "%s joined to chat";
public static final String DISCONNECT_MESSAGE = "%s disconnected";
    
    
}
  
  
  Creating repository
In repository package, create a new repository class called MessageRepository.java. This is the content for it:
package com.tujuhsembilan.socketio.repository;
import java.util.List;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.tujuhsembilan.socketio.model.Message;
@Repository
public interface MessageRepository extends JpaRepository<Message, UUID> {
    List<Message> findAllByRoom(String room);
}
  
  
  Creating services
- 
In service package, create a new class called MessageService.java.package com.tujuhsembilan.socketio.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.tujuhsembilan.socketio.model.Message; import com.tujuhsembilan.socketio.repository.MessageRepository; import lombok.RequiredArgsConstructor; @Service @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class MessageService { private final MessageRepository messageRepository; public List<Message> getMessage(String room) { return messageRepository.findAllByRoom(room); } public Message saveMessage(Message message) { return messageRepository.save(message); } }
2. Create another class in the same package called SocketService.java.
    ```
package com.tujuhsembilan.socketio.service;
import org.springframework.stereotype.Service;
import com.corundumstudio.socketio.SocketIOClient;
import com.tujuhsembilan.socketio.enums.MessageType;
import com.tujuhsembilan.socketio.model.Message;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class SocketService {
    private final MessageService messageService;
    public void sendSocketmessage(SocketIOClient senderClient, Message message, String room) {
        for (
            SocketIOClient client: senderClient.getNamespace().getRoomOperations(room).getClients()
        ) {
            if (!client.getSessionId().equals(senderClient.getSessionId())) {
                client.sendEvent("read_message", message);
            }
        }
    }
    public void saveMessage(SocketIOClient senderClient, Message message) {
        Message storedMessage = messageService.saveMessage(
            Message.builder()
                .messageType(MessageType.CLIENT)
                .message(message.getMessage())
                .room(message.getRoom())
                .username(message.getUsername())
                .build()
        );
        sendSocketmessage(senderClient, storedMessage, message.getRoom());
    }
    public void saveInfoMessage(SocketIOClient senderClient, String message, String room) {
        Message storedMessage = messageService.saveMessage(
            Message.builder()
                .messageType(MessageType.SERVER)
                .message(message)
                .room(room)
                .build()
        );
        sendSocketmessage(senderClient, storedMessage, room);
    }
}
    
    
  
  
  Creating socket module
Now, we are going to create a socket module. Open socket package, create a new file called SocketModule.java like this:
package com.tujuhsembilan.socketio.socket;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
import com.tujuhsembilan.socketio.constants.Constants;
import com.tujuhsembilan.socketio.model.Message;
import com.tujuhsembilan.socketio.service.SocketService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class SocketModule {
private final SocketIOServer server;
private final SocketService socketService;
public SocketModule(SocketIOServer server, SocketService socketService) {
    this.server = server;
    this.socketService = socketService;
    server.addConnectListener(this.onConnected());
    server.addDisconnectListener(this.onDisconnected());
    server.addEventListener("send_message", Message.class, this.onChatReceived());
}
private DataListener<Message> onChatReceived() {
    return (senderClient, data, ackSender) -> {
        log.info(data.toString());
        socketService.saveMessage(senderClient, data);
    };
}
private ConnectListener onConnected() {
    return (client) -> {
        var params = client.getHandshakeData().getUrlParams();
        String room = params.get("room").stream().collect(Collectors.joining());
        String username = params.get("username").stream().collect(Collectors.joining());
        client.joinRoom(room);
        socketService.saveInfoMessage(client, String.format(Constants.WELCOME_MESSAGE, username), room);
        log.info("Socket ID[{}] - room[{}] - username [{}]  Connected to chat module through", client.getSessionId().toString(), room, username);
    };
}
private DisconnectListener onDisconnected() {
    return client -> {
        var params = client.getHandshakeData().getUrlParams();
        String room = params.get("room").stream().collect(Collectors.joining());
        String username = params.get("username").stream().collect(Collectors.joining());
        socketService.saveInfoMessage(client, String.format(Constants.DISCONNECT_MESSAGE, username), room);
        log.info("Socket ID[{}] - room[{}] - username [{}]  discnnected to chat module through", client.getSessionId().toString(), room, username);
    };
}
    
    
}
  
  
  Creating controller
Now, to get the message in a certain room, let's create a controller. Open controller package, create a new file called MessageController.java. This is the content for our controller:
package com.tujuhsembilan.socketio.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.tujuhsembilan.socketio.model.Message;
import com.tujuhsembilan.socketio.service.MessageService;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/message")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MessageController {
private final MessageService messageService;
@CrossOrigin
@GetMapping("/{room}")
public ResponseEntity<List<Message>> getMessages(@PathVariable String room) {
    return ResponseEntity.ok(messageService.getMessage(room));
}
    
    
}
  
  
  Running the application
Since I have extension for Spring Boot in my Visual Studio code, I just went into SocketioApplication.java which located in src\main\java\com\tujuhsembilan\socketio\SocketioApplication.java and click Run. If the applicaion running well, this is the kind of log that you will see:

 





 
    
Top comments (2)
Thanks for sharing this. Do you know how to connect socket.io over https?
I am having some issues while running the socket.io over HTTPS as getting Cross-Origin Request Blocked. Here is StackOverflow
Good , I like