<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Vikas Rajput - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Vikas Rajput - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 02 Jun 2026 11:12:11 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/vikasrajputin/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build an AI Chatbot with Spring AI, React, and Docker ]]>
                </title>
                <description>
                    <![CDATA[ Hey Java developers, I’ve got good news: Spring now has official support for building AI applications using the Spring AI module. In this tutorial, we’ll build a chatbot application using Spring Boot, React, Docker, and OpenAI. This app will let user... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/ai-chatbot-with-spring-react-docker/</link>
                <guid isPermaLink="false">66f17acd2085b5a2fdb356e0</guid>
                
                    <category>
                        <![CDATA[ Springboot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ openai ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vikas Rajput ]]>
                </dc:creator>
                <pubDate>Mon, 23 Sep 2024 14:27:25 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/6UDansS-rPI/upload/d57a180a4cda63056c786838a71c6679.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey Java developers, I’ve got good news: Spring now has official support for building AI applications using the <a target="_blank" href="https://spring.io/projects/spring-ai">Spring AI</a> module.</p>
<p>In this tutorial, we’ll build a chatbot application using <a target="_blank" href="https://spring.io/projects/spring-boot"><strong>Spring Boot</strong></a>, <a target="_blank" href="https://react.dev/"><strong>React</strong></a>, <a target="_blank" href="https://www.docker.com/"><strong>Docker</strong></a>, and <a target="_blank" href="https://openai.com/"><strong>OpenAI</strong></a>. This app will let users interact with an AI-powered chatbot, ask questions, and receive responses in real time.</p>
<p>The entire source code mentioned in this article is already available on the <a target="_blank" href="https://github.com/vikasrajputin/springboot-react-docker-chatbot">GitHub repository</a>. Feel free to give it a star and fork it to play around.</p>
<p>To give you an idea of what we’ll be building here, this is how the final application will look:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726657239698/5170bf73-b317-4281-bcd1-583454d4113f.png" alt="Chatbot App UI using Spring AI, React, Docker by Vikas Rajput" class="image--center mx-auto" width="729" height="883" loading="lazy"></p>
<p>Are you excited? Let’s build it from scratch!</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-get-your-openai-key">Get Your OpenAI key</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-build-the-rest-api-in-spring-boot">Build the REST API in Spring Boot</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-build-the-chatui-using-reactjs">Build the ChatUI using Reactjs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-dockerize-the-application">How to Dockerize the Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-run-the-application">Run the Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-congratulations">Congratulations 🎉</a></p>
</li>
</ul>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>Before we dive into building the chatbot, here are a few things you’ll need to be familiar with:</p>
<ol>
<li><p>Basic understanding of <strong>Java</strong> and <strong>Spring Boot</strong>.</p>
</li>
<li><p>Basic understanding of <strong>React</strong> and <strong>CSS</strong>.</p>
</li>
<li><p>Install <a target="_blank" href="https://jdk.java.net/java-se-ri/17-MR1">JDK</a>, <a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">Node Package Manager</a> and <a target="_blank" href="https://docs.docker.com/get-started/get-docker/">Docke</a><a target="_blank" href="https://docs.docker.com/desktop/">r</a> onto your machine.</p>
</li>
</ol>
<h2 id="heading-get-your-openai-key"><strong>Get Your OpenAI key</strong></h2>
<p>First, you’ll need to sign up for an <a target="_blank" href="https://platform.openai.com/">OpenAI</a> account if you don’t have one. Once signed in, you’ll be taken to the homepage.</p>
<p>In the top right corner, click the “Dashboard” menu. On the sidebar, click "API Keys," then click the "Create new secret key" button to generate your secret key:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726818120291/5f1681a0-fdbe-401e-ab4b-769fe38d7957.png" alt="How to generate your OpenAI key" class="image--center mx-auto" width="1903" height="537" loading="lazy"></p>
<p>Copy the secret key and save it somewhere safe, as you’ll need it later to connect your app to the OpenAI API.</p>
<p>You can go through the OpenAI <a target="_blank" href="https://platform.openai.com/docs/api-reference/authentication">API reference guide</a> to learn more about how to call the APIs, what requests it accepts, and the responses it gives.</p>
<h2 id="heading-build-the-rest-api-in-spring-boot"><strong>Build the REST API in Spring Boot</strong></h2>
<p>Let’s head over to the <a target="_blank" href="https://start.spring.io/">spring initializer</a> to generate the boilerplate code:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726662395429/cd4b07fd-2597-43bf-8038-1821003125bb.png" alt="Build Spring AI app using the spring initializer" class="image--center mx-auto" width="1511" height="883" loading="lazy"></p>
<p>You can give the group, artifact, name, description, and package you choose. We’ve used Maven as the built tool, Spring boot version 3.3.3, Jar as a packaging option, and Java version 17.</p>
<p>Hit the generate button and the zip will be downloaded. Unzip the files and import them as a Maven project into your favourite IDE (mine is Intellij).</p>
<h3 id="heading-configure-your-openai-key-in-spring">Configure your OpenAI key in Spring</h3>
<p>You can either use the existing <code>application.properties</code> file or create a <code>application.yaml</code> file. I love working with Yaml, so created a <code>application.yaml</code> file where I can place all my Spring Boot configurations.</p>
<p>Add the OpenAIKey, Model, and Temperature to your <code>application.yaml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">spring:</span>
  <span class="hljs-attr">ai:</span>
    <span class="hljs-attr">openai:</span>
      <span class="hljs-attr">chat:</span>
        <span class="hljs-attr">options:</span>
          <span class="hljs-attr">model:</span> <span class="hljs-string">"gpt-3.5-turbo"</span>
          <span class="hljs-attr">temperature:</span> <span class="hljs-string">"0.7"</span>
      <span class="hljs-attr">key:</span> <span class="hljs-string">"PUT YOUR OPEN_API_KEY HERE"</span>
</code></pre>
<p>A similar configuration in <code>application.properties</code> may look like as follows:</p>
<pre><code class="lang-basic">spring.ai.openai.chat.options.model=gpt-<span class="hljs-number">3.5</span>-turbo
spring.ai.openai.chat.options.temperature=<span class="hljs-number">0.7</span>
spring.ai.openai.<span class="hljs-keyword">key</span>=<span class="hljs-string">"PUT YOUR OPEN_API_KEY HERE"</span>
</code></pre>
<h3 id="heading-build-the-chatcontroller">Build the ChatController</h3>
<p>Let’s create a <code>GET</code> API with the URL <code>/ai/chat/string</code> and a method to handle the logic:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</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">@Autowired</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> OpenAiChatModel chatModel;

    <span class="hljs-meta">@GetMapping("/ai/chat/string")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Flux&lt;String&gt; <span class="hljs-title">generateString</span><span class="hljs-params">(<span class="hljs-meta">@RequestParam(value = "message", defaultValue = "Tell me a joke")</span> String message)</span> </span>{
        <span class="hljs-keyword">return</span> chatModel.stream(message);
    }
}
</code></pre>
<ul>
<li><p>First, we’re adding <code>@RestController</code> to mark the <code>ChatController</code> class as our spring controller</p>
</li>
<li><p>Then, we’re injecting the dependency for the <code>OpenAiChatModel</code> class. It comes out of the box as part of the Spring AI dependency we’ve used.</p>
</li>
<li><p>The <code>OpenAiChatModel</code> comes with a method <code>stream(message)</code> which accepts the prompt as <code>String</code> and returns a <code>String</code> response (technically it’s a <code>Flux</code> of <code>String</code> as we’ve used a Reactive version of the same method).</p>
</li>
<li><p>Internally, <code>OpenAiChatModel.stream(message)</code> will call the OpenAI API and fetch the response from there. The OpenAI call will use the configuration steps mentioned in your <code>application.yaml</code> file, so make sure to use a valid OpenAI key.</p>
</li>
<li><p>We’ve created a method to handle the GET API call, which accepts the message and returns <code>Flux&lt;String&gt;</code> as the response.</p>
</li>
</ul>
<h3 id="heading-build-run-and-test-the-rest-api">Build, Run, and Test the REST API</h3>
<p>Use the maven commands to build and run the Spring Boot application:</p>
<pre><code class="lang-bash">./mvnw clean install spring-boot:run
</code></pre>
<p>Ideally, it will run on a <code>8080</code> port unless you’ve customized the port. Make sure to keep that port free to successfully run the application.</p>
<p>You can either use <a target="_blank" href="https://www.postman.com/">Postman</a> or the <a target="_blank" href="https://curl.se/">Curl</a> command to test your REST API:</p>
<pre><code class="lang-bash">curl --location <span class="hljs-string">'http://localhost:8080/ai/chat/string?message=How%20are%20you%3F'</span>
</code></pre>
<h2 id="heading-build-the-chatui-using-reactjs">Build the ChatUI using React.js</h2>
<p>We will be making it super simple and easy for the sake of this tutorial, so pardon me if I don’t follow any React best practices.</p>
<h3 id="heading-create-appjs-to-manage-the-chatui-form">Create <code>App.js</code> to Manage the ChatUI Form</h3>
<p>We’ll be using <code>useState</code> to manage the state:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [messages, setMessages] = useState([]);
<span class="hljs-keyword">const</span> [input, setInput] = useState(<span class="hljs-string">''</span>);
<span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<ul>
<li><p><code>messages</code>: It will store all the messages in the chat. Each message has a <code>text</code> and a <code>sender</code> (either 'user' or 'ai').</p>
</li>
<li><p><code>input</code>: To hold what the user is typing in the text box.</p>
</li>
<li><p><code>loading</code>: This state is set to <code>true</code> while the chatbot is waiting for a response from the AI, and <code>false</code> when the response is received.</p>
</li>
</ul>
<p>Let’s create a function <code>handleSend</code> and call it when the user sends a message by clicking a button or pressing Enter:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleSend = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (input.trim() === <span class="hljs-string">''</span>) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">const</span> newMessage = { <span class="hljs-attr">text</span>: input, <span class="hljs-attr">sender</span>: <span class="hljs-string">'user'</span> };
    setMessages([...messages, newMessage]);
    setInput(<span class="hljs-string">''</span>);
    setLoading(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'http://localhost:8080/ai/chat/string?message='</span> + input);
        <span class="hljs-keyword">const</span> aiMessage = { <span class="hljs-attr">text</span>: response.data, <span class="hljs-attr">sender</span>: <span class="hljs-string">'ai'</span> };
        setMessages([...messages, newMessage, aiMessage]);
    } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching AI response"</span>, error);
    } <span class="hljs-keyword">finally</span> {
        setLoading(<span class="hljs-literal">false</span>);
    }
};
</code></pre>
<p>Here’s what happens step by step:</p>
<ul>
<li><p><strong>Check empty input</strong>: If the input field is empty, the function returns early (nothing is sent).</p>
</li>
<li><p><strong>New message from the user</strong>: A new message is added to the <code>messages</code> array. This message has the <code>text</code> (whatever the user typed) and is marked as being sent by the 'user'.</p>
</li>
<li><p><strong>Reset input</strong>: The input field is cleared after the message is sent.</p>
</li>
<li><p><strong>Start loading</strong>: While waiting for the AI to respond, <code>loading</code> is set to <code>true</code> to show a loading indicator.</p>
</li>
<li><p><strong>Make API request</strong>: The code is used <code>axios</code> to request the AI chatbot API, passing the user's message. When the response comes back, a new message from the AI is added to the chat.</p>
</li>
<li><p><strong>Error handling</strong>: If there is a problem getting the AI’s response, an error is logged to the console.</p>
</li>
<li><p><strong>Stop loading</strong>: Finally, the loading state is turned off.</p>
</li>
</ul>
<p>Let’s write a function to update the <code>input</code> state whenever the user types something in the input field:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleInputChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setInput(e.target.value);
};
</code></pre>
<p>Next, let’s create a function to check if the user presses the Enter key. If they do, it calls <code>handleSend()</code> to send the message:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (e.key === <span class="hljs-string">'Enter'</span>) {
        handleSend();
    }
};
</code></pre>
<p>Now let’s create UI elements to render the chat messages:</p>
<pre><code class="lang-js">{messages.map(<span class="hljs-function">(<span class="hljs-params">message, index</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">message-container</span> ${<span class="hljs-attr">message.sender</span>}`}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{message.sender</span> === <span class="hljs-string">'user'</span> ? '<span class="hljs-attr">user-icon.png</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">ai-assistant.png</span>'}
            <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">message.sender</span>} <span class="hljs-attr">avatar</span>`}
            <span class="hljs-attr">className</span>=<span class="hljs-string">"avatar"</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">message</span> ${<span class="hljs-attr">message.sender</span>}`}&gt;</span>
            {message.text}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
))}
</code></pre>
<p>This block renders all the messages in the chat:</p>
<ul>
<li><p><strong>Mapping through messages</strong>: Each message is displayed as a <code>div</code> using <code>.map()</code>.</p>
</li>
<li><p><strong>Message styling</strong>: The class name of the message changes based on who the sender is (<code>user</code> or <code>ai</code>), making it clear who sent the message.</p>
</li>
<li><p><strong>Avatar images</strong>: Each message shows a small avatar, with a different image for the user and the AI.</p>
</li>
</ul>
<p>Let’s create some logic to show the loader based on a flag:</p>
<pre><code class="lang-js">{loading &amp;&amp; (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message-container ai"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"ai-assistant.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"AI avatar"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"avatar"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message ai"</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
)}
</code></pre>
<p>While the AI is thinking (when <code>loading</code> is <code>true</code>), we show a loading message (<code>...</code>) so the user knows a response is coming soon.</p>
<p>At last, create a button to click the message send button:</p>
<pre><code class="lang-jsx">&lt;button onClick={handleSend}&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FaPaperPlane</span> /&gt;</span></span>
&lt;/button&gt;
</code></pre>
<p>This button triggers the <code>handleSend()</code> function when clicked. The icon used here is a <a target="_blank" href="https://react-icons.github.io/react-icons/icons/fa/">paper plane</a>, which is common for "send" buttons.</p>
<p>The full <code>Chatbot.js</code> looks as below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { FaPaperPlane } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-icons/fa'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./Chatbot.css'</span>;

