{"id":5560,"date":"2024-09-18T10:10:08","date_gmt":"2024-09-18T10:10:08","guid":{"rendered":"https:\/\/www.aegissofttech.com\/insights\/?p=5560"},"modified":"2025-10-02T06:50:33","modified_gmt":"2025-10-02T06:50:33","slug":"integrating-ai-with-spring-tutorial","status":"publish","type":"post","link":"https:\/\/www.aegissofttech.com\/insights\/integrating-ai-with-spring-tutorial\/","title":{"rendered":"Integrating AI with Spring Tutorial: Building Intelligent Applications with Spring AI"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"5560\" class=\"elementor elementor-5560\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7c0448b9 e-flex e-con-boxed e-con e-parent\" data-id=\"7c0448b9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d0e92dd elementor-widget elementor-widget-text-editor\" data-id=\"d0e92dd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><\/p>\n<p>In the fast-paced world of technology, integrating artificial intelligence (AI) into applications has become essential for driving innovation and improving efficiency. The <a href=\"https:\/\/spring.io\/projects\/spring-ai\" target=\"_blank\" rel=\"noopener\">Spring AI Project<\/a> is a powerful extension of the Spring framework, designed to make it easier to incorporate AI capabilities into Spring-based applications. Let us delve into understanding Spring AI and Spring AI Structured Outputs.<\/p>\n<h2>1. What is Spring AI?<\/h2>\n<p>The <a href=\"https:\/\/spring.io\/projects\/spring-ai\" target=\"_blank\" rel=\"noopener\">Spring AI Project<\/a> extends the widely adopted Spring framework, providing a suite of tools and libraries that simplify the integration of AI functionalities into Spring applications. It bridges the gap between AI models and business applications, offering seamless integration, enhanced configurability, and strong support for various AI services and frameworks. Whether you&#8217;re working with machine learning models, natural language processing, or computer vision, Spring AI equips you with the components needed to effortlessly embed AI capabilities into your application. Spring AI offers three built-in classes\u2014<code>MapOutputConverter<\/code>, <code>ListOutputConverter<\/code>, and <code>BeanOutputConverter<\/code>\u2014that facilitate handling the most common response structures typically encountered in APIs. At a broad level, these converters serve two primary functions:<\/p>\n<ul>\n<li>They guide the prompt to generate responses in a specified format (such as XML or JSON) and structure, ensuring consistent and precise output.<\/li>\n<li>After receiving the response, they parse it into Java development services classes, including POJOs, Lists, or Maps, facilitating seamless integration with Java-based applications.<\/li>\n<\/ul>\n<h2>2. How to generate an OpenAI API key?<\/h2>\n<p>We&#8217;ll use an OpenAI model to generate a chat completion bot, so let&#8217;s first understand how to obtain an OpenAI key.<\/p>\n<ul>\n<li>Create an Account or Sign In: Go to the <a href=\"https:\/\/www.openai.com\" target=\"_blank\" rel=\"noopener\">OpenAI website<\/a> and either sign up for a new account or log in to your existing one.<\/li>\n<li>Access API Keys: After logging in, head to the API Keys section within your account dashboard.<\/li>\n<li>Generate a New API Key: Select the option to create a new API key. Assign a name or description to the key for easy reference.<\/li>\n<li>Generate and Save the Key: Click the Generate Key button. Make sure to copy the newly created API key and store it in a safe place, as you will need it to access OpenAI&#8217;s services.<\/li>\n<\/ul>\n<h2>3. Code example<\/h2>\n<h3>3.1 Dependencies<\/h3>\n<p>Add the following dependencies to your <code>pom.xml<\/code> file.<\/p>\n<pre>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"\n         xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 https:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt;\n    &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\n    &lt;parent&gt;\n        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n        &lt;artifactId&gt;spring-boot-starter-parent&lt;\/artifactId&gt;\n        &lt;version&gt;3.3.3&lt;\/version&gt;\n        &lt;relativePath\/&gt; &lt;!-- lookup parent from repository --&gt;\n    &lt;\/parent&gt;\n    &lt;groupId&gt;com&lt;\/groupId&gt;\n    &lt;artifactId&gt;demo&lt;\/artifactId&gt;\n    &lt;version&gt;0.0.1-SNAPSHOT&lt;\/version&gt;\n    &lt;name&gt;springai-structuredoutput&lt;\/name&gt;\n    &lt;description&gt;springai-structuredoutput&lt;\/description&gt;\n    &lt;url\/&gt;\n    &lt;licenses&gt;\n        &lt;license\/&gt;\n    &lt;\/licenses&gt;\n    &lt;developers&gt;\n        &lt;developer\/&gt;\n    &lt;\/developers&gt;\n    &lt;scm&gt;\n        &lt;connection\/&gt;\n        &lt;developerConnection\/&gt;\n        &lt;tag\/&gt;\n        &lt;url\/&gt;\n    &lt;\/scm&gt;\n    &lt;properties&gt;\n        &lt;java.version&gt;17&lt;\/java.version&gt;\n        &lt;spring-ai.version&gt;1.0.0-M2&lt;\/spring-ai.version&gt;\n    &lt;\/properties&gt;\n    &lt;dependencies&gt;\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt;\n        &lt;\/dependency&gt;\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework.ai&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-ai-openai-spring-boot-starter&lt;\/artifactId&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n            &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;\n            &lt;scope&gt;test&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n    &lt;\/dependencies&gt;\n    &lt;dependencyManagement&gt;\n        &lt;dependencies&gt;\n            &lt;dependency&gt;\n                &lt;groupId&gt;org.springframework.ai&lt;\/groupId&gt;\n                &lt;artifactId&gt;spring-ai-bom&lt;\/artifactId&gt;\n                &lt;version&gt;${spring-ai.version}&lt;\/version&gt;\n                &lt;type&gt;pom&lt;\/type&gt;\n                &lt;scope&gt;import&lt;\/scope&gt;\n            &lt;\/dependency&gt;\n        &lt;\/dependencies&gt;\n    &lt;\/dependencyManagement&gt;\n\n    &lt;build&gt;\n        &lt;plugins&gt;\n            &lt;plugin&gt;\n                &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\n                &lt;artifactId&gt;spring-boot-maven-plugin&lt;\/artifactId&gt;\n            &lt;\/plugin&gt;\n        &lt;\/plugins&gt;\n    &lt;\/build&gt;\n    &lt;repositories&gt;\n        &lt;repository&gt;\n            &lt;id&gt;spring-milestones&lt;\/id&gt;\n            &lt;name&gt;Spring Milestones&lt;\/name&gt;\n            &lt;url&gt;https:\/\/repo.spring.io\/milestone&lt;\/url&gt;\n            &lt;snapshots&gt;\n                &lt;enabled&gt;false&lt;\/enabled&gt;\n            &lt;\/snapshots&gt;\n        &lt;\/repository&gt;\n    &lt;\/repositories&gt;\n\n&lt;\/project&gt;\n<\/pre>\n<h3>3.2 Update the application properties<\/h3>\n<p>Add the following properties to the <code>application.properties<\/code> file. Remember to replace the OpenAI key.<\/p>\n<pre># Application properties\nspring.application.name=springai-structuredoutput\nspring.main.banner-mode=off\nserver.port=9090\n\n# OpenAI API key\nspring.ai.openai.api-key=your-openai-api-key\n<\/pre>\n<h3>3.3 Create a Model DTO<\/h3>\n<p>Create a Model DTO as it will be used for the <code>BeanOutputConverter<\/code> endpoint in the controller.<\/p>\n<pre>package com.demo.model;\n\npublic class Movie {\n\n    private String category;\n    private String book;\n    private String year;\n    private String review;\n    private String author;\n    private String summary;\n\n    public Movie() {\n    }\n\n    public Movie(String category, String book, String year, String review, String author, String summary) {\n        this.category = category;\n        this.book = book;\n        this.year = year;\n        this.review = review;\n        this.author = author;\n        this.summary = summary;\n    }\n\n    \/\/ getter method\n}\n<\/pre>\n<h3>3.4 Creating the Controller<\/h3>\n<p>The <code>ChatController<\/code> class is a REST controller in a Spring Boot application, responsible for handling the HTTP requests related to Structured Ouput in Spring AI.<\/p>\n<pre>package com.demo.controller;\n\nimport com.demo.model.Movie;\nimport org.springframework.ai.chat.client.ChatClient;\nimport org.springframework.ai.converter.ListOutputConverter;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.List;\nimport java.util.Map;\n\n@RestController\n@RequestMapping(\"\/chat\")\npublic class ChatController {\n\n    private final ChatClient client;\n\n    @Autowired\n    public ChatController(ChatClient.Builder builder) {\n        this.client = builder.build();\n    }\n\n    \/**\n     * Handles GET requests to \/chat\/response.\n     *\n     * @param category the category of the movie\n     * @param year     the year of the movie\n     * @return a JSON string containing the movie details\n     *\/\n    \/\/ curl -X GET \"http:\/\/localhost:9090\/chat\/response?category=action&amp;year=2022\"\n    @GetMapping(\"\/response\")\n    public String getResponse(@RequestParam String category, @RequestParam String year) {\n        System.out.println(\"category: \" + category);\n        System.out.println(\"year: \" + year);\n        System.out.println(\"String response\");\n        return client.prompt()\n                .user(user -&gt; user.text(\"Please provide the movie detail for the given {category} and {year} in the JSON format.\")\n                        .param(\"category\", category)\n                        .param(\"year\", year))\n                .call()\n                .content();\n\n    }\n\n\n    \/**\n     * Handles GET requests to \/chat\/beanResponse.\n     *\n     * @param category the category of the movie\n     * @param year     the year of the movie\n     * @return a Movie object containing the movie details\n     *\/\n    \/\/ curl -X GET \"http:\/\/localhost:9090\/chat\/beanResponse?category=action&amp;year=2022\"\n    @GetMapping(\"\/beanResponse\")\n    public Movie getBeanResponse(@RequestParam String category, @RequestParam String year) {\n        System.out.println(\"category: \" + category);\n        System.out.println(\"year: \" + year);\n        System.out.println(\"Bean response\");\n        return client.prompt()\n                .user(user -&gt; user.text(\"Please provide the movie detail for the given {category} and {year}.\")\n                        .param(\"category\", category)\n                        .param(\"year\", year))\n                .call()\n                .entity(Movie.class);\n    }\n\n    \/**\n     * Handles GET requests to \/chat\/listResponse.\n     *\n     * @param category the category of the movie\n     * @param year     the year of the movie\n     * @return a list of strings containing the names of the best movies\n     *\/\n    \/\/ curl -X GET \"http:\/\/localhost:9090\/chat\/listResponse?category=action&amp;year=2022\"\n    @GetMapping(\"\/listResponse\")\n    public List&lt;String&gt; getListResponse(@RequestParam String category, @RequestParam String year) {\n        System.out.println(\"category: \" + category);\n        System.out.println(\"year: \" + year);\n        System.out.println(\"List response\");\n        return client.prompt()\n                .user(user -&gt; user.text(\"Please provide the names of 5 best movies for the given {category} and {year}.\")\n                        .param(\"category\", category)\n                        .param(\"year\", year))\n                .call()\n                .entity(new ListOutputConverter(new DefaultConversionService()));\n    }\n\n    \/**\n     * Handles GET requests to \/chat\/mapResponse.\n     *\n     * @param category the category of the movie\n     * @param year     the year of the movie\n     * @return a map containing the movie details\n     *\/\n    \/\/ curl -X GET \"http:\/\/localhost:9090\/chat\/mapResponse?category=action&amp;year=2022\"\n    @GetMapping(\"\/mapResponse\")\n    public Map&lt;String, Object&gt; getMapResponse(@RequestParam String category, @RequestParam String year) {\n        System.out.println(\"category: \" + category);\n        System.out.println(\"year: \" + year);\n        System.out.println(\"Map response\");\n        return client.prompt()\n                .user(u -&gt; u.text(\"\"\"\n                                Please provide me best movie for the given {category} and the {year}.\n                                Please do provide a summary of the movie as well, the information should be\\s\n                                limited and not much in depth. The response should be in the JSON format\\s\n                                containing this information:\n                                category, movie, year, review, author, summary\n                                Please remove ```json from the final output\n                                \"\"\")\n                        .param(\"category\", category)\n                        .param(\"year\", year))\n                .call()\n                .entity(new ParameterizedTypeReference&lt;&gt;() {\n                });\n    }\n}\n<\/pre>\n<h3>3.5 Create the Main file<\/h3>\n<p>Create a Spring Boot application to initialize the application.<\/p>\n<pre>package com.demo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SpringaiStructuredoutputApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringaiStructuredoutputApplication.class, args);\n        System.out.println(\"Application started successfully.\");\n    }\n}\n<\/pre>\n<h3>3.6 Run the application and Demo<\/h3>\n<p>Now start the application and open the Postman tool to hit the api endpoint. Import the below curl GET requests in the Postman tool. You\u2019re free to change the prompt with a valid instruction.<\/p>\n<pre>\/\/ Handles GET requests to \/chat\/response.\ncurl -X GET \"http:\/\/localhost:9090\/chat\/response?category=action&amp;year=2022\"\n\n\n\/\/ Handles GET requests to \/chat\/beanResponse.\nhttp:\/\/localhost:9090\/chat\/beanResponse?category=action&year=2022\n\n\n\/\/ Handles GET requests to \/chat\/listResponse.\nhttp:\/\/localhost:9090\/chat\/listResponse?category=action&year=2022\n\n\n\/\/ Handles GET requests to \/chat\/mapResponse.\nhttp:\/\/localhost:9090\/chat\/mapResponse?category=action&year=2022\n<\/pre>\n<p>If everything goes well api responses in different formats will be returned and shown to the user.<\/p>\n<h2>4. Conclusion<\/h2>\n<p>In conclusion, as <a href=\"https:\/\/www.aegissofttech.com\/generative-ai-services\">Generative AI Development Services<\/a> continues to reshape the technological landscape, tools like Spring AI are essential for seamlessly integrating AI into applications. By leveraging <a href=\"https:\/\/www.aegissofttech.com\/insights\/alternatives-to-spring-apache-shiro-2-quarkus\/\">Alternative to Spring boot<\/a> AI, developers can easily add advanced AI capabilities to their Spring-based projects, enabling innovative solutions like generating images from user prompts, chat completion bots, etc.<\/p>\n<h2>5. Download the code<\/h2>\n<div>You can download the full code here: <a href=\"https:\/\/drive.usercontent.google.com\/u\/0\/uc?id=17lUm3fuM4fpmaL9p9pgLCEW7baM4Xs3V&amp;export=download\" target=\"_blank\" rel=\"noopener\"><strong>Download<\/strong><\/a><\/div>\n<div>\u00a0<\/div>\n<h4>Here is another Tutorial for\u00a0<a href=\"https:\/\/www.aegissofttech.com\/insights\/kafka-baggage-amp-webflux-migration-to-spring-boot\/\"><span style=\"color: var( --e-global-color-text ); font-family: var( --e-global-typography-text-font-family ), Sans-serif; font-weight: var( --e-global-typography-text-font-weight ); text-align: var(--text-align); background-color: var(--ast-global-color-5); font-size: 1rem;\">Kafka migration to Spring Boot 3.X<\/span><\/a><\/h4>\n<p><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":" ","protected":false},"author":12,"featured_media":5566,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[16,12,919],"tags":[],"class_list":["post-5560","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai","category-java","category-spring-boot"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/posts\/5560","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/comments?post=5560"}],"version-history":[{"count":17,"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/posts\/5560\/revisions"}],"predecessor-version":[{"id":14785,"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/posts\/5560\/revisions\/14785"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/media\/5566"}],"wp:attachment":[{"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/media?parent=5560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/categories?post=5560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aegissofttech.com\/insights\/wp-json\/wp\/v2\/tags?post=5560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}