<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The Backend Mindset]]></title><description><![CDATA[The Backend Mindset]]></description><link>https://the-backend-mindset.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 06 Sep 2026 01:59:54 GMT</lastBuildDate><atom:link href="https://the-backend-mindset.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How Does Spring Security Work? A Deep Dive Into Its Mechanisms]]></title><description><![CDATA[While building any application, the first and most important thing is that it should work properly. The next thing that comes into the picture is that it should be secure and protected.
Spring security is a powerful framework for securing Spring-base...]]></description><link>https://the-backend-mindset.hashnode.dev/how-does-spring-security-work-a-deep-dive-into-its-mechanisms</link><guid isPermaLink="true">https://the-backend-mindset.hashnode.dev/how-does-spring-security-work-a-deep-dive-into-its-mechanisms</guid><category><![CDATA[Springboot]]></category><category><![CDATA[spring security]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[coding]]></category><category><![CDATA[backend]]></category><category><![CDATA[backend developments]]></category><dc:creator><![CDATA[Gautam Singh Rathore]]></dc:creator><pubDate>Tue, 14 Jan 2025 10:06:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736849108965/499a8416-91b8-42ce-bc8a-7acb2743a053.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While building any application, the first and most important thing is that it should work properly. The next thing that comes into the picture is that it should be secure and protected.</p>
<p>Spring security is a powerful framework for securing Spring-based applications. It offers robust support for authentication, authorization, and protection against common attacks like CSRF.</p>
<p>In this article, we will dive into each component of spring security and understand their roles and flow in detail.</p>
<hr />
<h2 id="heading-spring-security-architecture">Spring Security Architecture</h2>
<p><img src="https://miro.medium.com/v2/resize:fit:875/1*kcfwR4V_9P8VjXz_xMgqZw.png" alt /></p>
<hr />
<h2 id="heading-components-of-architecture">Components of Architecture</h2>
<h3 id="heading-security-filter-chain">Security Filter Chain</h3>
<p>The security filter chain is a series of filters that process incoming HTTP requests in the order they are declared. These filters are the backbone of Spring Security and handle tasks like authentication, authorization, and session management.</p>
<p><strong>Key Filters:</strong></p>
<ul>
<li><p><code>UsernamePasswordAuthenticationFilter</code>: Handles form-based login.</p>
</li>
<li><p><code>BasicAuthenticationFilter</code>: Processes HTTP Basic Authentication.</p>
</li>
<li><p><code>CsrfFilter</code>: Manages CSRF protection.</p>
</li>
<li><p><code>FilterSecurityInterceptor</code>: Performs access control checks.</p>
</li>
</ul>
<p><strong>Configuration:</strong></p>
<p>In spring Security we create a separate <code>SecurityConfig</code> class annotated with @Configuration to provide custom implementations of various components.</p>
<pre><code class="lang-java">    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> SecurityFilterChain <span class="hljs-title">securityFilterChain</span><span class="hljs-params">(HttpSecurity httpSecurity , JwtAuthFilter jwtAuthFilter)</span> <span class="hljs-keyword">throws</span> Exception </span>{
        <span class="hljs-keyword">return</span> httpSecurity
                .csrf(csrf -&gt; csrf.disable())
                .cors(cors -&gt; cors.disable())
                .authorizeHttpRequests(auth -&gt; auth
                        .requestMatchers(<span class="hljs-string">"/auth/v1/login"</span>,<span class="hljs-string">"/auth/v1/signup"</span>,<span class="hljs-string">"/auth/v1/refreshToken"</span>).permitAll()
                        .anyRequest().authenticated()
                )
                .sessionManagement(ses -&gt; ses.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .httpBasic(Customizer.withDefaults())
                .formLogin(customizer -&gt; customizer.disable())
                <span class="hljs-comment">//.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)  -&gt; this way we can add custom filter in the filter chain</span>
                .build();
    }
</code></pre>
<hr />
<h3 id="heading-authentication-manager">Authentication Manager</h3>
<p>The <code>Authentication Manager</code> is the central component that verifies user identities. It coordinates the authentication process and delegates the actual authentication to <code>Authentication Providers</code>.</p>
<p>In more complex systems, you might have multiple Authentication Managers. Each manager can be associated with a specific set of Authentication Providers, allowing you to handle different types of authentication for different parts of your application.</p>
<h4 id="heading-how-it-works">How it works:</h4>
<ul>
<li><p>Takes an <code>Authentication</code> object (credentials, principal).</p>
</li>
<li><p>Passes it to an appropriate <code>AuthenticationProvider</code>.</p>
</li>
<li><p>Returns a fully authenticated <code>Authentication</code> object if successful.</p>
</li>
</ul>
<p><strong>Configuration:</strong></p>
<p>We can define a custom <code>AuthenticationManager</code> in our <code>SecurityConfig</code></p>
<pre><code class="lang-java"> <span class="hljs-meta">@Bean</span>
 <span class="hljs-function"><span class="hljs-keyword">public</span> AuthenticationManager <span class="hljs-title">authenticationManager</span><span class="hljs-params">(AuthenticationConfiguration config)</span> <span class="hljs-keyword">throws</span> Exception </span>{
     <span class="hljs-keyword">return</span> config.getAuthenticationManager();
 }
</code></pre>
<hr />
<h3 id="heading-authentication-provider">Authentication Provider</h3>
<p>The <code>Authentication Providers</code> are the workers of the <code>Authentication Manager</code>. They are responsible for actually performing the authentication.</p>
<p>It is a strategy for authentication and can support multiple providers (eg. database , LDAP)</p>
<h4 id="heading-how-it-works-1">How it works:</h4>
<ul>
<li><p>Checks if it supports the given authentication type.</p>
</li>
<li><p>Retrieves user details (via <code>UserDetailsService</code>).</p>
</li>
<li><p>Verifies credentials (e.g., password).</p>
</li>
<li><p>Returns a valid <code>Authentication</code> object or throws an exception.</p>
</li>
</ul>
<p>Spring Security supports various types of Authentication Providers</p>
<ul>
<li><p><code>DaoAuthenticationProvider</code> <strong>—</strong> uses a <code>UserDetailsService</code> to retrieve user details from database and compare credentials.</p>
</li>
<li><p><code>LdapAuthenticationProvider</code> — used for authenticating against LDAP servers.</p>
</li>
</ul>
<p><strong>Example:</strong></p>
<pre><code class="lang-java">   <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> AuthenticationProvider <span class="hljs-title">authenticationProvider</span><span class="hljs-params">()</span></span>{
         DaoAuthenticationProvider provider = <span class="hljs-keyword">new</span> DaoAuthenticationProvider();
         provider.setPasswordEncoder(passwordEncoder());
         provider.setUserDetailsService(myUserDetailsService);
         <span class="hljs-keyword">return</span> provider;
    }
</code></pre>
<ul>
<li><em>In this snippet, a custom</em> <code>DaoAuthenticationProvider</code> <em>is defined, configured with a</em> <code>UserDetailsService</code> <em>and a</em> <code>PasswordEncoder</code><em>.</em></li>
</ul>
<p><strong>Spring’s Default Behaviour:</strong></p>
<p>If no custom <code>AuthenticationManager</code> is defined, Spring Security automatically creates one and registers all available <code>AuthenticationProvider</code>s.</p>
<p>You don't need to define a custom <code>AuthenticationManager</code> if:</p>
<ul>
<li><p>You rely on Spring's default <code>ProviderManager</code> to aggregate multiple <code>AuthenticationProvider</code>s.</p>
</li>
<li><p>You only want to define and plug in custom logic through an <code>AuthenticationProvider</code>.</p>
</li>
<li><p><strong>Example:</strong> In the above example we don’t need to define custom AuthenticationManager.</p>
</li>
</ul>
<p>You should define your own <code>AuthenticationManager</code> if:</p>
<ul>
<li><p>You need full control over how providers are registered and chained.</p>
</li>
<li><p>You want to explicitly configure how the <code>AuthenticationManager</code> interacts with one or more <code>AuthenticationProvider</code>s.</p>
</li>
<li><p><strong>Example:</strong> Custom AuthenticationManager with multiple providers.</p>
</li>
<li><pre><code class="lang-java">  <span class="hljs-meta">@Bean</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> AuthenticationManager <span class="hljs-title">customAuthenticationManager</span><span class="hljs-params">()</span> </span>{
      DaoAuthenticationProvider daoProvider = <span class="hljs-keyword">new</span> DaoAuthenticationProvider();
      daoProvider.setUserDetailsService(customUserDetailsService);
      daoProvider.setPasswordEncoder(passwordEncoder());

      CustomAuthenticationProvider customProvider = <span class="hljs-keyword">new</span> CustomAuthenticationProvider();

      <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ProviderManager(Arrays.asList(daoProvider, customProvider));
  }
</code></pre>
</li>
<li><p>Now you must be thinking about</p>
</li>
<li><p>how the auth manager chooses which provider to use. The answer is in Spring Security, when multiple authentication providers are configured, the <code>AuthenticationManager</code> chooses which one to use based on the order they are defined. By default, it tries each provider in the order they are listed in the <code>AuthenticationManager</code> configuration, stopping as soon as one successfully authenticates the user.</p>
</li>
</ul>
<hr />
<h3 id="heading-password-encoder">Password Encoder:</h3>
<p>The <code>PasswordEncoder</code> handles password hashing and verification . Storing plain-text passwords is insecure.</p>
<ul>
<li><p><code>BCryptPasswordEncoder</code> - this is widely recommended choice for securely hashing passwords in Spring Security</p>
</li>
<li><p><code>StandardPasswordEncoder</code> - this encoder uses one-way hashing algorithm which is less secure and it is not recommended.</p>
</li>
<li><p><code>MessageDigestPasswordEncoder</code> - this encoder uses a specified message digest algorithm (e.g., SHA-256) to hash passwords. While it’s more secure than plain text, it’s not as strong as BCrypt and is considered less secure in modern applications.</p>
</li>
<li><p><code>SCryptPasswordEncoder</code> - SCrypt is another secure password hashing algorithm, similar to BCrypt. It’s designed to be memory-intensive, making it resistant to certain types of attacks. SCryptPasswordEncoder is a good choice for secure password hashing.</p>
</li>
</ul>
<p><strong>Example:</strong></p>
<pre><code class="lang-java"><span class="hljs-meta">@Bean</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> PasswordEncoder <span class="hljs-title">passwordEncoder</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder(<span class="hljs-number">12</span>); <span class="hljs-comment">// here 12 is the strength or rounds of hashing .</span>
    <span class="hljs-comment">// the default strength is 10 and it can lie between 0 to 20</span>
    <span class="hljs-comment">// setting high strength can lead to delay in the process</span>
}
</code></pre>
<hr />
<h3 id="heading-userdetailsservice">UserDetailsService</h3>
<p>The <code>UserDetailsService</code> is a core interface for loading user-specific data. It is used by the <code>AuthenticationProvider</code> to retrieve user details from a database or another source.</p>
<pre><code class="lang-java">   <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDetailsServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserDetailsService</span> </span>{
    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">public</span> UserRepository userRepository;

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> UserDetails <span class="hljs-title">loadUserByUsername</span><span class="hljs-params">(String username)</span> <span class="hljs-keyword">throws</span> UsernameNotFoundException </span>{
        Optional&lt;User&gt; user = userRepository.findById(username);
        <span class="hljs-keyword">if</span> (user.isEmpty()) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UsernameNotFoundException(<span class="hljs-string">"user not found with this username"</span>);
        }

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> UserDetailsImpl(user.get());
    }
}
</code></pre>
<ul>
<li><em>The</em> <code>UserDetailsServiceImpl</code> <em>class is implemented as a custom</em> <code>UserDetailsService</code><em>, and it overrides the</em> <code>loadUserByUsername</code> <em>method to retrieve user details from a database via a</em> <code>UserRepository</code><em>.</em></li>
</ul>
<hr />
<h3 id="heading-security-context-holder">Security Context Holder</h3>
<p>The <code>SecurityContextHolder</code> is the foundation of Spring Security's thread-based security model. It's used to store and retrieve the <code>SecurityContext</code>, which contains authentication and possibly other security-related details.</p>
<h4 id="heading-how-it-works-2">How it Works:</h4>
<ul>
<li><p>When a user successfully authenticates, the resulting <code>Authentication</code> object is stored in the <code>SecurityContext</code>.</p>
</li>
<li><p>The <code>SecurityContextHolder</code> uses thread-local storage to keep the security context tied to the current thread.</p>
</li>
<li><p>Once the request is complete, Spring Security clears the <code>SecurityContextHolder</code> to avoid data leaks.</p>
</li>
</ul>
<p><strong>Key Methods:</strong></p>
<pre><code class="lang-java"><span class="hljs-comment">// Set Authentication</span>
Authentication authentication = <span class="hljs-keyword">new</span> UsernamePasswordAuthenticationToken(user, password, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
</code></pre>
<pre><code class="lang-java"><span class="hljs-comment">// Get Authentication</span>
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
</code></pre>
<pre><code class="lang-java"><span class="hljs-comment">// Clear Context</span>
SecurityContextHolder.clearContext();
</code></pre>
<h4 id="heading-common-issues"><strong>Common Issues:</strong></h4>
<ul>
<li><p><strong>Data Not Persisting Across Threads:</strong></p>
<ul>
<li><p>By default, <code>SecurityContextHolder</code> uses <code>ThreadLocal</code> storage. If the execution spans multiple threads (e.g., asynchronous processing), the security context won't carry over.</p>
</li>
<li><p>Solution<strong>:</strong> Use <code>SecurityContextHolder.MODE_INHERITABLETHREADLOCAL</code> to propagate the context to child threads:</p>
<pre><code class="lang-java">  SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
</code></pre>
</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>Null Authentication:</strong></p>
<ul>
<li><p>This occurs if the security context is not set (e.g., during unauthenticated access or manual testing).</p>
</li>
<li><p>Solution<strong>:</strong> Ensure authentication is set programmatically in tests or correctly configured in the filter chain.</p>
</li>
</ul>
</li>
</ul>
<p><strong>Best Practices:</strong></p>
<ul>
<li><p>It is not recommended to access it directly in business logic instead we can use @AuthenticationPrincipal annotation in the controller instead.</p>
</li>
<li><pre><code class="lang-java">  <span class="hljs-meta">@GetMapping("/profile")</span>
  <span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; getProfile(<span class="hljs-meta">@AuthenticationPrincipal</span> UserDetails user) {
      <span class="hljs-keyword">return</span> ResponseEntity.ok(user);
  }
</code></pre>
</li>
</ul>
<hr />
<h3 id="heading-principal">Principal :</h3>
<p>The Principal in Spring Security refers to the currently authenticated user.t represents the identity of the user interacting with the application and is stored in the <code>SecurityContext</code>.</p>
<p>It is part of <code>Authentication</code> object stored in <code>SecurityContext</code>. It can be any object that represents the authenticated user, often an instance of <code>UserDetails</code> or a custom implemetation of it.</p>
<p><strong>Accessing the Principal:</strong></p>
<p>a. Using <code>SecurityContextHolder</code></p>
<pre><code class="lang-java"><span class="hljs-meta">@GetMapping("/profile")</span>
<span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; getProfile() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    Object principal = authentication.getPrincipal();

    <span class="hljs-keyword">if</span> (principal <span class="hljs-keyword">instanceof</span> UserDetails) {
        String username = ((UserDetails) principal).getUsername();
        <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"Logged in user: "</span> + username);
    }

    <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"Anonymous user"</span>);
}
</code></pre>
<p>b. Using <code>@AuthenticationPrincipal</code></p>
<pre><code class="lang-java"><span class="hljs-meta">@GetMapping("/profile")</span>
<span class="hljs-keyword">public</span> ResponseEntity&lt;?&gt; getProfile(<span class="hljs-meta">@AuthenticationPrincipal</span> UserDetails user) {
    <span class="hljs-keyword">return</span> ResponseEntity.ok(<span class="hljs-string">"Logged in user: "</span> + user.getUsername());
}
</code></pre>
<p>Here’s how the principal flows through the authentication process:</p>
<ol>
<li><p><strong>Login Attempt:</strong></p>
<ul>
<li>The user submits their credentials (e.g., username and password).</li>
</ul>
</li>
<li><p><strong>AuthenticationManager Delegation:</strong></p>
<ul>
<li>The <code>AuthenticationManager</code> delegates authentication to an <code>AuthenticationProvider</code>.</li>
</ul>
</li>
<li><p><strong>UserDetails Loaded:</strong></p>
<ul>
<li><p>The <code>UserDetailsService</code> loads the user's details (username, password, roles).</p>
</li>
<li><p>The <code>UserDetails</code> instance is set as the <code>principal</code>.</p>
</li>
</ul>
</li>
<li><p><strong>SecurityContext Updated:</strong></p>
<ul>
<li>If authentication is successful, the <code>Authentication</code> object is stored in the <code>SecurityContext</code>.</li>
</ul>
</li>
<li><p><strong>Accessing Principal:</strong></p>
<ul>
<li>Throughout the session, the principal can be accessed via the <code>SecurityContext</code>.</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-working-flow">Working Flow</h2>
<p>Now let us combine all our learnings and understand the whole flow of architecture.</p>
<p><img src="https://miro.medium.com/v2/resize:fit:875/1*bXZoyANJiP9aqxSqtFbo_A.png" alt /></p>
<ol>
<li><p>The request is intercepted by the <code>Security Filter Chain</code>. The Security Filter Chain consists of a series of filters, each with a specific security-related task.</p>
</li>
<li><p>If the user is not yet authenticated (i.e., not logged in), Spring Security’s authentication filters will trigger the <code>Authentication Manager</code>. If the credentials match, the Authentication Manager generates an <code>Authentication Object</code> indicating a successful authentication.</p>
</li>
<li><p>The <code>Authentication Manager</code> uses the configured <code>Authentication Providers</code> to verify the user’s credentials.</p>
</li>
<li><p><code>Authentication Providers</code> will use the <code>PasswordEncoder</code> to store and compare passwords.</p>
</li>
<li><p><code>Authentication Providers</code> may use the <code>UserDetailsService</code> to fetch user details. The user’s credentials are compared to the stored or provided credentials.</p>
</li>
<li><p><code>UserDetailsService</code> will fetch the data from the database.</p>
</li>
<li><p>The status of the authentication process will be sent to the user as a success or unauthorized response.</p>
</li>
<li><p>This Authentication object is stored within the security context managed by <code>SecurityContextHolder</code>. The security context now represents the authenticated user.</p>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope this article has helped you understand the key components and the feel of spring security.</p>
<p>Following this article I will publish another article in which we will see how can we implement JWT-based authentication in our spring boot application do check it out and subscribe to my newsletter so that we can learn together.</p>
<p>Thank you for reading and Happy Coding</p>
<p><a target="_blank" href="https://github.com/Gautam-Singh-Rathore">GitHub</a></p>
<p><a target="_blank" href="https://www.linkedin.com/in/gautam-singh-rathore-java/">LinkedIn</a></p>
<p><a target="_blank" href="https://hashnode.com/@gautam-singh">Hashnode</a></p>
]]></content:encoded></item><item><title><![CDATA[Building a Real-Time Chat Application with Spring Boot, WebSocket's, and STOMP: A Comprehensive Guide]]></title><description><![CDATA[In today's digital age, real-time communication has become an essential feature for many applications, ranging from chat systems and live notifications to multiplayer games and collaborative tools. Traditional HTTP protocols, while reliable for reque...]]></description><link>https://the-backend-mindset.hashnode.dev/building-a-real-time-chat-application-with-spring-boot-websockets-and-stomp-a-comprehensive-guide</link><guid isPermaLink="true">https://the-backend-mindset.hashnode.dev/building-a-real-time-chat-application-with-spring-boot-websockets-and-stomp-a-comprehensive-guide</guid><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[websockets]]></category><category><![CDATA[coding]]></category><category><![CDATA[learning]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Gautam Singh Rathore]]></dc:creator><pubDate>Mon, 23 Sep 2024 15:22:31 GMT</pubDate><content:encoded><![CDATA[<p>In today's digital age, real-time communication has become an essential feature for many applications, ranging from chat systems and live notifications to multiplayer games and collaborative tools. Traditional HTTP protocols, while reliable for request-response interactions, fall short when it comes to real-time, bidirectional communication. This is where <strong>WebSockets</strong> and <strong>STOMP</strong> (Simple Text Oriented Messaging Protocol) come into play, offering a robust solution for building interactive, real-time applications.</p>
<p>In this article, we will delve deep into the world of WebSockets and STOMP, exploring their necessity, underlying protocols, and how to implement them using <strong>Spring Boot</strong>. By the end of this guide, you'll have a thorough understanding of these technologies and how to leverage them to build a functional real-time chat application.</p>
<hr />
<h2 id="heading-understanding-http-vs-websockets"><strong>Understanding HTTP vs. WebSockets</strong></h2>
<h3 id="heading-http-the-foundation-of-the-web">HTTP: The Foundation of the Web</h3>
<p><strong>HyperText Transfer Protocol (HTTP)</strong> is the backbone of data communication on the World Wide Web. It operates on a <strong>request-response</strong> model, where a client (typically a web browser) sends a request to a server, and the server responds with the requested data. This model is stateless and unidirectional, meaning each request is independent, and the server cannot initiate communication.</p>
<p><strong>Key Characteristics of HTTP:</strong></p>
<ul>
<li><p><strong>Stateless:</strong> Each request is independent; the server does not retain any session information between requests.</p>
</li>
<li><p><strong>Unidirectional:</strong> Communication flows from client to server.</p>
</li>
<li><p><strong>Request-Response Cycle:</strong> The client must initiate each interaction.</p>
</li>
</ul>
<h3 id="heading-websockets-breaking-the-mold">WebSockets: Breaking the Mold</h3>
<p><strong>WebSockets</strong> provide a way to establish a <strong>persistent, full-duplex</strong> communication channel between the client and server. Unlike HTTP, WebSockets allow both parties to send messages independently at any time, facilitating real-time, bidirectional data exchange.</p>
<p><strong>Key Characteristics of WebSockets:</strong></p>
<ul>
<li><p><strong>Stateful:</strong> Maintains an open connection, allowing continuous communication.</p>
</li>
<li><p><strong>Bidirectional:</strong> Both client and server can send messages independently.</p>
</li>
<li><p><strong>Full-Duplex Communication:</strong> Simultaneous two-way data transfer.</p>
</li>
<li><p><strong>Low Latency:</strong> Minimal overhead after the initial connection, enabling near-instantaneous communication.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727104165042/a9f58e0a-d952-4ce5-835b-96eecb958573.png" alt class="image--center mx-auto" /></p>
<hr />
<h2 id="heading-why-use-websockets-the-need-for-real-time-communication">Why Use WebSockets? The Need for Real-Time Communication</h2>
<p>In applications where real-time data exchange is crucial, traditional HTTP falls short. Consider the following scenarios:</p>
<ol>
<li><p><strong>Chat Applications:</strong> Users expect instant message delivery without the need for constant polling.</p>
</li>
<li><p><strong>Live Sports Updates:</strong> Scores and events need to be updated in real-time.</p>
</li>
<li><p><strong>Collaborative Editing:</strong> Multiple users editing a document simultaneously require immediate synchronization.</p>
</li>
<li><p><strong>Online Gaming:</strong> Real-time interactions are essential for a seamless gaming experience.</p>
</li>
<li><p><strong>Live Dashboards:</strong> Financial markets, system monitoring, and other real-time dashboards benefit from instant data updates.</p>
</li>
</ol>
<p>In these cases, WebSockets provide the necessary infrastructure to handle continuous, low-latency communication efficiently, enhancing user experience and application performance.</p>
<hr />
<h2 id="heading-an-overview-of-the-websocket-protocol">An Overview of the WebSocket Protocol</h2>
<p>The <strong>WebSocket protocol</strong> is standardized as <strong>RFC 6455</strong> and operates over TCP. It begins with an <strong>HTTP handshake</strong> to establish the connection, which is then upgraded to a WebSocket connection. Once established, the protocol switches from HTTP to a bidirectional communication channel using <strong>WebSocket frames</strong>.</p>
<h3 id="heading-key-components-of-websocket">Key Components of WebSocket:</h3>
<ol>
<li><strong>Handshake:</strong> An initial HTTP request that upgrades the connection to WebSocket.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727104367033/481a1073-bec5-4810-b908-5753949d1395.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Frames:</strong> The basic units of communication, encapsulating data and control messages.</p>
</li>
<li><p><strong>Full-Duplex Communication:</strong> Allows simultaneous sending and receiving of messages.</p>
</li>
<li><p><strong>Persistent Connection:</strong> Maintains an open connection until explicitly closed by either party.</p>
</li>
</ol>
<h3 id="heading-websocket-frames">WebSocket Frames:</h3>
<p>Each frame contains the following components:</p>
<ul>
<li><p><strong>FIN Bit:</strong> Indicates if the frame is the final fragment in a message.</p>
</li>
<li><p><strong>Opcode:</strong> Defines the type of frame (e.g., text, binary, close, ping, pong).</p>
</li>
<li><p><strong>Masking Key:</strong> Used to obfuscate payload data (client-to-server frames must be masked).</p>
</li>
<li><p><strong>Payload Data:</strong> The actual data being transmitted.</p>
</li>
</ul>
<hr />
<h2 id="heading-introducing-stomp-simplifying-messaging">Introducing STOMP: Simplifying Messaging</h2>
<p>While WebSockets provide a robust communication channel, they operate at a low level, handling only the exchange of frames without any messaging semantics. This is where <strong>STOMP</strong> (Simple Text Oriented Messaging Protocol) comes into play.</p>
<p><strong>STOMP</strong> is a lightweight, text-based messaging protocol designed to work with message brokers. It adds a layer of messaging semantics on top of WebSockets, enabling structured message routing, subscriptions, and acknowledgments.</p>
<h3 id="heading-key-features-of-stomp">Key Features of STOMP:</h3>
<ul>
<li><p><strong>Command-Based Communication:</strong> Defines specific commands like <code>SEND</code>, <code>SUBSCRIBE</code>, <code>MESSAGE</code>, <code>ACK</code>, <code>NACK</code>, and <code>DISCONNECT</code>.</p>
</li>
<li><p><strong>Destination-Based Routing:</strong> Messages are sent to destinations (topics or queues) where clients can subscribe.</p>
</li>
<li><p><strong>Subscription Management:</strong> Clients can subscribe or unsubscribe from specific destinations.</p>
</li>
<li><p><strong>Message Acknowledgment:</strong> Supports various acknowledgment modes to ensure reliable message delivery.</p>
<h3 id="heading-example-stomp-frame">Example STOMP Frame:</h3>
<pre><code class="lang-plaintext">  SEND
  destination:/topic/chatroom
  content-type:text/plain

  Hello, Chatroom!