<span class="hljs-keyword">const</span> Chatbot = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [messages, setMessages] = useState([]);
    <span class="hljs-keyword">const</span> [input, setInput] = useState(<span class="hljs-string">''</span>);
    <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">const</span> handleSend = <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">if</span> (input.trim() === <span class="hljs-string">''</span>) <span class="hljs-keyword">return</span>;

        <span class="hljs-keyword">const</span> newMessage = { <span class="hljs-attr">text</span>: input, <span class="hljs-attr">sender</span>: <span class="hljs-string">'user'</span> };
        setMessages([...messages, newMessage]);
        setInput(<span class="hljs-string">''</span>);
        setLoading(<span class="hljs-literal">true</span>);

        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'http://localhost:8080/ai/chat/string?message='</span> + input);
            <span class="hljs-keyword">const</span> aiMessage = { <span class="hljs-attr">text</span>: response.data, <span class="hljs-attr">sender</span>: <span class="hljs-string">'ai'</span> };
            setMessages([...messages, newMessage, aiMessage]);
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching AI response"</span>, error);
        } <span class="hljs-keyword">finally</span> {
            setLoading(<span class="hljs-literal">false</span>);
        }
    };

    <span class="hljs-keyword">const</span> handleInputChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        setInput(e.target.value);
    };

    <span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (e.key === <span class="hljs-string">'Enter'</span>) {
            handleSend();
        }
    };

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chatbot-container"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-header"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"ChatBot.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Chatbot Logo"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-logo"</span> /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"breadcrumb"</span>&gt;</span>Home <span class="hljs-symbol">&amp;gt;</span> Chat<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chatbox"</span>&gt;</span>
                {messages.map((message, index) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">message-container</span> ${<span class="hljs-attr">message.sender</span>}`}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                            <span class="hljs-attr">src</span>=<span class="hljs-string">{message.sender</span> === <span class="hljs-string">'user'</span> ? '<span class="hljs-attr">user-icon.png</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">ai-assistant.png</span>'}
                            <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">message.sender</span>} <span class="hljs-attr">avatar</span>`}
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"avatar"</span>
                        /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">message</span> ${<span class="hljs-attr">message.sender</span>}`}&gt;</span>
                            {message.text}
                        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                ))}
                {loading &amp;&amp; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message-container ai"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"ai-assistant.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"AI avatar"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"avatar"</span> /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message ai"</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                )}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input-container"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{input}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleInputChange}</span>
                    <span class="hljs-attr">onKeyPress</span>=<span class="hljs-string">{handleKeyPress}</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type your message..."</span>
                /&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSend}</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FaPaperPlane</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Chatbot;
