Develop A Geocaching Multiplayer Game Using Flutter, Spring Boot, Oracle Database Free Spatial, and OpenStreetMap

June 26, 2023 | 11 minute read
Paul Parkinson
Architect and Developer Evangelist, Microservices and Converged Database
Text Size 100%:

In this blog, I will show you how to quickly create a full-stack app using an extremely powerful, versatile, popular, and entirely free software stack consisting of Flutter, Spring Boot, Oracle Database with Spatial (,SQL, JSON, and Blockchain), and OpenStreetMap.  All of the source is of course available here.

flutter springboot oracle spatial


As a use case, I will create a multi-player game based on Geocaching.  (Fun fact, there are now more than 3.1 million active geocaches in 196 different countries and even space.)

A player can place items/pictures at specific locations around the globe for other players to find.  When a player finds a geocache location, they sign the guestbook and can see others that have signed the guestbook. Using the honesty policy, a player has the option to take any items/pictures with the understanding that they will put other items/pictures in place.

Our application is an online version of the game though it could conceivably be used to track/match the real-world version or extended to any number of other purposes.

We'll go from bottom to top, setting up the app and describing each bit of the architecture, from Oracle Database Free (showing JSON, Spatial, Blockchain tables, ...) to Spring Boot (showing Rest, JSON, JDBC, ...) to Flutter (web and mobile, Widgets, Maps, Rest, ...).

In short, we'll...

  1. Create the database
  2. Configure Spring Boot to create and use a GeoCacheUser and relevant tables and JSON docs in the database. Build and verify.
  3. Build and run the Flutter service which will call the Spring Boot service which will call the Oracle database.

But first, let's take a quick walkthrough of the app...

flutter app gif

The app has a navigation bar with three items: Top CachesAdd GeoCache, and Map (Spatial).

First, we'll add geocaches using the Add GeoCache form (providing name, lat, long, and image URL).
flutter app screen1

Then, we'll check the Map (Spatial) to see and select geocaches.  

flutter app screen2

We'll notice the name and image of the cache and that we've signed it.

flutter app screen3

Finally, we'll go to Top Caches to see which caches had the most visits/signatures.

flutter app screen4


