Maven多模块父子工程与IDEA导入异常排查记录

Maven 多模块项目父子关系与 IDEA 导入异常排查记录

1. 问题背景

在学习 Spring AI 时,准备将多个 Demo 整合到一个 Maven 多模块工程中:

text 复制代码
Spring-AI-demo
│
├── pom.xml                 # 父工程
│
├── Spring-ai-demo
│   └── pom.xml             # 子模块
│
└── Spring-AI-ollama-Demo
    └── pom.xml             # 子模块

目标结构:
#mermaid-svg-RYdGQOM6TTOP8wLB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RYdGQOM6TTOP8wLB .error-icon{fill:#552222;}#mermaid-svg-RYdGQOM6TTOP8wLB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RYdGQOM6TTOP8wLB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RYdGQOM6TTOP8wLB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RYdGQOM6TTOP8wLB .marker.cross{stroke:#333333;}#mermaid-svg-RYdGQOM6TTOP8wLB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RYdGQOM6TTOP8wLB p{margin:0;}#mermaid-svg-RYdGQOM6TTOP8wLB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RYdGQOM6TTOP8wLB .cluster-label text{fill:#333;}#mermaid-svg-RYdGQOM6TTOP8wLB .cluster-label span{color:#333;}#mermaid-svg-RYdGQOM6TTOP8wLB .cluster-label span p{background-color:transparent;}#mermaid-svg-RYdGQOM6TTOP8wLB .label text,#mermaid-svg-RYdGQOM6TTOP8wLB span{fill:#333;color:#333;}#mermaid-svg-RYdGQOM6TTOP8wLB .node rect,#mermaid-svg-RYdGQOM6TTOP8wLB .node circle,#mermaid-svg-RYdGQOM6TTOP8wLB .node ellipse,#mermaid-svg-RYdGQOM6TTOP8wLB .node polygon,#mermaid-svg-RYdGQOM6TTOP8wLB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RYdGQOM6TTOP8wLB .rough-node .label text,#mermaid-svg-RYdGQOM6TTOP8wLB .node .label text,#mermaid-svg-RYdGQOM6TTOP8wLB .image-shape .label,#mermaid-svg-RYdGQOM6TTOP8wLB .icon-shape .label{text-anchor:middle;}#mermaid-svg-RYdGQOM6TTOP8wLB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RYdGQOM6TTOP8wLB .rough-node .label,#mermaid-svg-RYdGQOM6TTOP8wLB .node .label,#mermaid-svg-RYdGQOM6TTOP8wLB .image-shape .label,#mermaid-svg-RYdGQOM6TTOP8wLB .icon-shape .label{text-align:center;}#mermaid-svg-RYdGQOM6TTOP8wLB .node.clickable{cursor:pointer;}#mermaid-svg-RYdGQOM6TTOP8wLB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RYdGQOM6TTOP8wLB .arrowheadPath{fill:#333333;}#mermaid-svg-RYdGQOM6TTOP8wLB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RYdGQOM6TTOP8wLB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RYdGQOM6TTOP8wLB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RYdGQOM6TTOP8wLB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RYdGQOM6TTOP8wLB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RYdGQOM6TTOP8wLB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RYdGQOM6TTOP8wLB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RYdGQOM6TTOP8wLB .cluster text{fill:#333;}#mermaid-svg-RYdGQOM6TTOP8wLB .cluster span{color:#333;}#mermaid-svg-RYdGQOM6TTOP8wLB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RYdGQOM6TTOP8wLB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RYdGQOM6TTOP8wLB rect.text{fill:none;stroke-width:0;}#mermaid-svg-RYdGQOM6TTOP8wLB .icon-shape,#mermaid-svg-RYdGQOM6TTOP8wLB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RYdGQOM6TTOP8wLB .icon-shape p,#mermaid-svg-RYdGQOM6TTOP8wLB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RYdGQOM6TTOP8wLB .icon-shape .label rect,#mermaid-svg-RYdGQOM6TTOP8wLB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RYdGQOM6TTOP8wLB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RYdGQOM6TTOP8wLB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RYdGQOM6TTOP8wLB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Spring-AI-demo 父工程

packaging=pom
Spring-ai-demo 子模块
Spring-AI-ollama-Demo 子模块

但是 IDEA Maven 面板出现:

text 复制代码
Spring-AI-demo (root)

spring-ai-demo

两个项目并列显示,而不是:

text 复制代码
Spring-AI-demo
    |
    └── spring-ai-demo

因此怀疑 Maven 多模块配置异常。


2. 初步排查:检查 pom.xml

2.1 父工程 pom

父工程核心配置:

xml 复制代码
<packaging>pom</packaging>

<modules>
    <module>Spring-ai-demo</module>
</modules>