</code></pre>
<ul>
<li><p><strong>Command:</strong> <code>SEND</code></p>
</li>
<li><p><strong>Headers:</strong> <code>destination</code>, <code>content-type</code></p>
</li>
<li><p><strong>Body:</strong> <code>Hello, Chatroom!</code></p>
</li>
</ul>
</li>
</ul>
<hr />
<h3 id="heading-why-use-stomp-with-websockets">Why Use STOMP with WebSockets?</h3>
<p>While WebSockets excel at enabling real-time, bidirectional communication, managing messaging semantics like routing, subscriptions, and message types can become cumbersome. <strong>STOMP</strong> simplifies this process by providing a standardized way to handle messaging patterns commonly required in real-time applications.</p>
<h3 id="heading-benefits-of-combining-stomp-with-websockets">Benefits of Combining STOMP with WebSockets:</h3>
<ol>
<li><p><strong>Structured Messaging:</strong> STOMP commands and headers provide a clear structure for messages, making them easier to manage and debug.</p>
</li>
<li><p><strong>Destination-Based Routing:</strong> Easily route messages to specific topics or queues, facilitating both publish-subscribe and point-to-point messaging models.</p>
</li>
<li><p><strong>Subscription Management:</strong> Clients can dynamically subscribe or unsubscribe from destinations, allowing flexible message consumption.</p>
</li>
<li><p><strong>Message Acknowledgments:</strong> Ensure reliable message delivery with acknowledgment mechanisms, preventing message loss.</p>
</li>
<li><p><strong>Integration with Message Brokers:</strong> STOMP seamlessly integrates with message brokers like RabbitMQ, ActiveMQ, or Spring's built-in message broker, enhancing scalability and reliability.</p>
</li>
</ol>
<hr />
<h3 id="heading-establishing-a-websocket-connection-from-http-upgrade-to-full-duplex-communication">Establishing a WebSocket Connection: From HTTP Upgrade to Full-Duplex Communication</h3>
<p>Establishing a WebSocket connection involves several steps, starting with an HTTP request and culminating in a persistent, bidirectional communication channel. Let's walk through the process.</p>
<h3 id="heading-1-client-initiates-handshake">1. <strong>Client Initiates Handshake</strong></h3>
<p>The client sends an HTTP request to the server, requesting an upgrade to the WebSocket protocol. The request includes specific headers indicating the desire to establish a WebSocket connection.</p>
<p><strong>Example Handshake Request:</strong></p>
<pre><code class="lang-plaintext">GET /chat HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13
</code></pre>
<h3 id="heading-2-server-responds-with-upgrade-confirmation">2. <strong>Server Responds with Upgrade Confirmation</strong></h3>
<p>If the server supports WebSockets and accepts the request, it responds with a <code>101 Switching Protocols</code> status, confirming the upgrade.</p>
<p><strong>Example Handshake Response:</strong></p>
<pre><code class="lang-plaintext">HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
</code></pre>
<h3 id="heading-3-websocket-connection-established">3. <strong>WebSocket Connection Established</strong></h3>
<p>Once the handshake is successful, the protocol switches from HTTP to WebSocket. The connection remains open, allowing both client and server to send messages independently.</p>
<h3 id="heading-4-full-duplex-communication">4. <strong>Full-Duplex Communication</strong></h3>
<p>Both parties can now send messages at any time without the need for additional HTTP requests. Messages are encapsulated in WebSocket frames, ensuring efficient data transfer.</p>
<h3 id="heading-diagram-websocket-connection-flow">Diagram: WebSocket Connection Flow</h3>
<pre><code class="lang-plaintext">Client                               Server
  |                                     |
  |----- HTTP Upgrade Request --------&gt; |
  |                                     |
  |&lt;----- HTTP Upgrade Response --------|
  |                                     |
  |-------- WebSocket Frames ----------&gt;|
  |&lt;------- WebSocket Frames -----------|
  |                                     |
  |-------- WebSocket Frames ----------&gt;|
  |&lt;------- WebSocket Frames -----------|
  |                                     |
  |-------- Close Frame ----------------|
  |&lt;------- Close Frame ----------------|
  |                                     |