GeoJSON is a standard (RFC 7946) that uses JSON objects to represent various geometrical entities and combinations of these together with user-defined properties. In this application, we are plotting simple latitude and longitude coordinates that have certain properties and so are using a feature collection structure that contains an array of features. Features in turn have a geometry of type point (that contains the coordinates) and properties with an array of values specific to the application such as the name of the person who added the geocache, the image location of the image they placed, and the name of the person/people that visited the geocache.  The following is an example of this GeoJSON and it is represented by objects in the database/Oracle, back end/Spring Boot, and front end/Flutter.



  "type": "FeatureCollection",
  "features": [
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [
      "properties": {
        "name": "BillWatkins75",
        "imagelocation": "https://.../spacemountain.png"


Oracle Converged Database

In this application, we will use SQL, JSON, Blockchain Tables, and of course Spatial for the GeoJSON and then mapping of the same.  The Oracle converged database is extremely powerful and versatile as it provides support for SQL, JSON (and both simultaneously via the JSON Duality functionality), Rest, Messaging and Events, Editions,  IoT Streaming, Machine Learning, Blockchain, Graph, and Spatial all in one database. 

We can use any version of Oracle database.  On the cloud, we can use Oracle always free autonomous database (that's also nice as we can expose it via the Internet and make the game truly available globally/online in a couple minutes) or we can use the Oracle 23c Free version where we can simply install or use a container image locally. Or of course, we could use the local for dev and cloud for production, etc. and either of these options is very quick to set up...

Always Free Oracle Cloud Database option...

You can go here to set up an Oracle Cloud Always Free Autonomous Database
The prompts are very intuitive. You simply select "Autonomous Transaction Processing" in the Oracle Database menu screen as shown below and then click the "Create Autonomous Database" button.  You can take all of the defaults and simply provide an admin user password.  

create atp db

When the database is created/available, you will click the "Database Connection" button and download the wallet as shown here.

download wallet

Oracle Database Free option... 

You can go here to set up the Oracle Database Free 23c

Using the container image is very simple. You can simply execute the one line below, replacing -e ORACLE_PASSWORD=Welcome12345 with a password of your choice and  replacing -v oracle-volume:/somedirectory with a directory location (or omitting it entirely if you only wish to have in-memory database).


docker pull; docker run -e ORACLE_PASSWORD=Welcome12345 -v oracle-volume:/somedirectory


That's it!  

Spring Boot

You could download and install SQLcl to manage either of the databases/options mentioned or click "Database Actions" and then "SQL" in the OCI console to manage the cloud database.  This is a good idea as these are of course very useful and it is normal best practice to do so in order to create user's, etc., however, we will simply use Java code in or Spring Boot app to create the GeoCacheUser we will use for this app.

As usual, you will need Java and Maven to build the Spring Boot app. Clone or download the repos mentioned earliercd to the geocaching-game-flutter-springboot-oraclespatial/springboot_application directory and follow these steps to create the GeoCacheUser we will use in the app:

  1. Modify the datasource config in src/main/resources/application.yaml, providing urlusername, and password
  2. run mvn clean package
  3. run java -jar target/geojson-0.0.1-SNAPSHOT.jar
  4. run curl "http://localhost:8080/geocache/createDBUser?userName=GeoCacheUser&password=[youradminorsyspassword]"replacing the password value with yours. 
  5. stop the Java/Spring Boot process started in step 3.
  6. Now modify the datasource config in src/main/resources/application.yaml again, this time providing the username and password you provided in step 4.
  7. run mvn clean package
  8. run java -jar target/geojson-0.0.1-SNAPSHOT.jar
  9. run curl http://localhost:8080/geocache/createTables

Setup is now complete and you should be able to verify but running the following commands (though they will simply return empty JSON values at this point (eg {"type":"FeatureCollection","features":[]})

  •  curl http://localhost:8080/geocache/getGeoCaches
  •  curl http://localhost:8080/geocache/getGeoCacheTop10


Now that setup is out of the way, let's look at the Spring Boot portion of our application closer.

If you are involved with back end development at all, it is quite likely you are familiar with what is by far the most popular framework in this area, Spring Boot.

Generally, you would move the data operations out into a DAO (data access object), @Component, or JPA, etc., however, for simplicity, the logic of this application is kept minimal and is contained in the Spring RestController  The simple POJOs in the geojson package are simply a representation of the GeoJSON standard mentioned earlier.

The controller contains four main methods each of which uses a @PostMapping or @GetMapping (Rest endpoint annoations) to receive requests from the Flutter application layer and uses Spring Boot's JDBCTemplate (a convenience tempate/API for using JDBC) to talk to the Oracle database.: 

  • addGeoCache and getGeoCaches methods are used to store geocaches added by a user and retrieve them in order to plot them as markers on the map for the user to view. They work against the geocache table which is simple table that stores JSON and was created during setup with:
CREATE TABLE geocache (geocache_doc VARCHAR2 (4000) CHECK (geocache_doc is json))
  • addGeoCacheJournalEntry and getGeoCacheTop10 are used to store visits to a geocache (the equivalent of signing the guestbook in a realworld geocache).  These are journal/ledger type entries, and so we use the blockchain table functionality in the Oracle database to demonstrate an example where, for example, NFT type geocaching guarantees can be provided. Rows in a blockchain table are made tamper-resistant by special sequencing and chaining algorithms. Users can verify that rows have not been tampered. Blockchain tables can be used to implement blockchain applications where the participants trust the Oracle Database provider, but want means to verify that their data hasn’t been tampered with.  This is the very simple syntax of the table taht was created during setup with:
        (creatorname VARCHAR2(128), visitorname VARCHAR2(128), imageurl VARCHAR2(128), 
         longitude NUMBER, latitude NUMBER)
        HASHING USING "SHA2_512" VERSION "v1"


These four methods are quite straightforward as we are just plotting the GeoJSON coordinate/points on the map in Flutter.  There are other queries in the app that are currently unused by the application but are available as starters to be built upon for extra functionality re spatial analysis, etc. as well as testing. 

For example, use of SDO_GEOMETRY (JGeometry), etc. to perform queries based on proximity and containment, filter data, measure distance relationships and combine/transform spatial data, manage spatial sensor data from laser scanning or photogrammetry for 3D geographic information systems (GIS) and Smart City applications.   A good starting point can be found here and the related Java API here.

Also, from here it should be easy to expand to query the list of visitor's of a given creator's caches, creators of a given visitor, etc. for follow, follow-back, analystics, etc. functionality.




I will not go into differences between various languages, frameworks, etc. here, but to give an idea, Flutter is essentially tied with React Native as far as popularity.

Flutter has grown in popular so quickly due in large part to the fact that it provides an abstraction to allow a single code base to run on "any screen" including mobile, web apps, desktop apps, etc. while at the same time allowing access to the native features of all of these devices/screens.  It is also easy to use, built on the fast, object-oriented dart language dart and based on Widgets that naturally provide well-designed and adaptable UI constructs and patterns (again with inheritance such that themes, etc. maybe implicitly inherited, etc.). As a result, and another benefit, is the extensive community support it has obtained.

Again, the app is made as simple and succinct as possible while still showing key advantages and concetps and providing a powerful foundation to build on.

Flutter is quite easy to setup, but there is quite a bit of boiler code for any given project so the repos only provides three key files. There are also some components you may need to install, depending on your needs and environment. Again these should be easy to setup and so once you have finished the "Install", "Setup Editor", and "Test Drive" steps found here you will be ready to continue with our GeoCaching application here.

Once ready, copy the three files found in the geocaching-game-flutter-springboot-oraclespatial/flutter_application directory to the corresponding location in your project. Let's look closer at these three files...

  • pubspec.yaml is the basic spec for the application including various configuration and dependencies.  We have added three key dependencies in our application (corresponding imports are found in the *.dartfile source code):
    • flutter_map: ^5.0.0 provides map functionality (we are using, a free, editable map of the world that is built by volunteers, for tiles, etc.)
    • latlong2: ^0.9.0 provides the functionality for the marker points we put on the map
    • http: ^1.0.0 provides the ability to make Rest calls (to our Spring Boot service in particular).
  • geocachejson.dart is contains the object representation of the FeatureCollection (ie GeoJSON) as well as the Rest calls for fetching/reading from our Spring Boot service.
  • main.dart is the main program for our Flutter service. It in contains...
    • main() method which is the entry point of the app and calls into MyHomePage Widget (Widgets can be stateless or stateful) which in turn has a Scaffold with a LayoutBuilder containing a Column with three navigation items that correpsond to three Widgets for display in the mainArea...
    • GeoCacheTopScoresWidget queries for and displays the top ten most signed/visited geocache locations (ie calls the Spring Boot getGeoCacheTop10  method). It includes the name, etc. of the cache as well as an icon of the picture that got the most visits.
    • GeoCacheFormWidget contains the form a user enters in order to create a geocache (ie calls the Spring Boot addGeoCache method).
    • MapWidget queries for all of the geocache information (ie calls the Spring Boot method getGeoCaches) and displays it on the map. Users can move around the map as expected and select any location. When a location is selected, the image of the geocache is displayed along with a message notifying the user of what/whose cache they have signed. This is sent to the backend to be recorded in the blockchain table (ie calls the Spring Boot  addGeoCacheJournalEntry)

Run the app

Finally, with the database and Spring Boot app running we can run the Flutter app using whichever device we prefer by selecting from the bottom right menu and hitting the Start Debugging button. Further changes to the app are hot reloaded when the files are saved (making for fast dev cycles). Note, that depending on the environment, Flutter and Spring Boot are run in, it may be necessary to configure CORS or other security support between the the services or, for dev only obviously, disable security ( eg, by clearing the relevant stamp files in the flutter\bin\cache directory and setting --disable-web-security  in flutter\packages\flutter_tools\lib\src\web\chrome.dart)

flutter visualcode options
start debugging in vscode


I've intentionally made the application and source code as succinct as possible while providing a full stack with a considerable amount of functionality that should be easy to extend and build upon.  
I look forward to any comments or questions you may have and really appreciate your time reading.

Paul Parkinson

Architect and Developer Evangelist, Microservices and Converged Database

Paul is Architect and Developer Evangelist for Microservices and the Converged Database

His focus includes data and transaction processing, service mesh and event mesh, observability, and polyglot data models, languages, and frameworks.

The 18 years prior to this he was the Transaction Processing Dev Lead for the Mid-tier and Microservices (including WebLogic and Helidon)

Creator of the workshop "Building Microservices with Oracle Converged Database" @

Holds 20+ patents and has given numerous presentations and publications over the past 20+ years.

Previous Post

Learn to profile and analyze application performance with gprofng

Michael O'Reilly | 3 min read

Next Post

How To Call Cohere and Hugging Face AI from within an Oracle database using JavaScript (store and access results using SQL, JSON, and REST)

Paul Parkinson | 10 min read