{"id":46818,"date":"2024-12-06T00:00:00","date_gmt":"2024-12-06T08:00:00","guid":{"rendered":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/"},"modified":"2025-11-13T12:57:11","modified_gmt":"2025-11-13T20:57:11","slug":"building-an-online-text-storage-service-using-spring-boot-griddb","status":"publish","type":"post","link":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/","title":{"rendered":"Building an Online Text Storage Service using Spring Boot &#038; GridDB"},"content":{"rendered":"<p>Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage solutions like Pastebin and GitHub Gist, developers are looking for efficient ways to store and share text files. In this blog post, we&#8217;ll walk you through building your own online text storage service using Spring Boot. By following our step-by-step guide, you&#8217;ll learn how to create a powerful and secure platform that allows users to store and share text files effortlessly. Whether you&#8217;re a beginner or an experienced developer, this guide will equip you with the skills to build a robust text storage service.<\/p>\n<p>We will start from the requirements, high-level design, and finally the implementation using Spring Boot with docker-compose.<\/p>\n<h2>Source Code<\/h2>\n<p>Code can be found in the griddbnet github page:<\/p>\n<p><code>$ git clone https:\/\/github.com\/griddbnet\/Blogs.git --branch springboot-snippet<\/code><\/p>\n<h3>Requirements<\/h3>\n<h4>\u2705 We will have the following functional requirements:<\/h4>\n<ol>\n<li>Users enter text data into the system with the title<\/li>\n<li><strong>User<\/strong> clicks the snippet URL to view\/edit the content<\/li>\n<li>The system must generate a unique snippet ID<\/li>\n<\/ol>\n<h4>\u274e The out of scope:<\/h4>\n<ul>\n<li>User management (register, login)<\/li>\n<li>User authentication and authorization<\/li>\n<li>User choose a custom ID<\/li>\n<\/ul>\n<h4>\u2611\ufe0f The assumptions<\/h4>\n<ul>\n<li>The system supports only text-based data<\/li>\n<li>The content does not expire<\/li>\n<li>The read-to-write ratio is around 5:1<\/li>\n<\/ul>\n<h4>\u2611\ufe0f Capacity<\/h4>\n<p>On average, each snippet size is around 30 KB with a maximum size of 10 MB. With 10 million snippets per month, and each snippet requiring 30 KB of storage: 30\/snippet * 1,000,000 snippets\/month * 12 months = 3,600,000,000 KB\/year, which is equivalent to 3.6 TB of storage per year.<\/p>\n<h2>High Level Design<\/h2>\n<p>Typically, there are two methods for storing text content: utilizing object storage such as Amazon S3 and employing a database. This article streamlines the architecture by storing the text snippets directly within the database. Both the metadata and content are housed in the same database. This strategy enhances the speed of data retrieval. However, storing extensive text in this manner can escalate the database workload, potentially affecting performance as the data volume expands.<\/p>\n<h2>Data Storage<\/h2>\n<p>We will use three tables. The first table, &#8220;users&#8221;, stores information about registered users, like name and email.<br \/>\nThe second table, named &#8220;snippets&#8221;, stores information about the text metadata, like titles or creation dates, and the users who created it. Finally, the &#8220;storage&#8221; table is the vault where the actual text content of the user&#8217;s entries is securely stored.<br \/>\nA user might create multiple snippets but a paste is owned only by a single user.<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2024\/12\/table-online-text-storage.png\"><img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2024\/12\/table-online-text-storage.png\" alt=\"\" width=\"875\" height=\"312\" class=\"aligncenter size-full wp-image-31154\" srcset=\"\/wp-content\/uploads\/2024\/12\/table-online-text-storage.png 875w, \/wp-content\/uploads\/2024\/12\/table-online-text-storage-300x107.png 300w, \/wp-content\/uploads\/2024\/12\/table-online-text-storage-768x274.png 768w, \/wp-content\/uploads\/2024\/12\/table-online-text-storage-600x214.png 600w\" sizes=\"(max-width: 875px) 100vw, 875px\" \/><\/a><\/p>\n<h2>Project Setup<\/h2>\n<h3>To get started developing you&#8217;ll need to install the following softwares<\/h3>\n<ul>\n<li><a href=\"https:\/\/jdk.java.net\/21\/\">Java 17 or later<\/a>, <a href=\"https:\/\/maven.apache.org\/download.cgi\">Maven 3.5+<\/a>, <a href=\"https:\/\/docs.docker.com\/engine\/install\/\">Docker engine<\/a>, and your favorite text editor (<a href=\"https:\/\/spring.io\/guides\/gs\/intellij-idea\/\">Intellij IDEA<\/a>, or <a href=\"https:\/\/spring.io\/guides\/gs\/guides-with-vscode\/\">VSCode<\/a>)<\/li>\n<\/ul>\n<h3>Create a Spring Boot Project<\/h3>\n<p>Spring boot offers a fast way to build applications.<br \/>\nSpring Boot does not generate code to make edits to your files. Instead, when you start your application, Spring Boot dynamically wires up beans and settings and applies them to your application context.<br \/>\nWith Spring Boot, we can focus more on the business features and less on the infrastructure.<\/p>\n<p>Navigate to <a href=\"https:\/\/start.spring.io\/\">start.spring.io<\/a>. This service pulls in all the dependencies you need for an application and does most of the setup. Click generate, it will generate the Spring Boot project and download it as a zip. Now unzip this project and import it into any IDE.&lt;br&gt;<\/p>\n<p>To interact with GridDB, we need to add a GridDB Java Client to this project. Add the following dependency into maven <code>pom.xml<\/code>.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">\n&lt;dependency&gt;\n  &lt;groupId&gt;com.github.griddb&lt;\/groupId&gt;\n  &lt;artifactId&gt;gridstore&lt;\/artifactId&gt;\n  &lt;version&gt;5.5.0&lt;\/version&gt;\n&lt;\/dependency&gt;\n&lt;dependency&gt;\n  &lt;groupId&gt;com.github.f4b6a3&lt;\/groupId&gt;\n  &lt;artifactId&gt;tsid-creator&lt;\/artifactId&gt;\n  &lt;version&gt;5.2.5&lt;\/version&gt;\n&lt;\/dependency&gt;<\/code><\/pre>\n<\/div>\n<h2>Building the Web Application<\/h2>\n<p>Based on practical considerations and familiarity, we choose Thymeleaf to render the frontend.<br \/>\nThymeleaf provides an easy-to-understand and easy-to-debug flow, making it a practical choice.<br \/>\nThymeleaf eliminates the need for additional package management, reducing complexity and potential vulnerabilities.<\/p>\n<h3>The Front-End<\/h3>\n<p>Displaying a list of snippets, we define a basic HTML table structure with header and body sections.<br \/>\nInside the body, the code iterates through a list of snippets using a Thymeleaf loop (<code>th:each<\/code>).<br \/>\nThe first column shows the snippet title inside an anchor element to create a hyperlink to the snippet details.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-html\">&lt;div th_if=\"${snippets.size() &gt; 0}\" class=\"container\"&gt;\n    &lt;table class=\"table table-hover table-responsive-xl table-striped\"&gt;\n        &lt;thead class=\"thead-light\"&gt;\n            &lt;tr&gt;\n                &lt;th scope=\"col\"&gt;Title&lt;\/th&gt;\n                &lt;th scope=\"col\"&gt;Created Time&lt;\/th&gt;\n                &lt;th scope=\"col\"&gt;Size&lt;\/th&gt;\n            &lt;\/tr&gt;\n        &lt;\/thead&gt;\n        &lt;tbody class=\"table-group-divider\"&gt;\n            &lt;tr th_each=\"snippet : ${snippets}\"&gt;\n                &lt;td&gt;\n                    &lt;a class=\"small\" th_href=\"@{\/snippets\/{id}(id=${snippet.id})}\" th_text=\"${snippet.title}\"&gt;&lt;\/a&gt;\n                &lt;\/td&gt;\n                &lt;th id=\"timeAgo\" scope=\"row\"&gt;[[${snippet.timeAgo}]]&lt;\/th&gt;\n                &lt;th id=\"contentSizeHumanReadable\" scope=\"row\"&gt;[[${snippet.contentSizeHumanReadable}]]&lt;\/th&gt;                        \n            &lt;\/tr&gt;\n        &lt;\/tbody&gt;\n    &lt;\/table&gt;\n&lt;\/div&gt;<\/code><\/pre>\n<\/div>\n<p>And this is what the listing page will look like:<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2024\/12\/snippet-list.png\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2024\/12\/snippet-list.png\" alt=\"\" width=\"637\" height=\"610\" class=\"aligncenter size-full wp-image-31153\" srcset=\"\/wp-content\/uploads\/2024\/12\/snippet-list.png 637w, \/wp-content\/uploads\/2024\/12\/snippet-list-300x287.png 300w, \/wp-content\/uploads\/2024\/12\/snippet-list-600x575.png 600w\" sizes=\"(max-width: 637px) 100vw, 637px\" \/><\/a><\/p>\n<p>Creating a new snippet by using html form. The <code>th:action<\/code> expression directs the form to POST to the <code>\/snippets\/save<\/code> endpoint. The <code>th:object=\"${snippet}\"<\/code> declares the model object to use for collecting the form data.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-html\">&lt;form th_action=\"@{\/snippets\/save}\" method=\"post\" enctype=\"multipart\/form-data\" th_object=\"${snippet}\"\n  id=\"snippetForm\" style=\"max-width: 550px; margin: 0 auto\"&gt;\n\n  &lt;div class=\"p-3\"&gt;\n      &lt;div class=\"form-group row\"&gt;\n          &lt;label class=\"col-sm-3 col-form-label\" for=\"title\"&gt;Title&lt;\/label&gt;\n          &lt;div class=\"col-sm-9\"&gt;\n              &lt;input type=\"text\" th_field=\"*{title}\" required minlength=\"2\" maxlength=\"128\"\n                  class=\"form-control\" id=\"title\" \/&gt;\n          &lt;\/div&gt;\n      &lt;\/div&gt;\n\n      &lt;div class=\"form-group row\"&gt;\n          &lt;label class=\"col-sm-3 col-form-label\" for=\"content\"&gt;Content&lt;\/label&gt;\n          &lt;div class=\"col-sm-9\"&gt;\n              &lt;textarea rows=\"20\" cols=\"80\" th_field=\"*{content}\" form=\"snippetForm\" class=\"form-control\"\n                  id=\"content\" required\/&gt;\n          &lt;\/div&gt;\n      &lt;\/div&gt;\n\n      &lt;div class=\"form-group row\"&gt;\n          &lt;label class=\"col-sm-3 col-form-label\" for=\"userId\"&gt;User&lt;\/label&gt;\n          &lt;div class=\"col-sm-9\"&gt;\n              &lt;select th_field=\"*{userId}\"&gt;\n                  &lt;option th_each=\"user : ${users}\" th_text=\"${user.fullName}\" th_value=\"${user.id}\"&gt;\n              &lt;\/select&gt;\n          &lt;\/div&gt;\n      &lt;\/div&gt;\n\n      &lt;div class=\"text-center\"&gt;\n          &lt;input type=\"submit\" value=\"Save\" class=\"btn btn-primary btn-sm mr-2\" \/&gt;\n          &lt;input type=\"button\" value=\"Cancel\" id=\"btnCancel\" class=\"btn btn-secondary btn-sm\" \/&gt;\n      &lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;\/form&gt;<\/code><\/pre>\n<\/div>\n<p>And this is what the create snippet page will look like:<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2024\/12\/create-a-snippet.png\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2024\/12\/create-a-snippet.png\" alt=\"\" width=\"642\" height=\"711\" class=\"aligncenter size-full wp-image-31151\" srcset=\"\/wp-content\/uploads\/2024\/12\/create-a-snippet.png 642w, \/wp-content\/uploads\/2024\/12\/create-a-snippet-271x300.png 271w, \/wp-content\/uploads\/2024\/12\/create-a-snippet-600x664.png 600w\" sizes=\"(max-width: 642px) 100vw, 642px\" \/><\/a><\/p>\n<h3>Data access with GridDB<\/h3>\n<p>First, we create Java POJO classes that represent the underlying table or container in GridDB.<br \/>\nWe annotate a class with Lombok @Data, which automatically generates getters for all fields, a useful toString method, and hashCode and equals implementations that check all non-transient fields. Also generate setters for all non-final fields, as well as a constructor.<\/p>\n<p>We create the data access class according to the previous database design.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">@Data\npublic class User {\n    @RowKey\n    String id;\n    String email;\n    String fullName;\n    Date createdAt;\n}\n\n@Data\npublic class Snippet {\n    @RowKey\n    String id;\n\n    String title;\n    String storageId;\n    String userId;\n    Date createdAt;\n    String contentSizeHumanReadable;\n}\n\n@Data\npublic class Storage {\n    @RowKey\n    String id;\n\n    Blob content;\n}<\/code><\/pre>\n<\/div>\n<p>&lt;br&gt;<\/p>\n<p>Next, we create the <code>GridDBConfig<\/code> class as a central configuration for database operation.<br \/>\nThe class will do the following:<br \/>\n* Read environment variables for connecting to the GridDB database<br \/>\n* Create a GridStore class for managing database connection to the GridDB instance<br \/>\n* Create GridDB Collection&#8217;s container (Table) to manage a set of rows. The container is a rough equivalent of the table in a relational database.<br \/>\n* On creating\/updating the Collection we specify the name and object corresponding to the column layout of the collection.<br \/>\n  Also for each collection, we add an index for a column that is frequently searched and used in the condition of the WHERE section of TQL.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">@Configuration\npublic class GridDBConfig {\n\n  @Value(\"${GRIDDB_NOTIFICATION_MEMBER}\")\n  private String notificationMember;\n\n  @Value(\"${GRIDDB_CLUSTER_NAME}\")\n  private String clusterName;\n\n  @Value(\"${GRIDDB_USER}\")\n  private String user;\n\n  @Value(\"${GRIDDB_PASSWORD}\")\n  private String password;\n\n  @Bean\n  public GridStore gridStore() throws GSException {\n    \/\/ Acquiring a GridStore instance\n    Properties properties = new Properties();\n    properties.setProperty(\"notificationMember\", notificationMember);\n    properties.setProperty(\"clusterName\", clusterName);\n    properties.setProperty(\"user\", user);\n    properties.setProperty(\"password\", password);\n    GridStore store = GridStoreFactory.getInstance().getGridStore(properties);\n    return store;\n  }\n\n    @Bean\n    public Collection&lt;String, User&gt; userCollection(GridStore gridStore) throws GSException {\n        Collection&lt;String, User&gt; collection = gridStore.putCollection(\"users\", User.class);\n        collection.createIndex(\"email\");\n        return collection;\n    }\n\n    @Bean\n    public Collection&lt;String, Snippet&gt; snippetCollection(GridStore gridStore) throws GSException {\n        Collection&lt;String, Snippet&gt; snippetCollection =\n                gridStore.putCollection(AppConstant.SNIPPETS_CONTAINER, Snippet.class);\n        snippetCollection.createIndex(\"userId\");\n        snippetCollection.createIndex(\"title\");\n        return snippetCollection;\n    }\n\n    @Bean\n    public Collection&lt;String, Storage&gt; storageCollection(GridStore gridStore) throws GSException {\n        Collection&lt;String, Storage&gt; storageCollection =\n                gridStore.putCollection(AppConstant.STORAGES_CONTAINER, Storage.class);\n        return storageCollection;\n    }\n}<\/code><\/pre>\n<\/div>\n<p>&lt;br&gt;<\/p>\n<h3>The Service Layer<\/h3>\n<p>In the Spring framework, the Service Layer is one of the fundamental architectural layers, primarily responsible for implementing the business logic of an application.<\/p>\n<h4><code>SnippetService<\/code><\/h4>\n<p>Method <code>fetchAll<\/code> : query all the snippets from the collection order by newly created first.<\/p>\n<p>Method <code>create<\/code>:<br \/>\n* Is responsible for storing the snippet content in the storage collections, and saving the metadata of the new snippet.<br \/>\n* Calculate the size of the content and save that info in a human-readable format.<br \/>\n* Generate a snippet ID that is non-predictable, collision-free, and should be readable.<br \/>\n* We choose Time-Sorted Unique Identifiers (TSID) as the ID of the snippet. By using TSID, we get a time-sorted identifier including a random component, and can be represented as a 13-character string.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">@Service\n@RequiredArgsConstructor\npublic class SnippetService {\n    private final Logger log = LoggerFactory.getLogger(SnippetService.class);\n    private final Collection&lt;String, Snippet&gt; snippetCollection;\n    private final Collection&lt;String, Storage&gt; storagCollection;\n\n    public List&lt;Snippet&gt; fetchAll() {\n        List&lt;Snippet&gt; snippets = new ArrayList&lt;&gt;(0);\n        try {\n            String tql = \"SELECT * FROM \" + AppConstant.SNIPPETS_CONTAINER + \" ORDER BY createdAt DESC\";\n            Query&lt;Snippet&gt; query = snippetCollection.query(tql);\n            RowSet&lt;Snippet&gt; rowSet = query.fetch();\n            while (rowSet.hasNext()) {\n                snippets.add(rowSet.next());\n            }\n        } catch (GSException e) {\n            log.error(\"Error fetch all snippet\", e);\n        }\n        return snippets;\n    }\n\n    public void create(CreateSnippet createSnippet) {\n        try {\n            Snippet found = fetchOneByTitle(createSnippet.getTitle());\n            if (found != null) {\n                return;\n            }\n            Blob content = snippetCollection.createBlob();\n            content.setBytes(1, createSnippet.getContent().getBytes());\n            Storage storage = new Storage();\n            storage.setId(KeyGenerator.next(\"obj\"));\n            storage.setContent(content);\n            storagCollection.put(storage.getId(), storage);\n            Snippet snippet = new Snippet();\n            snippet.setTitle(createSnippet.getTitle());\n            snippet.setStorageId(storage.getId());\n            snippet.setUserId(createSnippet.getUserId());\n            snippet.setCreatedAt(new Date());\n            snippet.setContentSizeHumanReadable(toHumanReadableByNumOfLeadingZeros(\n                    createSnippet.getContent().getBytes().length));\n            snippetCollection.put(KeyGenerator.next(\"sn\"), snippet);\n        } catch (GSException e) {\n            e.printStackTrace();\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n}<\/code><\/pre>\n<\/div>\n<h3>The Controller Layer<\/h3>\n<p>This layer is responsible for handling incoming HTTP requests. The controller will receive requests, process them, and interact with the previous service layer to retrieve or manipulate data.<\/p>\n<p>The <code>SnippetsController<\/code> handles all HTTP request to <code>\/snippets<\/code>.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">@Controller\n@RequestMapping(\"\/snippets\")\n@RequiredArgsConstructor\npublic class SnippetsController {\n    private static final Logger log = LoggerFactory.getLogger(SnippetsController.class);\n    private final SnippetService snippetService;\n    private final UserService userService;\n\n    @GetMapping\n    String snippets(Model model) {\n        List&lt;Snippet&gt; snippets = snippetService.fetchAll();\n        List&lt;SnippetView&gt; snippetViews = snippets.stream()\n                .map(sn -&gt; SnippetView.builder()\n                        .id(sn.getId())\n                        .title(sn.getTitle())\n                        .createdAt(sn.getCreatedAt())\n                        .timeAgo(calculateTimeAgoByTimeGranularity(sn.getCreatedAt(), TimeGranularity.MINUTES))\n                        .contentSizeHumanReadable(sn.getContentSizeHumanReadable())\n                        .build())\n                .collect(Collectors.toList());\n\n        List&lt;User&gt; users = userService.fetchAll();\n        model.addAttribute(\"snippets\", snippetViews);\n        return \"snippets\";\n    }\n\n    @GetMapping(\"\/new\")\n    String newSnippet(Model model) {\n        List&lt;User&gt; users = userService.fetchAll();\n        model.addAttribute(\"snippet\", new CreateSnippet());\n        model.addAttribute(\"users\", users);\n        return \"new_snippet\";\n    }\n\n    @PostMapping(\"\/save\")\n    String saveSnippet(@ModelAttribute(\"snippet\") CreateSnippet createSnippet) {\n        snippetService.create(createSnippet);\n        return \"redirect:\/snippets\";\n    }\n}<\/code><\/pre>\n<\/div>\n<p>Method <code>snippets(Model model)<\/code>:<br \/>\n* Handle GET request to URL <code>\/snippets<\/code><br \/>\n* Call the service layer to get a list of snippets<br \/>\n* Format the creation time into time ago format for each snippet<br \/>\n* Return a <code>View<\/code> (in this case, <code>snippets<\/code>) for rendering HTML content of snippet list<\/p>\n<p>Method <code>newSnippet(Model model)<\/code>:<br \/>\n* Handle GET request to URL <code>\/snippets\/new<\/code>.<br \/>\n* Use a <code>Model<\/code> object to expose a new Snippet (<code>CreateSnippet<\/code>) to the view template. <code>CreateSnippet<\/code> contains fields such as <code>title<\/code> and <code>content<\/code>.<br \/>\n* Call the service layer to save the Snippet data<\/p>\n<h3>Running the Project with Docker Compose<\/h3>\n<p>To spin up the project we will utilize Docker, a popular container engine.<br \/>\nFirst, build the docker image using the following command:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">  docker compose -f docker-compose-dev.yml build<\/code><\/pre>\n<\/div>\n<p>Run the app:<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">  docker compose -f docker-compose-dev.yml up<\/code><\/pre>\n<\/div>\n<p>Upon successful execution of the command, you can access the website at http:\/\/localhost:8080.<\/p>\n<h2>Conclusion<\/h2>\n<p>In conclusion, creating a basic online text storage service using Java Spring Boot and GridDB is a simple and effective process. Spring Boot allows us to concentrate on our core development tasks, while Thymeleaf speeds up template prototyping by not requiring a back-end initially. GridDB efficiently handles the storage of text content using the blob data type.<\/p>\n<p>To take your service to the next level, consider adding data compression to save on database storage, building metrics to track the viewer count of each text snippet, and encryption. By implementing these enhancements, you can turn a basic service into a powerful and feature-rich platform.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage solutions like Pastebin and GitHub Gist, developers are looking for efficient ways to store and share text files. In this blog post, we&#8217;ll walk you through building your [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":31150,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-46818","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building an Online Text Storage Service using Spring Boot &amp; GridDB | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building an Online Text Storage Service using Spring Boot &amp; GridDB | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/\" \/>\n<meta property=\"og:site_name\" content=\"GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/griddbcommunity\/\" \/>\n<meta property=\"article:published_time\" content=\"2024-12-06T08:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-13T20:57:11+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.griddb.net\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1018\" \/>\n\t<meta property=\"og:image:height\" content=\"673\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"griddb-admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:site\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"griddb-admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"Building an Online Text Storage Service using Spring Boot &#038; GridDB\",\"datePublished\":\"2024-12-06T08:00:00+00:00\",\"dateModified\":\"2025-11-13T20:57:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/\"},\"wordCount\":1290,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/griddb.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/\",\"url\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/\",\"name\":\"Building an Online Text Storage Service using Spring Boot & GridDB | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg\",\"datePublished\":\"2024-12-06T08:00:00+00:00\",\"dateModified\":\"2025-11-13T20:57:11+00:00\",\"description\":\"Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg\",\"contentUrl\":\"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg\",\"width\":1018,\"height\":673},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/griddb.net\/en\/#website\",\"url\":\"https:\/\/griddb.net\/en\/\",\"name\":\"GridDB: Open Source Time Series Database for IoT\",\"description\":\"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL\",\"publisher\":{\"@id\":\"https:\/\/griddb.net\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/griddb.net\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/griddb.net\/en\/#organization\",\"name\":\"Fixstars\",\"url\":\"https:\/\/griddb.net\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"contentUrl\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"width\":200,\"height\":83,\"caption\":\"Fixstars\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/griddbcommunity\/\",\"https:\/\/x.com\/GridDBCommunity\",\"https:\/\/www.linkedin.com\/company\/griddb-by-toshiba\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\",\"name\":\"griddb-admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"caption\":\"griddb-admin\"},\"url\":\"https:\/\/www.griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building an Online Text Storage Service using Spring Boot & GridDB | GridDB: Open Source Time Series Database for IoT","description":"Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/","og_locale":"en_US","og_type":"article","og_title":"Building an Online Text Storage Service using Spring Boot & GridDB | GridDB: Open Source Time Series Database for IoT","og_description":"Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage","og_url":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2024-12-06T08:00:00+00:00","article_modified_time":"2025-11-13T20:57:11+00:00","og_image":[{"width":1018,"height":673,"url":"https:\/\/www.griddb.net\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg","type":"image\/jpeg"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#article","isPartOf":{"@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/"},"author":{"name":"griddb-admin","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"Building an Online Text Storage Service using Spring Boot &#038; GridDB","datePublished":"2024-12-06T08:00:00+00:00","dateModified":"2025-11-13T20:57:11+00:00","mainEntityOfPage":{"@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/"},"wordCount":1290,"commentCount":0,"publisher":{"@id":"https:\/\/griddb.net\/en\/#organization"},"image":{"@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/","url":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/","name":"Building an Online Text Storage Service using Spring Boot & GridDB | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/griddb.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage"},"image":{"@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg","datePublished":"2024-12-06T08:00:00+00:00","dateModified":"2025-11-13T20:57:11+00:00","description":"Have you ever needed to share a piece of code or text quickly and securely with someone else? With the growing need for easy-to-use online text storage","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.griddb.net\/en\/blog\/building-an-online-text-storage-service-using-spring-boot-griddb\/#primaryimage","url":"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg","contentUrl":"\/wp-content\/uploads\/2024\/12\/blog-onlinetextstorage_update.jpg","width":1018,"height":673},{"@type":"WebSite","@id":"https:\/\/griddb.net\/en\/#website","url":"https:\/\/griddb.net\/en\/","name":"GridDB: Open Source Time Series Database for IoT","description":"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL","publisher":{"@id":"https:\/\/griddb.net\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/griddb.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/griddb.net\/en\/#organization","name":"Fixstars","url":"https:\/\/griddb.net\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/","url":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","contentUrl":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","width":200,"height":83,"caption":"Fixstars"},"image":{"@id":"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/griddbcommunity\/","https:\/\/x.com\/GridDBCommunity","https:\/\/www.linkedin.com\/company\/griddb-by-toshiba"]},{"@type":"Person","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233","name":"griddb-admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","caption":"griddb-admin"},"url":"https:\/\/www.griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/46818","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/comments?post=46818"}],"version-history":[{"count":1,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/46818\/revisions"}],"predecessor-version":[{"id":51478,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/46818\/revisions\/51478"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media\/31150"}],"wp:attachment":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media?parent=46818"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/categories?post=46818"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/tags?post=46818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}