含义:

  • 当前项目不是普通 Spring Boot 应用
  • 它负责聚合管理子模块
  • Maven 会根据 modules 查找子工程

2.2 子工程 pom

子工程:

xml 复制代码
<parent>
    <groupId>com.djm</groupId>
    <artifactId>Spring-AI-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>

含义:

子模块继承父工程。

最终关系:
#mermaid-svg-R9y5V7xlbozLL25B{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-R9y5V7xlbozLL25B .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-R9y5V7xlbozLL25B .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-R9y5V7xlbozLL25B .error-icon{fill:#552222;}#mermaid-svg-R9y5V7xlbozLL25B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-R9y5V7xlbozLL25B .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-R9y5V7xlbozLL25B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-R9y5V7xlbozLL25B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-R9y5V7xlbozLL25B .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-R9y5V7xlbozLL25B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-R9y5V7xlbozLL25B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-R9y5V7xlbozLL25B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-R9y5V7xlbozLL25B .marker.cross{stroke:#333333;}#mermaid-svg-R9y5V7xlbozLL25B svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-R9y5V7xlbozLL25B p{margin:0;}#mermaid-svg-R9y5V7xlbozLL25B .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-R9y5V7xlbozLL25B .cluster-label text{fill:#333;}#mermaid-svg-R9y5V7xlbozLL25B .cluster-label span{color:#333;}#mermaid-svg-R9y5V7xlbozLL25B .cluster-label span p{background-color:transparent;}#mermaid-svg-R9y5V7xlbozLL25B .label text,#mermaid-svg-R9y5V7xlbozLL25B span{fill:#333;color:#333;}#mermaid-svg-R9y5V7xlbozLL25B .node rect,#mermaid-svg-R9y5V7xlbozLL25B .node circle,#mermaid-svg-R9y5V7xlbozLL25B .node ellipse,#mermaid-svg-R9y5V7xlbozLL25B .node polygon,#mermaid-svg-R9y5V7xlbozLL25B .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-R9y5V7xlbozLL25B .rough-node .label text,#mermaid-svg-R9y5V7xlbozLL25B .node .label text,#mermaid-svg-R9y5V7xlbozLL25B .image-shape .label,#mermaid-svg-R9y5V7xlbozLL25B .icon-shape .label{text-anchor:middle;}#mermaid-svg-R9y5V7xlbozLL25B .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-R9y5V7xlbozLL25B .rough-node .label,#mermaid-svg-R9y5V7xlbozLL25B .node .label,#mermaid-svg-R9y5V7xlbozLL25B .image-shape .label,#mermaid-svg-R9y5V7xlbozLL25B .icon-shape .label{text-align:center;}#mermaid-svg-R9y5V7xlbozLL25B .node.clickable{cursor:pointer;}#mermaid-svg-R9y5V7xlbozLL25B .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-R9y5V7xlbozLL25B .arrowheadPath{fill:#333333;}#mermaid-svg-R9y5V7xlbozLL25B .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-R9y5V7xlbozLL25B .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-R9y5V7xlbozLL25B .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R9y5V7xlbozLL25B .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-R9y5V7xlbozLL25B .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R9y5V7xlbozLL25B .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-R9y5V7xlbozLL25B .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-R9y5V7xlbozLL25B .cluster text{fill:#333;}#mermaid-svg-R9y5V7xlbozLL25B .cluster span{color:#333;}#mermaid-svg-R9y5V7xlbozLL25B div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-R9y5V7xlbozLL25B .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-R9y5V7xlbozLL25B rect.text{fill:none;stroke-width:0;}#mermaid-svg-R9y5V7xlbozLL25B .icon-shape,#mermaid-svg-R9y5V7xlbozLL25B .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R9y5V7xlbozLL25B .icon-shape p,#mermaid-svg-R9y5V7xlbozLL25B .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-R9y5V7xlbozLL25B .icon-shape .label rect,#mermaid-svg-R9y5V7xlbozLL25B .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R9y5V7xlbozLL25B .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-R9y5V7xlbozLL25B .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-R9y5V7xlbozLL25B :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} spring-boot-starter-parent
Spring-AI-demo
Spring-ai-demo


3. 使用 Maven 命令验证

不要只相信 IDEA 界面。

进入父工程目录:

bash 复制代码
mvn validate

输出:

text 复制代码
Reactor Build Order:

Spring-AI-demo [pom]
Spring-ai-demo [jar]