</code></pre>
<p>Use <code>&lt;Chatbot/&gt;</code> inside the <code>App.js</code> to load the Chatbot UI:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Chatbot</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Along with this, we’re also using CSS to make our chatbot a little more beautiful. You can refer to <a target="_blank" href="https://github.com/vikasrajputin/springboot-react-docker-chatbot/blob/main/chatbot-ui/src/App.css">App.css</a> and <a target="_blank" href="https://github.com/vikasrajputin/springboot-react-docker-chatbot/blob/main/chatbot-ui/src/Chatbot.css">Chatbot.css</a> for that.</p>
<h3 id="heading-run-the-frontend">Run the Frontend</h3>
<p>Use the <code>npm</code> command to run the application:</p>
<pre><code class="lang-bash">npm start
</code></pre>
<p>This should run the frontend on the URL <code>http://localhost:3000</code>. The application is good to be tested now.</p>
<p>But running the backend and frontend separately is a bit of a hassle. So let’s use Docker to make the entire build process easier.</p>
<h2 id="heading-how-to-dockerize-the-application"><strong>How to Dockerize th</strong>e Applic<strong>ation</strong></h2>
<p>Let’s dockerize the entire application to help bundle and ship it anywhere hassle-free. You can install and configure Docker from the <a target="_blank" href="https://docs.docker.com/get-started/get-docker/">official Docker website</a>.</p>
<h3 id="heading-dockerize-the-backend">Dockerize the Backend</h3>
<p>The backend of our chatbot is built with Spring Boot, so we will create a <code>Dockerfile</code> that builds the Spring Boot app into an executable JAR file and runs it in a container.</p>
<p>Let’s write the <code>Dockerfile</code> for it:</p>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># Start with an official image that has Java installed</span>
<span class="hljs-keyword">FROM</span> openjdk:<span class="hljs-number">17</span>-jdk-alpine