</code></pre>
<hr />
<h3 id="heading-building-a-real-time-chat-application-with-spring-boot-websockets-and-stomp">Building a Real-Time Chat Application with Spring Boot, WebSockets, and STOMP</h3>
<p>With a solid understanding of WebSockets and STOMP, let's apply this knowledge to build a real-time chat application using <strong>Spring Boot</strong>. This section will guide you through the entire process, from setting up the project to implementing backend and frontend functionalities.</p>
<h3 id="heading-backend-configuration">Backend Configuration</h3>
<h3 id="heading-setting-up-spring-boot-with-websockets">Setting Up Spring Boot with WebSockets</h3>
<p>To begin, the backend is powered by <strong>Spring Boot</strong> and leverages <strong>STOMP</strong> over WebSockets to facilitate real-time communication between the client and server. Here's a step-by-step breakdown of how we achieve this.</p>
<h4 id="heading-add-dependencies">Add Dependencies</h4>
<p>In your <code>pom.xml</code>, make sure to include the necessary Spring dependencies for WebSockets and messaging.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Spring Boot Starter for WebSockets --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-websocket<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Spring Boot Starter for Web --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Spring Boot Starter for Messaging (STOMP support) --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-websocket<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>
</code></pre>
<h4 id="heading-1-websocket-configuration">1. <strong>WebSocket Configuration</strong></h4>
<p>To set up WebSockets in Spring Boot, you need to configure the WebSocket message broker and define WebSocket endpoints. This is done using the <code>@EnableWebSocketMessageBroker</code> annotation and implementing the <code>WebSocketMessageBrokerConfigurer</code> interface.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.gautam.ChatApplication.config;