说明:
#mermaid-svg-UpLZRNUm0NUWoVgH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UpLZRNUm0NUWoVgH .error-icon{fill:#552222;}#mermaid-svg-UpLZRNUm0NUWoVgH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UpLZRNUm0NUWoVgH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UpLZRNUm0NUWoVgH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UpLZRNUm0NUWoVgH .marker.cross{stroke:#333333;}#mermaid-svg-UpLZRNUm0NUWoVgH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UpLZRNUm0NUWoVgH p{margin:0;}#mermaid-svg-UpLZRNUm0NUWoVgH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UpLZRNUm0NUWoVgH .cluster-label text{fill:#333;}#mermaid-svg-UpLZRNUm0NUWoVgH .cluster-label span{color:#333;}#mermaid-svg-UpLZRNUm0NUWoVgH .cluster-label span p{background-color:transparent;}#mermaid-svg-UpLZRNUm0NUWoVgH .label text,#mermaid-svg-UpLZRNUm0NUWoVgH span{fill:#333;color:#333;}#mermaid-svg-UpLZRNUm0NUWoVgH .node rect,#mermaid-svg-UpLZRNUm0NUWoVgH .node circle,#mermaid-svg-UpLZRNUm0NUWoVgH .node ellipse,#mermaid-svg-UpLZRNUm0NUWoVgH .node polygon,#mermaid-svg-UpLZRNUm0NUWoVgH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UpLZRNUm0NUWoVgH .rough-node .label text,#mermaid-svg-UpLZRNUm0NUWoVgH .node .label text,#mermaid-svg-UpLZRNUm0NUWoVgH .image-shape .label,#mermaid-svg-UpLZRNUm0NUWoVgH .icon-shape .label{text-anchor:middle;}#mermaid-svg-UpLZRNUm0NUWoVgH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UpLZRNUm0NUWoVgH .rough-node .label,#mermaid-svg-UpLZRNUm0NUWoVgH .node .label,#mermaid-svg-UpLZRNUm0NUWoVgH .image-shape .label,#mermaid-svg-UpLZRNUm0NUWoVgH .icon-shape .label{text-align:center;}#mermaid-svg-UpLZRNUm0NUWoVgH .node.clickable{cursor:pointer;}#mermaid-svg-UpLZRNUm0NUWoVgH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UpLZRNUm0NUWoVgH .arrowheadPath{fill:#333333;}#mermaid-svg-UpLZRNUm0NUWoVgH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UpLZRNUm0NUWoVgH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UpLZRNUm0NUWoVgH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UpLZRNUm0NUWoVgH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UpLZRNUm0NUWoVgH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UpLZRNUm0NUWoVgH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UpLZRNUm0NUWoVgH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UpLZRNUm0NUWoVgH .cluster text{fill:#333;}#mermaid-svg-UpLZRNUm0NUWoVgH .cluster span{color:#333;}#mermaid-svg-UpLZRNUm0NUWoVgH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UpLZRNUm0NUWoVgH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UpLZRNUm0NUWoVgH rect.text{fill:none;stroke-width:0;}#mermaid-svg-UpLZRNUm0NUWoVgH .icon-shape,#mermaid-svg-UpLZRNUm0NUWoVgH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UpLZRNUm0NUWoVgH .icon-shape p,#mermaid-svg-UpLZRNUm0NUWoVgH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UpLZRNUm0NUWoVgH .icon-shape .label rect,#mermaid-svg-UpLZRNUm0NUWoVgH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UpLZRNUm0NUWoVgH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UpLZRNUm0NUWoVgH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UpLZRNUm0NUWoVgH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Maven Reactor
Spring-AI-demo
Spring-ai-demo

Maven 本身已经正确识别父子关系。

因此:

  • pom 文件没有根本错误
  • modules 配置正常
  • parent 继承正常

4. 真正的问题:IDEA 项目模型

Maven 和 IDEA 使用不同的模型。

Maven 模型

由:

xml 复制代码
<modules>

决定。

IDEA 模型

由:

text 复制代码
.idea
*.iml

决定。

之前的问题:
#mermaid-svg-ZPdYnkAPQvRRTbSQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .error-icon{fill:#552222;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .marker.cross{stroke:#333333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ p{margin:0;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .cluster-label text{fill:#333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .cluster-label span{color:#333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .cluster-label span p{background-color:transparent;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .label text,#mermaid-svg-ZPdYnkAPQvRRTbSQ span{fill:#333;color:#333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .node rect,#mermaid-svg-ZPdYnkAPQvRRTbSQ .node circle,#mermaid-svg-ZPdYnkAPQvRRTbSQ .node ellipse,#mermaid-svg-ZPdYnkAPQvRRTbSQ .node polygon,#mermaid-svg-ZPdYnkAPQvRRTbSQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .rough-node .label text,#mermaid-svg-ZPdYnkAPQvRRTbSQ .node .label text,#mermaid-svg-ZPdYnkAPQvRRTbSQ .image-shape .label,#mermaid-svg-ZPdYnkAPQvRRTbSQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .rough-node .label,#mermaid-svg-ZPdYnkAPQvRRTbSQ .node .label,#mermaid-svg-ZPdYnkAPQvRRTbSQ .image-shape .label,#mermaid-svg-ZPdYnkAPQvRRTbSQ .icon-shape .label{text-align:center;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .node.clickable{cursor:pointer;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .arrowheadPath{fill:#333333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZPdYnkAPQvRRTbSQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZPdYnkAPQvRRTbSQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZPdYnkAPQvRRTbSQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .cluster text{fill:#333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .cluster span{color:#333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZPdYnkAPQvRRTbSQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .icon-shape,#mermaid-svg-ZPdYnkAPQvRRTbSQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .icon-shape p,#mermaid-svg-ZPdYnkAPQvRRTbSQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .icon-shape .label rect,#mermaid-svg-ZPdYnkAPQvRRTbSQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZPdYnkAPQvRRTbSQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZPdYnkAPQvRRTbSQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZPdYnkAPQvRRTbSQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Maven
Spring-AI-demo
Spring-ai-demo
IDEA
Spring-AI-demo Module
Spring-ai-demo Module