<span class="hljs-comment"># Set the working directory inside the container</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Copy the Maven/Gradle build file and source code into the container</span>
<span class="hljs-keyword">COPY</span><span class="bash"> target/chatbot-backend.jar /app/chatbot-backend.jar</span>

<span class="hljs-comment"># Expose the application’s port</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8080</span>

<span class="hljs-comment"># Command to run the Spring Boot app</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"java"</span>, <span class="hljs-string">"-jar"</span>, <span class="hljs-string">"chatbot-backend.jar"</span>]</span>
</code></pre>
<ul>
<li><p><code>FROM openjdk:17-jdk-alpine</code>: This specifies that the container should be based on a lightweight Alpine Linux image that includes JDK 17, which is needed to run Spring Boot.</p>
</li>
<li><p><code>WORKDIR /app</code>: Sets the working directory inside the container to <code>/app</code>, where our application files will live.</p>
</li>
<li><p><code>COPY target/chatbot-backend.jar /app/chatbot-backend.jar</code>: Copies the built JAR file from your local machine (usually in the <code>target</code> folder after building the project with Maven or Gradle) into the container.</p>
</li>
<li><p><code>EXPOSE 8080</code>: This tells Docker that the application will listen for requests on port 8080.</p>
</li>
<li><p><code>CMD ["java", "-jar", "chatbot-backend.jar"]</code>: This specifies the command that will run when the container starts. It runs the JAR file that launches the Spring Boot app.</p>
</li>
</ul>
<h3 id="heading-dockerize-the-frontend">Dockerize the Frontend</h3>
<p>The front end of our chatbot is built using React, and we can Dockerize it by creating a Dockerfile that installs the necessary dependencies, builds the app, and serves it using a lightweight web server like NGINX.</p>
<p>Let’s write the <code>Dockerfile</code> for the React frontend:</p>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># Use a Node image to build the React app</span>
<span class="hljs-keyword">FROM</span> node:<span class="hljs-number">16</span>-alpine AS build

