Build a Spring Boot 3 Web QA App with Vector Store and AI in Minutes

This guide walks through creating a Spring Boot 3 application that loads web pages into a vector database using Spring AI, configures AI models and embeddings, and exposes REST endpoints for storing documents and answering queries with retrieval‑augmented generation.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Build a Spring Boot 3 Web QA App with Vector Store and AI in Minutes

1. Introduction

This article demonstrates how to implement a web‑page question‑answering service using Spring Boot 3.4.2 and Spring AI. A given URL is loaded, its content stored in a vector database, and queries are answered by retrieving relevant chunks and sending them to a large language model.

2. Practical Example

2.1 Prepare Environment

Add the required Maven dependencies:

<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>

<!-- Ollama BGE‑M3 model for embeddings -->
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>

<!-- Milvus vector store -->
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-vector-store-milvus</artifactId>
</dependency>

<!-- Alibaba DashScope (optional) -->
<dependency>
  <groupId>com.alibaba.cloud.ai</groupId>
  <artifactId>spring-ai-alibaba-autoconfigure-dashscope</artifactId>
  <version>1.0.0.2</version>
</dependency>

<!-- Jsoup for web page parsing -->
<dependency>
  <groupId>org.jsoup</groupId>
  <artifactId>jsoup</artifactId>
  <version>1.18.3</version>
</dependency>

Configure Spring AI properties (YAML style):

spring:
  ai:
    dashscope:
      api-key: sk-xxxooo
      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
      chat:
        options:
          model: qwen-turbo
      embedding:
        enabled: false
---
spring:
  ai:
    ollama:
      base-url: http://localhost:11111
      embedding:
        model: bge-m3:latest
---
spring:
  ai:
    vectorstore:
      milvus:
        client:
          host: localhost
          port: 19530
          username: xxx
          password: ooo
        initialize-schema: true
        databaseName: "mydb"
        collectionName: "mydocs"
        autoId: true
        id-field-name: id
        embeddingDimension: 1024

Exclude conflicting auto‑configurations:

@SpringBootApplication(
    exclude = {
        OllamaChatAutoConfiguration.class,
        DashScopeEmbeddingAutoConfiguration.class
    }
)
public class SpringBootAiWebQaApplication {}

2.2 Document Reader

Implement DocumentReader using Jsoup to fetch a page and convert it to a Spring AI Document:

public class WebDocumentReader implements DocumentReader {
    private static final Logger logger = LoggerFactory.getLogger(WebDocumentReader.class);
    private final String url;
    public WebDocumentReader(String url) { this.url = url; }
    @Override
    public List<Document> get() {
        try {
            X509ExtendedTrustManager trustManager = createTrustManager();
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
            org.jsoup.nodes.Document doc = Jsoup.connect(url)
                .sslSocketFactory(sslContext.getSocketFactory())
                .get();
            Map<String, Object> metadata = Map.of(
                "source", url,
                "date", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now())
            );
            return List.of(new Document(doc.body().text(), metadata));
        } catch (Exception e) {
            logger.error("Failed to load [{}]: {}", this.url, e);
            return List.of();
        }
    }
    private X509ExtendedTrustManager createTrustManager() {
        return new X509ExtendedTrustManager() {
            public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
            // other methods omitted for brevity
        };
    }
}

2.3 Write Documents to Vector Store

@Service
public class WebDocumentService {
    private final VectorStore vectorStore;
    public WebDocumentService(VectorStore vectorStore) { this.vectorStore = vectorStore; }
    public void save(String url) {
        WebDocumentReader reader = new WebDocumentReader(url);
        List<Document> docs = reader.get();
        TokenTextSplitter splitter = new TokenTextSplitter(1000, 400, 10, 5000, true);
        List<Document> chunks = splitter.apply(docs);
        this.vectorStore.add(chunks);
    }
}

Spring AI provides several text splitters, e.g., TokenTextSplitter, ContentFormatTransformer, KeywordMetadataEnricher, and SummaryMetadataEnricher.

2.4 Configure ChatClient

@Configuration
public class ChatConfig {
    @Bean
    ChatClient chatClient(ChatClient.Builder builder, VectorStore vectorStore) {
        PromptTemplate promptTemplate = new PromptTemplate("""
            Context:
            ---------------------
            {context}
            ---------------------
            Answer the query without prior knowledge.
            Rules:
            1. If the answer is not in the context, reply \"I don't know\".
            2. Avoid phrases like \"According to the context...\".
            Query: {query}
            Answer:
            """);
        QueryAugmenter queryAugmenter = ContextualQueryAugmenter.builder()
            .promptTemplate(promptTemplate)
            .build();
        Advisor retrievalAdvisor = RetrievalAugmentationAdvisor.builder()
            .queryAugmenter(queryAugmenter)
            .documentRetriever(VectorStoreDocumentRetriever.builder()
                .similarityThreshold(0.40)
                .topK(1)
                .vectorStore(vectorStore)
                .build())
            .build();
        List<Advisor> advisors = List.of(new SimpleLoggerAdvisor(), retrievalAdvisor);
        return builder.defaultAdvisors(advisors).build();
    }
}

The RetrievalAugmentationAdvisor performs similarity search in the vector store and feeds the retrieved text together with the user query to the LLM.

2.5 Controller Endpoints

@RestController
@RequestMapping("/web")
public class WebController {
    private final WebDocumentService webDocumentService;
    public WebController(WebDocumentService webDocumentService) { this.webDocumentService = webDocumentService; }
    @GetMapping("/load")
    public ResponseEntity<?> load(String url) {
        this.webDocumentService.save(url);
        return ResponseEntity.ok("success");
    }
}

@RestController
@RequestMapping("/chat")
public class ChatController {
    private final ChatClient chatClient;
    public ChatController(ChatClient chatClient) { this.chatClient = chatClient; }
    @GetMapping
    public ResponseEntity<?> chat(String prompt) {
        String answer = this.chatClient.prompt(prompt).call().content();
        return ResponseEntity.ok(answer);
    }
}

2.6 Testing

1. Use the /web/load endpoint to store a web page (e.g., a CCTV news article) into Milvus. 2. Query the /chat endpoint with a question; the system retrieves the most relevant chunk and returns the AI‑generated answer. The console shows successful storage and retrieval.

All steps above constitute the complete tutorial for building a Spring Boot 3 web‑QA application powered by Spring AI and Milvus.

Illustration
Illustration
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootMilvusspring-aiVector StoreWeb QA
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.