![image](https://private-user-images.githubusercontent.com/56931032/343861538-ccee2aac-200e-4979-9858-36ece03d9dad.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjI0NzkxNTQsIm5iZiI6MTcyMjQ3ODg1NCwicGF0aCI6Ii81NjkzMTAzMi8zNDM4NjE1MzgtY2NlZTJhYWMtMjAwZS00OTc5LTk4NTgtMzZlY2UwM2Q5ZGFkLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODAxVDAyMjA1NFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTk4OTNjODRjNWQ3MTkxYWIxMDA0NGQ4ZTJiOThkMGQ3Njg5NjQ1OTdkOTFhOTMzNGEwYzI0MmExODMxMDcwM2UmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.gGoizK-gO07bC8V-_z7YRrx1x1Mid_Wvta0bPrRfhmw)
![image](https://private-user-images.githubusercontent.com/56931032/343861600-b3d04342-6d00-4726-8380-0e54856f6303.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjI0NzkxNTQsIm5iZiI6MTcyMjQ3ODg1NCwicGF0aCI6Ii81NjkzMTAzMi8zNDM4NjE2MDAtYjNkMDQzNDItNmQwMC00NzI2LTgzODAtMGU1NDg1NmY2MzAzLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODAxVDAyMjA1NFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRhZjdmNDZlZmVkNjdhOTRiY2Q5NjEwMGE1MWU3Yjk1OGE1MWQyZTE1M2MwMmM4YTFkODM0OWNiNGUwMjAwOWImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.76VkxWHRHppE3OrEmhMz8mvV1jsnphK8wRunS0Y5Qhc)
![image](https://private-user-images.githubusercontent.com/56931032/344028754-4ea1122a-5947-4f73-ba52-daafa050373b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjI0NzkxNTQsIm5iZiI6MTcyMjQ3ODg1NCwicGF0aCI6Ii81NjkzMTAzMi8zNDQwMjg3NTQtNGVhMTEyMmEtNTk0Ny00ZjczLWJhNTItZGFhZmEwNTAzNzNiLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODAxVDAyMjA1NFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTM2ZTU5NDEzODk4NzdhYjEzZjc4ZGJiNzkwY2UyOTE5ODE2Yjg0ZTEyMTYwYTA0NGUzZjAzNzcyNTU4NmZkMGQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.chDgvc7Cc7hvM2yhvwcz9ZafHvqhzngAUD2HDbup3bo)
- new
![image](https://private-user-images.githubusercontent.com/56931032/344044837-825ecc32-0510-4471-bc48-2098b70eb45b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjI0NzkxNTQsIm5iZiI6MTcyMjQ3ODg1NCwicGF0aCI6Ii81NjkzMTAzMi8zNDQwNDQ4MzctODI1ZWNjMzItMDUxMC00NDcxLWJjNDgtMjA5OGI3MGViNDViLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODAxVDAyMjA1NFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWY2OTM1YTBhY2U2YzZkMWRmZGYxMDE5MWU3ODA0NGIzOWNhZWZhMTYyYjVlY2FiZjI3YTQ4NmZkOWU3YzFlNTEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.gfth23tCZBMUcduGsvsOVLu3hV8e9OOBkDpiOSGsle0)
![image](https://private-user-images.githubusercontent.com/56931032/344044932-94779900-5940-4c32-beed-d69ea6ed86d8.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjI0NzkxNTQsIm5iZiI6MTcyMjQ3ODg1NCwicGF0aCI6Ii81NjkzMTAzMi8zNDQwNDQ5MzItOTQ3Nzk5MDAtNTk0MC00YzMyLWJlZWQtZDY5ZWE2ZWQ4NmQ4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODAxVDAyMjA1NFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTRjY2NkNDE1ZDhmZDRmNGQzZmQ2ZDMxNzQ5MWM1MjllY2Q3NGIzMDljYWUyY2ZjYzJjYTIxODI5NTZjYjE0ODMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.W6UiZti--CMNR0fh3kz8z0acW5mcLiycM7TKgR2y_vE)
Here is a simple template code to create a Vaadin application that consumes a reactive stream using Project Reactor's Flux
. This example includes a mock method returning a Flux<String>
and the Vaadin code to display the content with a delay of 1 second.
Flux<String>
import reactor.core.publisher.Flux;
import java.time.Duration;
public class DataService {
public Flux<String> getDataStream() {
return Flux.just("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
.delayElements(Duration.ofSeconds(1));
}
}
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import reactor.core.publisher.Flux;
@Route("")
public class MainView extends VerticalLayout {
public MainView() {
DataService dataService = new DataService();
Div container = new Div();
container.setText("Loading data...");
add(container);
Flux<String> dataStream = dataService.getDataStream();
dataStream.subscribe(
item -> getUI().ifPresent(ui -> ui.access(() -> container.add(new Div(new Text(item))))),
error -> getUI().ifPresent(ui -> ui.access(() -> container.add(new Div(new Text("Error: " + error.getMessage()))))),
() -> getUI().ifPresent(ui -> ui.access(() -> container.add(new Div(new Text("All items loaded.")))))
);
}
}
Mock Method (DataService
):
getDataStream
returns a Flux<String>
that emits items every 1 second.Vaadin View (MainView
):
VerticalLayout
is created with a Div
to hold the loading data.DataService
is instantiated, and the Flux<String>
from getDataStream
is subscribed to.Div
with the item text is added to the container
Div
.container
.This template code should help you get started with a reactive Vaadin application displaying data with a delay. You can customize it further as per your requirements.
Here's a template code for a chat client using a ChatClient
bean from the Spring AI dependency. The focus here is on the ChatClient
code part within the Vaadin view.
ChatClient
Beanimport com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import org.springframework.beans.factory.annotation.Autowired;
import reactor.core.publisher.Flux;
@Route("")
public class ChatView extends VerticalLayout {
private final ChatClient chatClient;
@Autowired
public ChatView(ChatClient chatClient) {
this.chatClient = chatClient;
TextField questionField = new TextField("Enter your question");
Button sendButton = new Button("Send");
Div chatArea = new Div();
sendButton.addClickListener(event -> {
String question = questionField.getValue();
Flux<String> responseStream = chatClient.getResponse(question);
responseStream.subscribe(
response -> getUI().ifPresent(ui -> ui.access(() -> chatArea.add(new Div(new Text(response))))),
error -> getUI().ifPresent(ui -> ui.access(() -> chatArea.add(new Div(new Text("Error: " + error.getMessage()))))),
() -> getUI().ifPresent(ui -> ui.access(() -> chatArea.add(new Div(new Text("Conversation ended.")))))
);
});
add(questionField, sendButton, chatArea);
}
}
Autowired ChatClient:
ChatClient
bean is autowired into the ChatView
constructor.Vaadin Components:
TextField
for entering the question.Button
to send the question.Div
to display the chat messages.Button Click Listener:
ChatClient
's getResponse
method.Flux<String>
returned by getResponse
is subscribed to.chatArea
Div
as they arrive.This template demonstrates how to use a ChatClient
bean from the Spring AI dependency within a Vaadin view, making the chat functionality reactive.
Sure, I'll show you how to replace the mock service with a real
ChatClient
that streams responses. This example assumes you have theChatClient
configured and ready to use.Vaadin Component with ChatClient
Here's the updated Vaadin component that uses
ChatClient
to stream responses:ChatClient Configuration
Ensure your
ChatClient
is configured correctly. Here’s a simple configuration class forChatClient
:Explanation
ChatClient Configuration:
ChatClient
usingWebClient
. It uses theapiKey
from your properties file.MainView:
Text
component to display the loading status and aButton
to start the loading process.startLoading
method subscribes to theFlux
returned bychatClient.prompt()
, updating theText
component with each emitted item.Reactive Data Streaming:
Flux<String>
is created by callingchatClient.prompt().user("Tell me a joke").stream().content()
.dataStream
is processed reactively, updating the UI with each new piece of data emitted by theFlux
.Dependencies
Ensure you have the necessary dependencies in your
pom.xml
orbuild.gradle
:Maven (pom.xml)
Gradle (build.gradle)
This setup will allow your Vaadin application to consume streaming data from a
ChatClient
and update the UI reactively.