<span class="hljs-comment"># Set the working directory inside the container</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /app</span>

<span class="hljs-comment"># Copy the package.json and install the dependencies</span>
<span class="hljs-keyword">COPY</span><span class="bash"> package.json package-lock.json ./</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install</span>

<span class="hljs-comment"># Copy the rest of the application code and build it</span>
<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm run build</span>

<span class="hljs-comment"># Use a lightweight NGINX server to serve the built app</span>
<span class="hljs-keyword">FROM</span> nginx:alpine
<span class="hljs-keyword">COPY</span><span class="bash"> --from=build /app/build /usr/share/nginx/html</span>

<span class="hljs-comment"># Expose port 80 for the web traffic</span>
<span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span>

<span class="hljs-comment"># Start NGINX</span>
<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"nginx"</span>, <span class="hljs-string">"-g"</span>, <span class="hljs-string">"daemon off;"</span>]</span>
</code></pre>
<ul>
<li><p><code>FROM node:16-alpine AS build</code>: This uses a lightweight Node.js image to build the React app. We install all dependencies and build the app inside this container.</p>
</li>
<li><p><code>WORKDIR /app</code>: Sets the working directory inside the container to <code>/app</code>.</p>
</li>
<li><p><code>COPY package.json package-lock.json ./</code>: Copies <code>package.json</code> and <code>package-lock.json</code> to install dependencies.</p>
</li>
<li><p><code>RUN npm install</code>: Installs the dependencies listed in the package.json.</p>
</li>
<li><p><code>COPY . .</code>: Copies all the frontend source code into the container.</p>
</li>
<li><p><code>RUN npm run build</code>: Builds the React application. The built files will be in a <code>build</code> folder.</p>
</li>
<li><p><code>FROM nginx:alpine</code>: After building the app, this line starts a new container based on the <code>nginx</code> web server.</p>
</li>
<li><p><code>COPY --from=build /app/build /usr/share/nginx/html</code>: Copies the built React app from the first container into the nginx container, placing it in the default folder where NGINX serves files.</p>
</li>
<li><p><code>EXPOSE 80</code>: This exposes port 80, which NGINX uses to serve web traffic.</p>
</li>
<li><p><code>CMD ["nginx", "-g", "daemon off;"]</code>: This starts the NGINX server in the foreground to serve your React app.</p>
</li>
</ul>
<h3 id="heading-docker-compose-to-run-both">Docker Compose to Run Both</h3>
<p>Now that we have separate Dockerfiles for the frontend and backend, we’ll use <code>docker-compose</code> to orchestrate running both containers at once.</p>
<p>Let’s write the <code>docker-compose.yml</code> file inside the root directory of the project:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">'3'</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">backend:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">./backend</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"8080:8080"</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">chatbot-network</span>

  <span class="hljs-attr">frontend:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">./frontend</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:80"</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">backend</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">chatbot-network</span>