<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.messaging.simp.config.MessageBrokerRegistry;
<span class="hljs-keyword">import</span> org.springframework.web.socket.config.annotation.*;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableWebSocketMessageBroker</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSocketConfig</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">WebSocketMessageBrokerConfigurer</span> </span>{

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerStompEndpoints</span><span class="hljs-params">(StompEndpointRegistry registry)</span> </span>{
        registry.addEndpoint(<span class="hljs-string">"/ws"</span>) <span class="hljs-comment">// WebSocket endpoint</span>
                .setAllowedOrigins(<span class="hljs-string">"*"</span>) <span class="hljs-comment">// Allow cross-origin requests</span>
                .withSockJS(); <span class="hljs-comment">// Enable SockJS fallback options</span>
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configureMessageBroker</span><span class="hljs-params">(MessageBrokerRegistry config)</span> </span>{
        config.enableSimpleBroker(<span class="hljs-string">"/topic"</span>, <span class="hljs-string">"/queue"</span>); <span class="hljs-comment">// In-memory message broker</span>
        config.setApplicationDestinationPrefixes(<span class="hljs-string">"/app"</span>); <span class="hljs-comment">// Prefix for application destinations</span>
    }
}
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>@Configuration</code> and <code>@EnableWebSocketMessageBroker</code>: Indicates that this class contains Spring configuration and enables WebSocket message handling, backed by a message broker.</p>
</li>
<li><p><code>registerStompEndpoints</code>: Defines the <code>/ws</code> endpoint that clients will use to connect to the WebSocket. <code>withSockJS()</code> enables fallback options for browsers that don’t support WebSockets.</p>
</li>
<li><p><code>configureMessageBroker</code>: Configures the message broker. The simple in-memory broker is enabled for destinations prefixed with <code>/topic</code> and <code>/queue</code>. Messages sent to destinations starting with <code>/app</code> are routed to message-handling methods.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727104554976/9bbd0c78-e0e0-4f1f-a641-d5a4b1415407.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-2-chat-controller">2. <strong>Chat Controller</strong></h4>
<p>The <code>ChatController</code> handles incoming WebSocket messages and routes them to the appropriate destinations.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.gautam.ChatApplication.chat;

