跳到主要内容
Spring AI 实战:从零开发 IDEA 插件版 AI 代码助手 | 极客日志
Java AI java
Spring AI 实战:从零开发 IDEA 插件版 AI 代码助手 本文基于 Spring AI 与 IntelliJ Platform SDK,详解如何从零构建支持上下文感知的 IDE 代码助手。通过整合 JavaParser 与 Maven API 解析项目结构,结合 Prompt 工程实现 Controller、Service、Mapper 的完整生成及性能优化。方案涵盖前后端架构设计、核心功能实现、私有化部署及常见踩坑经验,旨在解决通用 AI 助手上下文缺失痛点,提供可直接复用的生产级代码参考。
岁月神偷 发布于 2026/4/11 更新于 2026/5/25 13 浏览Spring AI 实战:从零开发 IDEA 插件版 AI 代码助手
作为 Java 开发者,日常工作中难免陷入重复编写 CRUD、调试语法错误和优化性能的循环。市面上的通用 AI 代码助手往往难以精准感知项目上下文(如包结构、依赖版本、数据库表),导致生成的代码需要大量修改才能落地。
本文基于 Spring AI 与 IntelliJ Platform SDK,完整拆解一款定制化 AI 代码助手的开发全流程。后端整合 JavaParser 与 Maven API 实现代码解析,前端通过 IDEA 插件提供对话窗口和一键插入功能,支持需求描述→代码生成、上下文感知、补全三大核心能力。所有代码均为生产环境可直接复用的实战参考。
一、项目背景与架构设计
1.1 核心需求
维度 核心需求 技术挑战 代码生成 输入需求描述,生成 Controller+Service+Mapper 完整代码 Spring AI Prompt 工程、Java 语法合规性校验 代码优化 自动修复语法错误、优化性能(如 SQL 优化) JavaParser 解析 AST、大模型分析 上下文感知 感知当前项目的包结构、依赖、数据库表结构 IDEA 插件获取上下文、后端存储管理 交互体验 IDEA 内对话窗口、一键插入生成的代码 Swing 开发、前后端通信协议
1.2 整体架构
核心架构清晰呈现了前后端交互与模块逻辑:
1.3 技术栈选型
结合 Java 生态与 IDEA 插件规范,最终选型如下:
技术领域 选型 选型理由 后端核心 Spring Boot 3.2 + Spring AI 0.8.1 原生适配 Spring 生态,支持多模型统一调用 代码解析 JavaParser 3.25.10 轻量高效的 AST 解析库 Maven 交互 Maven API 3.9.6 解析 pom.xml,获取依赖与包结构 IDEA 插件 IntelliJ Platform SDK 2023.2 官方 SDK,支持全功能开发 前端交互 Swing + OkHttp 4.12.0 Swing 实现窗口,OkHttp 负责通信 大模型 GPT-4 + 通义千问 高生成质量或私有化部署可选 存储 MySQL 8.0 + Redis 7.0 存储上下文与代码片段
二、核心技术架构拆解
2.1 后端核心:Spring AI + 工具调用体系
2.1.1 Spring AI 配置
我们先完成基础配置,以 OpenAI 为例支持多模型调用:
@Configuration
public class SpringAiConfig {
@Bean
public OpenAiChatClient openAiChatClient () {
String apiKey = System.getenv("OPENAI_API_KEY" );
String baseUrl = "https://api.openai.com/v1" ;
OpenAiApi openAiApi = new OpenAiApi (baseUrl, apiKey);
OpenAiChatClient client = new OpenAiChatClient (openAiApi);
client.setTemperature(0.2 );
client.setModel("gpt-4" );
return client;
}
}
2.1.2 工具调用层:JavaParser + Maven API 工具调用层是区别于通用 AI 的核心。通过 JavaParser 解析代码 AST、Maven API 解析项目依赖,让 AI 生成的代码贴合项目实际。
@Service
public class ProjectContextParser {
public ProjectContext parseMavenProject (String pomPath) throws Exception {
ProjectContext context = new ProjectContext ();
File pomFile = new File (pomPath);
MavenXpp3Reader reader = new MavenXpp3Reader ();
Model model = reader.read(new FileReader (pomFile));
context.setGroupId(model.getGroupId());
context.setArtifactId(model.getArtifactId());
context.setBasePackage(model.getGroupId() + "." + model.getArtifactId());
List<String> dependencies = new ArrayList <>();
for (Dependency dep : model.getDependencies()) {
dependencies.add(dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion());
}
context.setDependencies(dependencies);
File srcDir = new File (pomFile.getParentFile(), "src/main/java" );
if (srcDir.exists()) {
context.setSrcRootPath(srcDir.getAbsolutePath());
List<String> packages = parsePackages(srcDir);
context.setPackages(packages);
}
return context;
}
private List<String> parsePackages (File srcDir) {
List<String> packages = new ArrayList <>();
File[] files = srcDir.listFiles();
if (files == null ) return packages;
for (File file : files) {
if (file.isDirectory()) {
String packageName = file.getAbsolutePath().replace(srcDir.getAbsolutePath(), "" )
.replace(File.separator, "." );
if (!packageName.isEmpty()) {
packages.add(packageName.substring(1 ));
}
packages.addAll(parsePackages(file));
}
}
return packages;
}
public boolean validateJavaCode (String code) {
try {
CompilationUnit cu = StaticJavaParser.parse(code);
List<Problem> problems = cu.getProblems();
return problems.isEmpty();
} catch (Exception e) {
return false ;
}
}
}
@Data
public class ProjectContext {
private String groupId;
private String artifactId;
private String basePackage;
private List<String> dependencies;
private List<String> packages;
private String srcRootPath;
private String projectId;
}
2.2 前端核心:IDEA 插件开发基础
2.2.1 插件工程搭建 使用 IntelliJ IDEA 新建 IntelliJ Platform Plugin 工程,选择 SDK 版本(2023.2)。在 plugin.xml 中定义入口与窗口布局:
<idea-plugin >
<id > com.ai.code.assistant</id >
<name > AI Code Assistant</name >
<version > 1.0</version >
<vendor email ="[email protected] " > Your Name</vendor >
<description > 基于 Spring AI 的 Java 代码助手,支持上下文感知的代码生成与优化</description >
<actions >
<action text ="AI Code Assistant" description ="Open AI Code Assistant Dialog" >
<add-to-group group-id ="EditorPopupMenu" anchor ="first" />
<keyboard-shortcut keymap ="$default" first-keystroke ="ctrl alt A" />
</action >
</actions >
<extensions defaultExtensionNs ="com.intellij" >
<toolWindow anchor ="right" factoryClass ="com.ai.code.assistant.window.AiToolWindowFactory" />
</extensions >
</idea-plugin >
2.2.2 对话窗口开发(Swing) 开发 IDEA 内的对话窗口,支持输入需求、展示生成的代码:
public class AiCodeDialog extends JDialog {
private JTextArea inputArea;
private JTextPane resultArea;
private JButton generateBtn;
private JButton insertBtn;
private Project currentProject;
public AiCodeDialog (Project project) {
super (WindowManager.getInstance().getFrame(project), "AI Code Assistant" , Dialog.ModalityType.MODELESS);
this .currentProject = project;
initUI();
setSize(800 , 600 );
setLocationRelativeTo(null );
}
private void initUI () {
inputArea = new JTextArea (5 , 50 );
inputArea.setPlaceholder("请输入代码生成需求,例如:生成用户管理的 Controller+Service+Mapper" );
JScrollPane inputScroll = new JScrollPane (inputArea);
resultArea = new JTextPane ();
resultArea.setContentType("text/java" );
JScrollPane resultScroll = new JScrollPane (resultArea);
generateBtn = new JButton ("生成代码" );
insertBtn = new JButton ("插入到编辑器" );
insertBtn.setEnabled(false );
JPanel panel = new JPanel (new BorderLayout ());
JPanel topPanel = new JPanel (new BorderLayout ());
topPanel.add(new JLabel ("需求描述:" ), BorderLayout.NORTH);
topPanel.add(inputScroll, BorderLayout.CENTER);
JPanel btnPanel = new JPanel ();
btnPanel.add(generateBtn);
btnPanel.add(insertBtn);
panel.add(topPanel, BorderLayout.NORTH);
panel.add(resultScroll, BorderLayout.CENTER);
panel.add(btnPanel, BorderLayout.SOUTH);
add(panel);
}
private void generateCode () {
ProjectContext context = collectProjectContext();
CodeGenerateRequest request = new CodeGenerateRequest ();
request.setRequirement(inputArea.getText());
request.setProjectContext(context);
OkHttpClient client = new OkHttpClient ();
resultArea.setText(generatedCode);
insertBtn.setEnabled(true );
}
private ProjectContext collectProjectContext () {
ProjectContext context = new ProjectContext ();
String projectPath = currentProject.getBasePath();
VirtualFile pomFile = currentProject.getBaseDir().findChild("pom.xml" );
if (pomFile != null ) {
context.setPomPath(pomFile.getPath());
}
Editor editor = FileEditorManager.getInstance(currentProject).getSelectedTextEditor();
if (editor != null ) {
PsiFile psiFile = PsiDocumentManager.getInstance(currentProject).getPsiFile(editor.getDocument());
if (psiFile instanceof PsiJavaFile) {
PsiJavaFile javaFile = (PsiJavaFile) psiFile;
context.setCurrentPackage(javaFile.getPackageName());
}
}
context.setProjectId(currentProject.getName());
return context;
}
private void insertCodeToEditor () {
Editor editor = FileEditorManager.getInstance(currentProject).getSelectedTextEditor();
if (editor == null ) return ;
Document document = editor.getDocument();
SelectionModel selectionModel = editor.getSelectionModel();
int start = selectionModel.getSelectionStart();
int end = selectionModel.getSelectionEnd();
WriteCommandAction.runWriteCommandAction(currentProject, () -> {
document.replaceString(start, end, resultArea.getText());
});
selectionModel.removeSelection();
editor.getCaretModel().moveToOffset(start + resultArea.getText().length());
}
}
三、核心功能实现
3.1 代码生成:Controller+Service+Mapper 完整生成
3.1.1 Prompt 工程核心逻辑 Prompt 工程是代码生成质量的关键。结合项目上下文,让 AI 生成的代码直接贴合项目包结构、依赖版本:
@Service
public class PromptEngineeringService {
public Prompt buildGeneratePrompt (String requirement, ProjectContext context) {
String systemPrompt = "你是一位资深 Java 后端开发工程师,精通 Spring Boot、MyBatis、MySQL。\n" +
"请根据以下需求和项目上下文,生成符合规范的 Java 代码:\n" +
"1. 包结构必须符合项目基础包:%s\n" +
"2. 代码必须兼容项目依赖版本,优先使用项目已引入的依赖\n" +
"3. 生成完整的 Controller+Service+Mapper 层,包含必要的注释、异常处理\n" +
"4. 代码风格符合阿里巴巴 Java 开发手册\n" +
"5. 只返回代码,不返回多余解释\n" +
"项目上下文:\n" +
"- 基础包名:%s\n" +
"- 已存在的包:%s\n" +
"- 项目依赖:%s" ;
String formattedSystemPrompt = String.format(systemPrompt,
context.getBasePackage(),
context.getBasePackage(),
String.join("," , context.getPackages()),
String.join("," , context.getDependencies()));
String userPrompt = "需求:" + requirement;
return new Prompt (List.of(
new SystemMessage (formattedSystemPrompt),
new UserMessage (userPrompt)
));
}
}
3.1.2 代码生成核心接口
@RestController
@RequestMapping("/api/code")
public class CodeGenerateController {
@Autowired
private OpenAiChatClient openAiChatClient;
@Autowired
private PromptEngineeringService promptService;
@Autowired
private ProjectContextParser contextParser;
@Autowired
private ProjectContextRepository contextRepository;
@PostMapping("/generate")
public Result<String> generateCode (@RequestBody CodeGenerateRequest request) {
try {
ProjectContext context;
if (request.getProjectContext().getProjectId() != null ) {
context = contextRepository.findByProjectId(request.getProjectContext().getProjectId());
if (context == null ) {
context = contextParser.parseMavenProject(request.getProjectContext().getPomPath());
context.setProjectId(request.getProjectContext().getProjectId());
contextRepository.save(context);
}
} else {
context = request.getProjectContext();
}
Prompt prompt = promptService.buildGeneratePrompt(request.getRequirement(), context);
AiResponse response = openAiChatClient.generate(prompt);
String generatedCode = response.getGeneration().getText();
boolean isValid = contextParser.validateJavaCode(generatedCode);
if (!isValid) {
generatedCode = regenerateCode(prompt);
}
return Result.success(generatedCode);
} catch (Exception e) {
log.error("生成代码失败" , e);
return Result.error("生成代码失败:" + e.getMessage());
}
}
private String regenerateCode (Prompt prompt) {
List<Message> messages = Stream.concat(
prompt.getMessages().stream(),
Stream.of(new UserMessage ("以上代码存在语法错误,请修复后重新生成,只返回修复后的代码" ))
).collect(Collectors.toList());
Prompt newPrompt = new Prompt (messages);
return openAiChatClient.generate(newPrompt).getGeneration().getText();
}
}
3.1.3 效果示例 用户输入需求 :生成用户管理的 Controller+Service+Mapper,包含查询、新增、修改、删除接口。
package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> listAll () {
return userService.listAll();
}
@GetMapping("/{id}")
public User getById (@PathVariable Long id) {
return userService.getById(id);
}
@PostMapping
public boolean save (@RequestBody User user) {
return userService.save(user);
}
@PutMapping("/{id}")
public boolean update (@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.update(user);
}
@DeleteMapping("/{id}")
public boolean delete (@PathVariable Long id) {
return userService.delete(id);
}
}
3.2 代码优化:自动修复语法错误与性能问题
3.2.1 代码优化 Prompt 设计 public Prompt buildOptimizePrompt (String code, String optimizeType) {
String systemPrompt = "你是一位资深 Java 性能优化工程师,精通 Java 语法、性能调优。\n" +
"请根据指定类型优化以下代码:\n" +
"优化类型:%s\n" +
"优化规则:\n" +
"1. 修复语法错误,保证代码可编译\n" +
"2. 性能优化需给出具体的优化点(如循环优化、SQL 优化、集合使用优化)\n" +
"3. 保留原有业务逻辑,只优化语法和性能\n" +
"4. 输出优化后的代码 + 优化说明(分开展示)" ;
String formattedPrompt = String.format(systemPrompt, optimizeType);
return new Prompt (List.of(
new SystemMessage (formattedPrompt),
new UserMessage ("需要优化的代码:\n" + code)
));
}
3.2.2 代码优化接口实现 @PostMapping("/optimize")
public Result<CodeOptimizeResponse> optimizeCode (@RequestBody CodeOptimizeRequest request) {
try {
Prompt prompt = promptService.buildOptimizePrompt(request.getCode(), request.getOptimizeType());
AiResponse response = openAiChatClient.generate(prompt);
String result = response.getGeneration().getText();
CodeOptimizeResponse responseVO = parseOptimizeResult(result);
return Result.success(responseVO);
} catch (Exception e) {
log.error("优化代码失败" , e);
return Result.error("优化代码失败:" + e.getMessage());
}
}
private CodeOptimizeResponse parseOptimizeResult (String result) {
CodeOptimizeResponse response = new CodeOptimizeResponse ();
String[] parts = result.split("===优化说明===" );
if (parts.length >= 1 ) {
response.setOptimizedCode(parts[0 ].replace("===优化后代码===" , "" ).trim());
}
if (parts.length >= 2 ) {
response.setOptimizeDesc(parts[1 ].trim());
}
return response;
}
3.2.3 优化效果示例
public List<User> listUsers (List<Long> ids) {
List<User> users = new ArrayList <>();
for (Long id : ids) {
User user = userMapper.getById(id);
users.add(user);
}
return users;
}
public List<User> listUsers (List<Long> ids) {
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyList();
}
return userMapper.listByIds(ids);
}
性能问题:循环遍历 ID 列表,每次查询数据库,导致多次 IO 操作,性能低下;
优化方案:使用 MyBatis 的批量查询方法 listByIds,一次 SQL 查询获取所有数据;
额外优化:增加空值判断,避免空指针异常。
3.3 知识注入:项目上下文感知的代码补全
3.3.1 上下文感知核心逻辑 上下文感知的代码补全是核心亮点。IDEA 插件实时采集当前编辑文件的包结构、已导入的类,后端结合这些信息生成精准的补全建议:
@Service
public class CodeCompletionService {
public List<String> completeCode (CodeCompletionRequest request) {
String systemPrompt = "请根据当前 Java 文件的上下文,生成代码补全建议:\n" +
"1. 补全建议必须符合当前包结构:%s\n" +
"2. 优先使用已导入的类:%s\n" +
"3. 补全建议简洁,每条不超过 50 个字符\n" +
"4. 只返回补全建议列表,每行一个" ;
String formattedPrompt = String.format(systemPrompt,
request.getCurrentPackage(),
String.join("," , request.getImportedClasses()));
String userPrompt = "需要补全的代码片段:\n" + request.getCodeSnippet();
Prompt prompt = new Prompt (List.of(
new SystemMessage (formattedPrompt),
new UserMessage (userPrompt)
));
AiResponse response = openAiChatClient.generate(prompt);
String result = response.getGeneration().getText();
return Arrays.stream(result.split("\n" ))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
}
}
3.3.2 IDEA 插件端补全联动 在 IDEA 插件中监听编辑器的输入事件,实时调用补全接口:
public class CodeCompletionListener extends TypedActionHandlerBase {
@Override
public void execute (@NotNull Editor editor, char c, @NotNull DataContext dataContext) {
CaretModel caretModel = editor.getCaretModel();
int offset = caretModel.getOffset();
Document document = editor.getDocument();
String codeSnippet = document.getText(new TextRange (Math.max(0 , offset - 100 ), offset));
Project project = CommonDataKeys.PROJECT.getData(dataContext);
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
CodeCompletionRequest request = new CodeCompletionRequest ();
request.setCodeSnippet(codeSnippet);
if (psiFile instanceof PsiJavaFile) {
PsiJavaFile javaFile = (PsiJavaFile) psiFile;
request.setCurrentPackage(javaFile.getPackageName());
List<String> importedClasses = javaFile.getImportList().getAllImports().stream()
.map(ImportStatement::getQualifiedName)
.collect(Collectors.toList());
request.setImportedClasses(importedClasses);
}
CompletableFuture.runAsync(() -> {
List<String> completions = callCompletionApi(request);
showCompletionSuggestions(editor, completions);
});
}
}
四、实战部署:插件打包与私有仓库发布
4.1 IDEA 插件打包 在 build.gradle 中配置插件打包信息:
plugins {
id 'java'
id 'org.jetbrains.intellij' version '1.17.3'
}
intellij {
version = '2023.2'
type = 'IC'
plugins = ['java']
}
sourceCompatibility = 17
targetCompatibility = 17
tasks.buildPlugin {
archiveBaseName = 'ai-code-assistant'
archiveVersion = '1.0.0'
destinationDirectory = file("$projectDir/dist")
}
打包完成后,在 dist 目录下生成 ai-code-assistant-1.0.0.zip 插件包。
4.2 私有仓库发布
搭建私有插件仓库 :使用 Nexus 或 JetBrains Plugin Repository 搭建私有仓库;
上传插件包 :将打包后的 zip 文件上传到私有仓库;
IDEA 配置私有仓库 :
打开 IDEA → Settings → Plugins → Gear 图标 → Manage Plugin Repositories;
添加私有仓库地址(如 http://your-nexus-url/repository/idea-plugins/);
在插件市场中搜索 AI Code Assistant 即可安装。
4.3 后端服务部署 mvn clean package -DskipTests
部署到服务器 :将 target/ai-code-assistant-1.0.0.jar 上传到服务器,执行启动命令:
nohup java -jar ai-code-assistant-1.0.0.jar --spring.profiles.active=prod > app.log 2>&1 &
配置反向代理 :使用 Nginx 配置域名和 HTTPS,对外提供 API 服务。
五、实战踩坑与优化方案 问题分类 具体问题 根因 最终解决方案 IDEA 插件 插件启动时获取不到项目上下文 插件加载时机过早,项目未完全初始化 在 projectOpened 事件中初始化上下文采集逻辑 代码生成 AI 生成的代码包名错误 Prompt 中上下文拼接不完整 优化 Prompt,强制 AI 使用项目基础包名,增加校验逻辑 性能问题 代码生成响应慢(>5s) AI 调用 + 上下文解析耗时 1. 缓存项目上下文(Redis);2. 异步生成代码,返回任务 ID 轮询结果 语法校验 JavaParser 校验误判 JavaParser 版本与 IDEA SDK 不兼容 统一使用 IDEA 内置的 Java 解析器(PSI API)替代 JavaParser 插件交互 插入代码时格式错乱 换行符 / 缩进不一致 插入前格式化代码(CodeStyleManager.getInstance(project).reformat(psiElement))
六、总结与进阶规划
6.1 核心总结
架构设计 :以 Spring AI 为核心 + 工具调用层为差异化,结合 IDEA 插件实现前后端联动,解决通用 AI 代码助手的上下文脱节问题;
核心能力 :通过 Prompt 工程实现高质量代码生成,基于 JavaParser 实现语法校验,基于 IDEA PSI API 实现上下文采集;
部署落地 :完成插件打包、私有仓库发布、后端服务部署,形成完整的提效工具链;
6.2 进阶规划
私有化部署 :支持通义千问、文心一言等国产大模型私有化部署,满足企业数据安全需求;
本地知识库 :接入项目的数据库表结构、接口文档,进一步提升代码生成的精准度;
批量代码生成 :支持根据数据库表结构,一键生成整个模块的代码;
团队协作 :增加代码片段共享、团队定制 Prompt 功能;
多 IDE 适配 :支持 Eclipse、VS Code 等其他 IDE,扩大使用范围。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online