{"id":18048062,"url":"https://github.com/ivangfr/springboot-rsocket-webflux-aop","last_synced_at":"2025-10-14T18:34:33.969Z","repository":{"id":45269166,"uuid":"280617740","full_name":"ivangfr/springboot-rsocket-webflux-aop","owner":"ivangfr","description":"The goal of this project is to play with RSocket protocol. For it, we will implement three Spring Boot Java applications, movie-server, movie-client-shell and movie-client-ui. As storage, it's used the reactive NoSQL database MongoDB. All the streaming of movie events and the logging are handling by AOP (Aspect Oriented Programming).","archived":false,"fork":false,"pushed_at":"2024-11-15T09:24:09.000Z","size":15407,"stargazers_count":24,"open_issues_count":0,"forks_count":10,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T08:42:33.931Z","etag":null,"topics":["docker","graalvm","java","mongodb","native","rsocket","semantic-ui","spring-aop","spring-boot","spring-data-mongodb-reactive","spring-shell","spring-webflux","thymeleaf","websocket"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivangfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ivangfr"}},"created_at":"2020-07-18T08:47:18.000Z","updated_at":"2025-01-26T02:21:21.000Z","dependencies_parsed_at":"2024-10-30T20:21:14.497Z","dependency_job_id":null,"html_url":"https://github.com/ivangfr/springboot-rsocket-webflux-aop","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-rsocket-webflux-aop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-rsocket-webflux-aop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-rsocket-webflux-aop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivangfr%2Fspringboot-rsocket-webflux-aop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivangfr","download_url":"https://codeload.github.com/ivangfr/springboot-rsocket-webflux-aop/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248197331,"owners_count":21063619,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","graalvm","java","mongodb","native","rsocket","semantic-ui","spring-aop","spring-boot","spring-data-mongodb-reactive","spring-shell","spring-webflux","thymeleaf","websocket"],"created_at":"2024-10-30T20:11:11.953Z","updated_at":"2025-10-14T18:34:28.951Z","avatar_url":"https://github.com/ivangfr.png","language":"Java","funding_links":["https://github.com/sponsors/ivangfr"],"categories":[],"sub_categories":[],"readme":"# springboot-rsocket-webflux-aop\n\nThe goal of this project is to play with [`RSocket`](https://rsocket.io/) protocol. For it, we will implement three [`Spring Boot`](https://docs.spring.io/spring-boot/index.html) Java applications: `movie-server`, `movie-client-shell` and `movie-client-ui`. As storage, it's used the reactive NoSQL database [`MongoDB`](https://www.mongodb.com/). All the streaming of movie events and the logging are handling by AOP (Aspect Oriented Programming).\n\n## Proof-of-Concepts \u0026 Articles\n\nOn [ivangfr.github.io](https://ivangfr.github.io), I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.\n\n## Additional Readings\n\n- \\[**Medium**\\] [**RSocket Crypto Server Tutorial**](https://medium.com/@ivangfr/list/rsocket-crypto-server-tutorial-651560b2159a)\n- \\[**Medium**\\] [**Implementing and Securing a Spring Boot RSocket App using Keycloak for IAM**](https://itnext.io/implementing-and-securing-a-spring-boot-rsocket-app-with-keycloak-5a6c74bf453d)\n\n## Project Diagram\n\n![project-diagram](documentation/project-diagram.jpeg)\n\n## Applications\n\n- ### movie-server\n\n  `Spring Boot` Java Web application that exposes REST API endpoints or RSocket routes to manage `movies`. Movies data are stored in reactive `MongoDB`.\n  \n  `movie-server` has the following profiles:\n  \n  - `default`\n     - start REST API on port `8080` and uses `HTTP`\n     \n  - `rsocket-tcp`\n     - start REST API on port `8080` and uses `HTTP`\n     - start RSocket on port `7000` and uses `TCP`\n     \n  - `rsocket-websocket`\n     - start REST API on port `8080` and uses `HTTP`\n     - start RSocket with mapping-path `/rsocket` and uses `WebSocket`\n\n- ### movie-client-shell\n\n  `Spring Boot` Shell Java application that has a couple of commands to interact with `movie-server`.\n  \n  The picture below show those commands\n  \n  ![movie-client-shell](documentation/movie-client-shell.jpeg)\n\n  It has the following profiles:\n  \n  - `default`\n     - start shell with enabled commands to call `movie-server` REST API endpoints using `HTTP`\n     \n  - `rsocket-tcp`\n     - start shell with enabled commands to call `movie-server` REST API endpoints using `HTTP`\n     - start shell with enabled commands to call `movie-server` RSocket routes using `TCP`\n     \n  - `rsocket-websocket`\n     - start shell with enabled commands to call `movie-server` REST API endpoints using `HTTP`\n     - start shell with enabled commands to call `movie-server` RSocket routes using `WebSocket`\n\n- ### movie-client-ui\n\n  `Spring Boot` Java Web application that uses [`Thymeleaf`](https://www.thymeleaf.org/) and `Websocket` to show at real-time all the events generated when movies are added, deleted, liked and disliked.\n\n  ![movie-client-ui](documentation/movie-client-ui.jpeg)\n\n  `movie-client-ui` has the following profiles:\n  \n  - `default`\n     - start REST API on port `8081` and uses `HTTP`\n     - does not connect to `movie-server` through `RSocket`; does not receive movie events;\n     \n  - `rsocket-tcp`\n     - start REST API on port `8080` and uses `HTTP`\n     - connects to `movie-server` through `RSocket`using `TCP`; receives movie events;\n     \n  - `rsocket-websocket`\n     - start REST API on port `8080` and uses `HTTP`\n     - connects to `movie-server` through `RSocket`using `WebSocket`; receives movie events;\n\n## Demo\n\nThe GIF below shows a user running some commands in `movie-client-shell`, terminal on the right. In the right-top terminal is running `movie-server` and in the right-bottom, `movie-client-ui`. On the background, there's a browser where movie events are displayed. \n\n![demo](documentation/demo.gif)\n\n## Prerequisites\n\n- [`Java 21+`](https://www.oracle.com/java/technologies/downloads/#java21)\n- [`Docker`](https://www.docker.com/)\n\n## Start Environment\n\nOpen a terminal and inside `springboot-rsocket-webflux-aop` root folder run\n```\ndocker compose up -d\n```\n\n## Running applications with Maven\n\n- **movie-server**\n\n  Open a new terminal and, inside `springboot-rsocket-webflux-aop` root folder, run one of the following profile's command\n  \n  | Profile           | Command                                                                                           |\n  |-------------------|---------------------------------------------------------------------------------------------------|\n  | rsocket-tcp       | ./mvnw clean spring-boot:run --projects movie-server -Dspring-boot.run.profiles=rsocket-tcp       |\n  | rsocket-websocket | ./mvnw clean spring-boot:run --projects movie-server -Dspring-boot.run.profiles=rsocket-websocket |\n  | default           | ./mvnw clean spring-boot:run --projects movie-server                                              |\n  \n- **movie-client-shell**\n\n  Open a new terminal and, inside `springboot-rsocket-webflux-aop` root folder, run the following command to build the executable jar file\n  ```\n  ./mvnw clean package --projects movie-client-shell -DskipTests\n  ```\n\n  To start `movie-client-shell`, run the profile's command you picked to run `movie-server`\n  \n  | Profile           | Commands                                                                                                    |\n  |-------------------|-------------------------------------------------------------------------------------------------------------|\n  | rsocket-tcp       | export SPRING_PROFILES_ACTIVE=rsocket-tcp \u0026\u0026 ./movie-client-shell/target/movie-client-shell-1.0.0.jar       |\n  | rsocket-websocket | export SPRING_PROFILES_ACTIVE=rsocket-websocket \u0026\u0026 ./movie-client-shell/target/movie-client-shell-1.0.0.jar |\n  | default           | export SPRING_PROFILES_ACTIVE=default \u0026\u0026 ./movie-client-shell/target/movie-client-shell-1.0.0.jar           |\n\n- **movie-client-ui**\n\n  Open a new terminal and, inside `springboot-rsocket-webflux-aop` root folder, run the profile's command you picked to run `movie-server`\n  \n  | Profile           | Command                                                                                              |\n  |-------------------|------------------------------------------------------------------------------------------------------|\n  | rsocket-tcp       | ./mvnw clean spring-boot:run --projects movie-client-ui -Dspring-boot.run.profiles=rsocket-tcp       |\n  | rsocket-websocket | ./mvnw clean spring-boot:run --projects movie-client-ui -Dspring-boot.run.profiles=rsocket-websocket |\n  | default           | ./mvnw clean spring-boot:run --projects movie-client-ui                                              |\n\n## Running applications as Docker containers\n\n- ### Build Docker images\n\n  - In a terminal, make sure you are in `springboot-rsocket-webflux-aop` root folder\n  - Run the following script to build the Docker images\n    - JVM\n      ```\n      ./docker-build.sh\n      ```\n    - Native (it's not working yet, see [Issues](#issues))\n      ```\n      ./docker-build.sh native\n      ```\n\n- ### Environment variables\n\n  - **movie-server**\n\n    | Environment Variable | Description                                                       |\n    |----------------------|-------------------------------------------------------------------|\n    | `MONGODB_HOST`       | Specify host of the `Mongo` database to use (default `localhost`) |\n    | `MONGODB_PORT`       | Specify port of the `Mongo` database to use (default `27017`)     |\n\n  - **movie-client-shell**\n\n    | Environment Variable | Description                                                     |\n    |----------------------|-----------------------------------------------------------------|\n    | `MOVIE_SERVER_HOST`  | Specify host of the `movie-server` to use (default `localhost`) |\n\n  - **movie-client-ui**\n\n    | Environment Variable | Description                                                     |\n    |----------------------|-----------------------------------------------------------------|\n    | `MOVIE_SERVER_HOST`  | Specify host of the `movie-server` to use (default `localhost`) |\n\n- ### Start Docker containers\n\n  - In a terminal, make sure you are inside `springboot-rsocket-webflux-aop` root folder\n  - Run following command\n    - rsocket-tcp\n      ```\n      ./start-server-and-ui.sh rsocket-tcp \u0026\u0026 ./start-shell.sh rsocket-tcp\n      ```\n    - rsocket-websocket\n      ```\n      ./start-server-and-ui.sh rsocket-websocket \u0026\u0026 ./start-shell.sh rsocket-websocket\n      ```\n    - default\n      ```\n      ./start-server-and-ui.sh \u0026\u0026 ./start-shell.sh\n      ```\n\n## Application's URL\n\n| Application     | Type     | Transport | URL                         |\n|-----------------|----------|-----------|-----------------------------|\n| movie-server    | RSocket  | TCP       | tcp://localhost:7000        |\n| movie-server    | RSocket  | WebSocket | ws://localhost:8080/rsocket |\n| movie-server    | REST     | HTTP      | http://localhost:8080       |\n| movie-client-ui | Website  | HTTP      | http://localhost:8081       |\n\n\u003e **Note**: you can see the clients connected to `movie-server` by calling the `info` actuator endpoint\n\u003e ```\n\u003e curl -i localhost:8080/actuator/info\n\u003e ```\n\n## Playing Around with movie-client-shell commands\n\n\u003e **Note**: to run the commands below, you must start `movie-server` and `movie-client-shell` with `rsocket-tcp` or `rsocket-websocket` profiles\n\n- Open a browser and access `movie-client-ui` at http://localhost:8081\n\n- Go to `movie-client-shell` terminal\n\n- Add a movie using RSocket (`Request-Response`) \n  ```\n  add-movie-rsocket --imdb aaa --title \"RSocketland\"\n  ```\n  \n  It should return\n  ```\n  {\"imdb\":\"aaa\",\"title\":\"RSocketland\",\"lastModifiedDate\":\"2020-07-20T12:43:39.857248\",\"likes\":0,\"dislikes\":0}\n  ```\n  \n  A `+` action should be displayed in `movie-client-ui`\n  \n- Add a movie using REST\n  ```\n  add-movie-rest --imdb bbb --title \"I, REST\"\n  ```\n  \n  It should return\n  ```\n  {\"imdb\":\"bbb\",\"title\":\"I, REST\",\"lastModifiedDate\":\"2020-07-20T12:44:13.266657\",\"likes\":0,\"dislikes\":0}\n  ```\n  \n  A `+` action should be displayed in `movie-client-ui`\n  \n- Send a like to `RSocketland` movie using RSocket (`Fire-And-Forget`)\n  ```\n  like-movie-rsocket --imdb aaa\n  ```\n  \n  It should return\n  ```\n  Like submitted\n  ```\n  \n  A `thumbs-up` action should be displayed in `movie-client-ui`\n\n- Get all movies using RSocket (`Request-Stream`)\n  ```\n  get-movies-rsocket\n  ```\n  \n  It should return\n  ```\n  {\"imdb\":\"aaa\",\"title\":\"RSocketland\",\"lastModifiedDate\":\"2020-07-20T12:56:34.565\",\"likes\":1,\"dislikes\":0}\n  {\"imdb\":\"bbb\",\"title\":\"I, REST\",\"lastModifiedDate\":\"2020-07-20T12:56:26.846\",\"likes\":0,\"dislikes\":0}\n  ```\n  \n- Select movies using RSocket (`Channel`)\n  ```\n  select-movies-rsocket --imdbs aaa,bbb\n  ```\n  \n  It should return\n  ```\n  | IMBD: aaa        | TITLE: RSocketland                    | LIKES: 1     | DISLIKES: 0     |\n  | IMBD: bbb        | TITLE: I, REST                        | LIKES: 0     | DISLIKES: 0     |\n  ```\n  \n- Delete movie `RSocketland` using RSocket (`Request-Response`) and movie `I, REST` using REST\n  ```\n  delete-movie-rsocket --imdb aaa\n  delete-movie-rest --imdb bbb\n  ```\n  \n  It should return, as response, the IMDB of the movies\n  \n  A `-` actions should be displayed in `movie-client-ui`\n  \n- **Simulation**\n\n  There are two scripts that contain some commands to add, retrieve, like, dislikes and delete movies. One uses REST and another RSocket to communicate with `movie-server`. At the end of the script execution, it's shown the `Execution Time` in `milliseconds`.\n  \n  - If you are running the applications with Maven\n    - REST\n      ```\n      script ../src/main/resources/simulation-rest.txt\n      ```\n    - RSocket\n      ```\n      script ../src/main/resources/simulation-rsocket.txt\n      ```\n\n  - If you are running the applications as Docker containers\n    - REST\n      ```\n      script /workspace/BOOT-INF/classes/simulation-rest.txt\n      ```\n    - RSocket\n      ```\n      script /workspace/BOOT-INF/classes/simulation-rsocket.txt\n      ```\n\n## Useful Commands\n\n- **MongoDB**\n\n  Find all movies\n  ```\n  docker exec -it mongodb mongosh moviedb\n  db.movies.find()\n  ```\n  \u003e Type `exit` to get out of `MongoDB` shell\n\n## Shutdown\n\n- To stop `movie-client-shell`, go to the terminal where it is running and type `exit`\n- To stop `movie-server` and `movie-client-ui`\n  - If you start them with Maven, go to the terminals where they are running and press `Ctrl+C`\n  - If you start them as Docker containers, go to a terminal and, inside `springboot-rsocket-webflux-aop` root folder, run the following command\n    ```\n    ./stop-server-and-ui.sh\n    ```\n- To stop and remove docker compose `mongodb` container, network and volumes, go to a terminal and, inside `springboot-rsocket-webflux-aop` root folder, run the command below\n  ```\n  docker compose down -v\n  ```\n\n## Cleanup\n\nTo remove the Docker images created by this project, go to a terminal and, inside `springboot-rsocket-webflux-aop` root folder, run the script below\n```\n./remove-docker-images.sh\n```\n\n## References\n\n- https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#rsocket\n- https://spring.io/blog/2020/05/12/getting-started-with-rsocket-servers-calling-clients\n- https://grapeup.com/blog/reactive-service-to-service-communication-with-rsocket-introduction/\n\n## Issues\n\n#### movie-server\n\nDocker native image builds and starts up successfully. However, it doesn't accept connections even using JVM version of `movie-client-ui` and `movie-client-shell`.  \n\n#### movie-client-ui\n\nAfter building and starting the Docker native image successfully, the app looks fine (i.e., we can open the page, websocket is connected, etc). However, it is not connecting to `movie-server`.\n\n#### movie-client-shell\n\nAfter building the Docker native image and running it successfully, we have some problems such as\n- there is the following WARN\n  ```\n  Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)\n  ```\n- the autocomplete is not working;\n- when tried to run one of script files (`simulation-rest.txt` or `simulation-rsocket.txt`) there is the following exception\n  ```\n  movie-client-shell\u003e script /app/resources/simulation-rest.txt\n  java.lang.NullPointerException\n  Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.\n  movie-client-shell\u003e stacktrace\n  java.lang.NullPointerException\n  \tat java.base@17.0.7/java.io.FileInputStream.\u003cinit\u003e(FileInputStream.java:149)\n  \tat java.base@17.0.7/java.io.FileReader.\u003cinit\u003e(FileReader.java:75)\n  \tat org.springframework.shell.standard.commands.Script.script(Script.java:60)\n  \tat java.base@17.0.7/java.lang.reflect.Method.invoke(Method.java:568)\n  \tat org.springframework.shell.command.invocation.InvocableShellMethod.doInvoke(InvocableShellMethod.java:306)\n  \tat org.springframework.shell.command.invocation.InvocableShellMethod.invoke(InvocableShellMethod.java:232)\n  \tat org.springframework.shell.command.CommandExecution$DefaultCommandExecution.evaluate(CommandExecution.java:227)\n  \tat org.springframework.shell.Shell.evaluate(Shell.java:248)\n  \tat org.springframework.shell.Shell.run(Shell.java:159)\n  \tat org.springframework.shell.jline.InteractiveShellRunner.run(InteractiveShellRunner.java:73)\n  \tat org.springframework.shell.DefaultShellApplicationRunner.run(DefaultShellApplicationRunner.java:65)\n  \tat org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:762)\n  \tat org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752)\n  \tat org.springframework.boot.SpringApplication.run(SpringApplication.java:319)\n  \tat org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)\n  \tat org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)\n  \tat com.ivanfranchin.movieclientshell.MovieClientShellApplication.main(MovieClientShellApplication.java:10)  \n  ```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspringboot-rsocket-webflux-aop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivangfr%2Fspringboot-rsocket-webflux-aop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivangfr%2Fspringboot-rsocket-webflux-aop/lists"}