<span class="hljs-keyword">import</span> org.springframework.messaging.handler.annotation.MessageMapping;
<span class="hljs-keyword">import</span> org.springframework.messaging.handler.annotation.Payload;
<span class="hljs-keyword">import</span> org.springframework.messaging.handler.annotation.SendTo;
<span class="hljs-keyword">import</span> org.springframework.messaging.simp.SimpMessageHeaderAccessor;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;

<span class="hljs-meta">@Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChatController</span> </span>{

    <span class="hljs-meta">@MessageMapping("/chat.sendMessage")</span>
    <span class="hljs-meta">@SendTo("/topic/public")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ChatMessage <span class="hljs-title">sendMessage</span><span class="hljs-params">(<span class="hljs-meta">@Payload</span> ChatMessage chatMessage)</span> </span>{
        <span class="hljs-keyword">return</span> chatMessage;
    }

    <span class="hljs-meta">@MessageMapping("/chat.addUser")</span>
    <span class="hljs-meta">@SendTo("/topic/public")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ChatMessage <span class="hljs-title">addUser</span><span class="hljs-params">(<span class="hljs-meta">@Payload</span> ChatMessage chatMessage,
                               SimpMessageHeaderAccessor headerAccessor)</span> </span>{
        <span class="hljs-comment">// Add username to WebSocket session</span>
        headerAccessor.getSessionAttributes().put(<span class="hljs-string">"username"</span>, chatMessage.getSender());
        <span class="hljs-keyword">return</span> chatMessage;
    }
}
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>@Controller</code>: Marks the class as a Spring MVC Controller to handle WebSocket messages.</p>
</li>
<li><p><code>@MessageMapping</code>: Maps incoming messages to specific methods based on the destination. For example, messages sent to <code>/app/chat.sendMessage</code> are handled by <code>sendMessage()</code>.</p>
</li>
<li><p><code>@SendTo</code>: Specifies the destination to which the return value will be sent. In this case, messages are broadcasted to <code>/topic/public</code>.</p>
</li>
<li><p><code>@Payload</code>: Binds the message payload to a method parameter.</p>
</li>
<li><p><code>SimpMessageHeaderAccessor</code>: Allows access to the message headers, enabling the addition of session attributes like <code>username</code>.</p>
</li>
</ul>
<h4 id="heading-3-chat-message-model">3. <strong>Chat Message Model</strong></h4>
<p>The <code>ChatMessage</code> class represents the structure of chat messages exchanged between clients and the server.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.gautam.ChatApplication.chat;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChatMessage</span> </span>{
    <span class="hljs-keyword">private</span> String sender;
    <span class="hljs-keyword">private</span> String content;
    <span class="hljs-keyword">private</span> MessageType type;

    <span class="hljs-comment">// Constructors</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ChatMessage</span><span class="hljs-params">()</span> </span>{
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ChatMessage</span><span class="hljs-params">(String sender, String content, MessageType type)</span> </span>{
        <span class="hljs-keyword">this</span>.sender = sender;
        <span class="hljs-keyword">this</span>.content = content;
        <span class="hljs-keyword">this</span>.type = type;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ChatMessage</span><span class="hljs-params">(String sender, MessageType type)</span> </span>{
        <span class="hljs-keyword">this</span>.sender = sender;
        <span class="hljs-keyword">this</span>.type = type;
    }

    <span class="hljs-comment">// Getters and Setters</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getSender</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> sender;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSender</span><span class="hljs-params">(String sender)</span> </span>{
        <span class="hljs-keyword">this</span>.sender = sender;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getContent</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> content;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setContent</span><span class="hljs-params">(String content)</span> </span>{
        <span class="hljs-keyword">this</span>.content = content;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> MessageType <span class="hljs-title">getType</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> type;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setType</span><span class="hljs-params">(MessageType type)</span> </span>{
        <span class="hljs-keyword">this</span>.type = type;
    }
}
</code></pre>
<h4 id="heading-4-message-type-enum">4. <strong>Message Type Enum</strong></h4>
<p>The <code>MessageType</code> enum defines the types of messages that can be exchanged, such as chat messages, user join, and user leave events.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.gautam.ChatApplication.chat;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">MessageType</span> </span>{
    CHAT,
    JOIN,
    LEAVE
}
</code></pre>
<h4 id="heading-5-handling-websocket-events">5. <strong>Handling WebSocket Events</strong></h4>
<p>To manage user connections and disconnections, an event listener is implemented. This listener captures disconnection events and notifies other users when someone leaves the chat.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.gautam.ChatApplication.config;

<span class="hljs-keyword">import</span> com.gautam.ChatApplication.chat.ChatMessage;
<span class="hljs-keyword">import</span> com.gautam.ChatApplication.chat.MessageType;
<span class="hljs-keyword">import</span> lombok.RequiredArgsConstructor;
<span class="hljs-keyword">import</span> lombok.extern.slf4j.Slf4j;
<span class="hljs-keyword">import</span> org.slf4j.Logger;
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;
<span class="hljs-keyword">import</span> org.springframework.context.event.EventListener;
<span class="hljs-keyword">import</span> org.springframework.messaging.simp.SimpMessageSendingOperations;
<span class="hljs-keyword">import</span> org.springframework.messaging.simp.stomp.StompHeaderAccessor;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;
<span class="hljs-keyword">import</span> org.springframework.web.socket.messaging.SessionDisconnectEvent;

<span class="hljs-meta">@Component</span>
<span class="hljs-meta">@RequiredArgsConstructor</span>
<span class="hljs-meta">@Slf4j</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSocketEventListener</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger log = LoggerFactory.getLogger(WebSocketEventListener.class);

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> SimpMessageSendingOperations messageTemplate;

    <span class="hljs-meta">@EventListener</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleWebSocketDisconnect</span><span class="hljs-params">(SessionDisconnectEvent event)</span> </span>{
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        String username = (String) headerAccessor.getSessionAttributes().get(<span class="hljs-string">"username"</span>);
        <span class="hljs-keyword">if</span> (username != <span class="hljs-keyword">null</span>) {
            log.info(<span class="hljs-string">"User disconnected: {}"</span>, username);
            ChatMessage chatMessage = <span class="hljs-keyword">new</span> ChatMessage(username, MessageType.LEAVE);
            messageTemplate.convertAndSend(<span class="hljs-string">"/topic/public"</span>, chatMessage);
        }
    }
}
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><code>@Component</code>: Marks the class as a Spring bean for component scanning.</p>
</li>
<li><p><code>@RequiredArgsConstructor</code>: Lombok annotation to generate a constructor for <code>messageTemplate</code>, enabling dependency injection.</p>
</li>
<li><p><code>@Slf4j</code>: Lombok annotation to generate a logger instance.</p>
</li>
<li><p><code>@EventListener</code>: Listens for <code>SessionDisconnectEvent</code>, which is triggered when a WebSocket session is closed.</p>
</li>
<li><p><code>handleWebSocketDisconnect()</code>: Retrieves the username from session attributes and broadcasts a leave message to <code>/topic/public</code>.</p>
</li>
</ul>
<hr />
<h2 id="heading-frontend-using-sockjs-and-stomp-in-javascript">Frontend: Using SockJS and STOMP in JavaScript</h2>
<p>For the frontend, we can use <strong>SockJS</strong> and <strong>STOMP</strong> to connect to the WebSocket server. Here’s how you can set up the basic client-side logic.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Connecting to WebSocket</span>
<span class="hljs-keyword">const</span> socket = <span class="hljs-keyword">new</span> SockJS(<span class="hljs-string">'http://localhost:8080/ws'</span>);  <span class="hljs-comment">// Connect to the WebSocket endpoint</span>
<span class="hljs-keyword">const</span> stompClient = Stomp.over(socket);