<span class="hljs-attr">networks:</span>
  <span class="hljs-attr">chatbot-network:</span>
    <span class="hljs-attr">driver:</span> <span class="hljs-string">bridge</span>
</code></pre>
<ul>
<li><p><code>version: '3'</code>: This defines the version of Docker Compose being used.</p>
</li>
<li><p><code>services:</code>: This defines the services we want to run.</p>
<ul>
<li><p><code>backend</code>: This service builds the backend using the Dockerfile located in the <code>./backend</code> directory and exposes port 8080.</p>
</li>
<li><p><code>frontend</code>: This service builds the front end using the Dockerfile located in the <code>./frontend</code> directory. It maps port 3000 on the host to port 80 inside the container.</p>
</li>
</ul>
</li>
<li><p><code>depends_on:</code>: This makes sure the front end waits for the backend to be ready before it starts.</p>
</li>
<li><p><code>networks:</code>: This section defines a shared network so that both the backend and frontend can communicate with each other.</p>
</li>
</ul>
<h2 id="heading-run-the-application">Run the Application</h2>
<p>To run the entire application (both frontend and backend), you can use the following command:</p>
<pre><code class="lang-bash">docker-compose up --build
</code></pre>
<p>This command will:</p>
<ul>
<li><p>Build both the frontend and backend images.</p>
</li>
<li><p>Start both containers (backend on port 8080, frontend on port 3000).</p>
</li>
<li><p>Set up networking so that both services can communicate.</p>
</li>
</ul>
<p>Now, you can head over to <code>http://localhost:3000</code> load the Chatbot UI and start asking your questions to the AI.</p>
<h2 id="heading-congratulations">Congratulations 🎉</h2>
<p>You’ve successfully built a full-stack chatbot application using Spring Boot, React, Docker, and OpenAI.</p>
<p>The source code shown in the project is available on <a target="_blank" href="https://github.com/vikasrajputin/springboot-react-docker-chatbot">Github</a>, if you found it helpful give it a star, and feel free to fork it and play around with it.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