也就是说:

Maven 认为:

一个父工程包含子模块

但是 IDEA 认为:

两个独立 Maven 项目


5. 为什么修改 pom 没有效果?

因为 IDEA 已经缓存了旧项目结构。

即使:

xml 复制代码
<parent>

和:

xml 复制代码
<modules>

修改正确。

IDEA 仍然读取旧的:

text 复制代码
.idea/
*.iml

导致 Module 关系没有刷新。


6. 最终解决方案

Step 1:确认 Maven 配置正确

执行:

bash 复制代码
mvn validate

确认 Reactor Build Order。


Step 2:删除 IDEA 项目缓存

删除:

text 复制代码
.idea
*.iml

注意:

不要删除:

text 复制代码
pom.xml
src

Step 3:重新导入父工程

不要打开子模块 pom。

正确方式:

text 复制代码
Open

Spring-AI-demo/pom.xml

让 IDEA 根据 Maven Reactor 重新生成项目模型。


7. 最终正确结构

IDEA Maven 面板:

text 复制代码
Spring-AI-demo (root)
│
├── Lifecycle
├── Plugins
│
└── Spring-ai-demo
        |
        ├── Lifecycle
        └── Plugins

Project Structure:

text 复制代码
Modules

Spring-AI-demo
Spring-ai-demo

8. 本次问题总结

错误认知

认为:

修改 pom 后 IDEA 会自动理解新的父子关系。

实际上:

Maven 配置和 IDEA 工程模型是两个独立系统。


排查流程总结

以后遇到 Maven 多模块问题:

  1. 检查父 pom:
xml 复制代码
<modules>
  1. 检查子 pom:
xml 复制代码
<parent>
  1. 使用:
bash 复制代码
mvn validate

确认 Maven Reactor。

  1. 如果 Maven 正常,IDEA 异常:

优先考虑:

  • Maven Reload
  • 删除 .idea
  • 删除 .iml
  • 重新从父 pom 导入

9. 经验总结

这次问题本质:

不是 Spring AI 问题。

不是依赖问题。

不是代码问题。

而是:

Maven 多模块结构、Maven Reactor 和 IDEA Module 模型之间的不一致。

理解这一点以后,面对企业项目中的:

text 复制代码
xxx-project
├── xxx-common
├── xxx-user
├── xxx-order
└── xxx-gateway

这类大型 Maven 工程,可以快速判断项目结构和排查导入问题。

相关推荐
≮傷£≯√1 小时前
OpenCV ncnn 人脸识别(一)
服务器·人工智能·opencv
动物园猫1 小时前
绝缘子目标检测数据集:2,000张图像 | 目标检测
人工智能·目标检测·计算机视觉
甲维斯1 小时前
很遗憾!GPT5.6SOL又输给了O哥了!
人工智能
彩讯股份3006341 小时前
Claude Code 开启多 Session 通信,Rich AIBox 拆解多智能体 AI 团队
人工智能
我不是疯子是傻子1 小时前
用 DeepSeek 将 Modbus 协议文档自动化为 Qt 枚举与寄存器结构体?「文档解析+AI生成+编译验证」的代码工厂实践
人工智能·qt·自动化
小淮AI1 小时前
告别水印困扰?2026年AI图像修复工具实测
人工智能
泛凡(Linyongui)1 小时前
第三篇、生命的bug分两种:一种是Flash坏了,一种是RAM乱了
人工智能·单片机·程序人生
OAK中国_官方1 小时前
在 OAK 上进行箱体尺寸测量:无需专用测量系统
人工智能·机器人·oak深度相机·箱体测量
网易云信1 小时前
AI 也要"背业绩":销售正在成为 Agent 落地的下一个黄金战场
人工智能·agent