<span class="hljs-comment">// Function to connect to the WebSocket server</span>
stompClient.connect({}, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">frame</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Connected: '</span> + frame);

    <span class="hljs-comment">// Subscribe to the topic where messages will be broadcast</span>
    stompClient.subscribe(<span class="hljs-string">'/topic/messages'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">message</span>) </span>{
        <span class="hljs-keyword">const</span> msgContent = <span class="hljs-built_in">JSON</span>.parse(message.body);
        showMessage(msgContent.content, msgContent.sender); <span class="hljs-comment">// Display received message</span>
    });
});

<span class="hljs-comment">// Function to send messages</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendMessage</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> messageContent = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'message'</span>).value;
    <span class="hljs-keyword">const</span> sender = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'sender'</span>).value;

    stompClient.send(<span class="hljs-string">"/app/chat"</span>, {}, <span class="hljs-built_in">JSON</span>.stringify({
        <span class="hljs-string">'content'</span>: messageContent,
        <span class="hljs-string">'sender'</span>: sender
    }));
}

<span class="hljs-comment">// Function to display messages on the page</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">showMessage</span>(<span class="hljs-params">message, sender</span>) </span>{
    <span class="hljs-keyword">const</span> messagesDiv = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'messages'</span>);
    messagesDiv.innerHTML += <span class="hljs-string">`&lt;p&gt;&lt;strong&gt;<span class="hljs-subst">${sender}</span>:&lt;/strong&gt; <span class="hljs-subst">${message}</span>&lt;/p&gt;`</span>;
}
</code></pre>
<ul>
<li><p><code>SockJS('</code><a target="_blank" href="http://localhost:8080/ws"><code>http://localhost:8080/ws</code></a><code>')</code>: This connects to the WebSocket endpoint defined in the Spring Boot backend.</p>
</li>
<li><p><code>stompClient.subscribe('/topic/messages', ...)</code>: Subscribes to the broadcast channel where messages are sent by the server.</p>
</li>
<li><p><code>stompClient.send(...)</code>: Sends a message to the server.</p>
</li>
</ul>
<h3 id="heading-explanation-of-sockjs-functions">Explanation of SockJS Functions</h3>
<ul>
<li><p><code>SockJS</code>: Provides WebSocket fallback options for browsers that don’t natively support WebSockets.</p>
</li>
<li><p><code>Stomp.over(socket)</code>: Uses the WebSocket connection to communicate using the STOMP protocol.</p>
</li>
<li><p><code>stompClient.connect()</code>: Establishes the connection between the client and server.</p>
</li>
<li><p><code>stompClient.subscribe()</code>: Listens for messages broadcast from the server.</p>
</li>
<li><p><code>stompClient.send()</code>: Sends a message from the client to the server.</p>
</li>
</ul>
<p>This is the basic setup for real-time communication using WebSockets on the client side.</p>
<hr />
<h3 id="heading-connect-with-me">Connect with me</h3>
<p>For a complete implementation, please check my GitHub and LinkedIn:</p>
<ul>
<li><p><a target="_blank" href="https://github.com/Gautam-Singh-Rathore/Learning-WebSockets/tree/main"><strong>GitHub</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.linkedin.com/in/gautam-singh-rathore-74967428b/"><strong>LinkedIn</strong></a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>