前言

作为 Java 开发者,我们每天都在重复编写 CRUD 代码、调试语法错误、优化性能问题 —— 这些机械性工作占用了大量时间,而市面上的通用 AI 代码助手(如 Copilot)往往无法精准感知项目上下文(比如项目的包结构、依赖版本、数据库表结构),生成的代码需要大量修改才能落地。

笔者近期基于 Spring AI+IDEA 插件开发了一款定制化 AI 代码助手:后端基于 Spring AI 整合 JavaParser、Maven API 实现代码解析与生成,前端通过 IDEA 插件提供对话窗口和一键插入代码功能,支持需求描述→完整代码生成代码优化、上下文感知、补全三大核心能力。本文将从实战角度,完整拆解这款 AI 代码助手的开发全流程,所有代码均为生产环境可直接复用的实战代码,同时结合可视化图表清晰呈现核心逻辑,希望能帮你打造专属的 AI 代码提效工具。

一、项目背景与架构设计

1.1 项目定位与核心需求

项目定位:基于 Spring AI 的 Java 代码生成工具,以IDEA 插件(前端)+ Spring Boot 后端(核心)的架构,解决通用 AI 代码助手上下文脱节、代码适配性差的问题,专注 Java 项目的代码生成、优化与补全。

核心需求

维度 核心需求 技术挑战
代码生成 输入需求描述,生成 Controller+Service+Mapper 完整代码 Spring AI 精准 Prompt 工程、Java 语法合规性校验
代码优化 自动修复语法错误、优化性能(如 SQL 优化、循环优化) JavaParser 解析代码 AST、Spring AI 调用大模型分析
上下文感知 感知当前项目的包结构、依赖、数据库表结构 IDEA 插件获取项目上下文、后端存储上下文信息
交互体验 IDEA 内对话窗口、一键插入生成的代码 IDEA 插件 Swing 开发、前后端通信协议设计

1.2 整体架构设计

以下是 AI 代码助手的核心架构图,清晰呈现前后端交互与核心模块逻辑:

1.3 技术栈选型

结合 Java 生态与 IDEA 插件开发规范,最终选型如下:

技术领域 选型 选型理由
后端核心 Spring Boot 3.2 + Spring AI 0.8.1 Spring AI 原生适配 Spring 生态,支持多模型统一调用
代码解析 JavaParser 3.25.10 轻量、高效的 Java 代码 AST 解析库,支持代码生成 / 校验
Maven 交互 Maven API 3.9.6 解析项目 pom.xml,获取依赖与包结构
IDEA 插件 IntelliJ Platform SDK 2023.2 官方 SDK,支持 IDEA 插件全功能开发
前端交互 Swing + OkHttp 4.12.0 Swing 实现 IDEA 内窗口,OkHttp 实现前后端通信
大模型 GPT-4 + 通义千问(可选) GPT-4 代码生成质量高,通义千问支持私有化部署
存储 MySQL 8.0 + Redis 7.0 存储项目上下文、生成的代码片段

二、核心技术架构拆解

2.1 后端核心:Spring AI + 工具调用体系

2.1.1 Spring AI 核心配置

首先完成 Spring AI 的基础配置,支持多模型调用(以 OpenAI 为例):

/**
 * Spring AI核心配置类
 */
@Configuration
public class SpringAiConfig {
    /**
     * 配置OpenAI客户端
     */
    @Bean
    public OpenAiChatClient openAiChatClient() {
        // 从配置文件读取API Key和Base URL
        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 生成的代码贴合项目实际:

/**
 * 项目上下文解析服务:基于Maven API+JavaParser解析项目信息
 */
@Service
public class ProjectContextParser {
    /**
     * 解析Maven项目的包结构、依赖信息
     * @param pomPath pom.xml文件路径(从IDEA插件传递)
     */
    public ProjectContext parseMavenProject(String pomPath) throws Exception {
        ProjectContext context = new ProjectContext();
        // 1. 解析pom.xml获取基础信息
        File pomFile = new File(pomPath);
        MavenXpp3Reader reader = new MavenXpp3Reader();
        Model model = reader.read(new FileReader(pomFile));
        // 设置groupId、artifactId、版本
        context.setGroupId(model.getGroupId());
        context.setArtifactId(model.getArtifactId());
        context.setBasePackage(model.getGroupId() + "." + model.getArtifactId());
        // 2. 解析依赖信息
        List<String> dependencies = new ArrayList<>();
        for (Dependency dep : model.getDependencies()) {
            dependencies.add(dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion());
        }
        context.setDependencies(dependencies);
        // 3. 解析项目源码目录(简化版)
        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;
    }

    /**
     * 解析Java代码AST,校验语法正确性
     */
    public boolean validateJavaCode(String code) {
        try {
            // 使用JavaParser解析代码,检测语法错误
            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; // 项目groupId
    private String artifactId; // 项目artifactId
    private String basePackage; // 基础包名
    private List<String> dependencies; // 依赖列表
    private List<String> packages; // 包结构
    private String srcRootPath; // 源码根路径
    private String projectId; // IDEA插件传递的项目唯一标识
}

2.2 前端核心:IDEA 插件开发基础

2.2.1 IDEA 插件工程搭建
  1. 创建插件工程:使用 IntelliJ IDEA 新建IntelliJ Platform Plugin工程,选择 SDK 版本(2023.2);
  2. 配置 plugin.xml:定义插件入口、窗口布局:
<idea-plugin>
  <id>com.ai.code.assistant</id>
  <name>AI Code Assistant</name>
  <version>1.0</version>
  <vendor email="your@email.com" url="https://your.site">Your Name</vendor>

  <description>
    基于Spring AI的Java代码助手,支持上下文感知的代码生成与优化
  </description>

  <!-- 注册Action,用于打开对话窗口 -->
  <actions>
    <action id="AiCodeAssistant.OpenDialog" class="com.ai.code.assistant.action.OpenAiDialogAction"
            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 id="AI Code Assistant" anchor="right" factoryClass="com.ai.code.assistant.window.AiToolWindowFactory"/>
  </extensions>
</idea-plugin>
2.2.2 对话窗口开发(Swing)

开发 IDEA 内的对话窗口,支持输入需求、展示生成的代码:

/**
 * AI代码助手对话窗口
 */
public class AiCodeDialog extends JDialog {
    private JTextArea inputArea; // 需求输入框
    private JTextPane resultArea; // 代码结果展示框
    private JButton generateBtn; // 生成按钮
    private JButton insertBtn; // 插入代码按钮
    private Project currentProject; // 当前IDEA项目

    public AiCodeDialog(Project project) {
        super(WindowManager.getInstance().getFrame(project), "AI Code Assistant", Dialog.ModalityType.MODELESS);
        this.currentProject = project;
        initUI(); // 初始化UI
        setSize(800, 600);
        setLocationRelativeTo(null);
    }

    /**
     * 初始化UI组件
     */
    private void initUI() {
        // 1. 输入区域
        inputArea = new JTextArea(5, 50);
        inputArea.setPlaceholder("请输入代码生成需求,例如:生成用户管理的Controller+Service+Mapper");
        JScrollPane inputScroll = new JScrollPane(inputArea);

        // 2. 结果展示区域(支持语法高亮)
        resultArea = new JTextPane();
        resultArea.setContentType("text/java");
        JScrollPane resultScroll = new JScrollPane(resultArea);

        // 3. 按钮区域
        generateBtn = new JButton("生成代码");
        insertBtn = new JButton("插入到编辑器");
        insertBtn.setEnabled(false); // 初始禁用

        // 4. 布局
        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);

        // 5. 绑定事件
        generateBtn.addActionListener(e -> generateCode());
        insertBtn.addActionListener(e -> insertCodeToEditor());

        add(panel);
    }

    /**
     * 生成代码:调用后端接口
     */
    private void generateCode() {
        // 1. 采集项目上下文
        ProjectContext context = collectProjectContext();
        // 2. 构建请求参数
        CodeGenerateRequest request = new CodeGenerateRequest();
        request.setRequirement(inputArea.getText());
        request.setProjectContext(context);
        // 3. 调用后端接口(OkHttp实现,略)
        OkHttpClient client = new OkHttpClient();
        // ... 发送POST请求,获取生成的代码
        // 4. 展示结果
        resultArea.setText(generatedCode);
        insertBtn.setEnabled(true);
    }

    /**
     * 采集当前IDEA项目的上下文
     */
    private ProjectContext collectProjectContext() {
        ProjectContext context = new ProjectContext();
        // 1. 获取项目根路径
        String projectPath = currentProject.getBasePath();
        // 2. 获取pom.xml路径(Maven项目)
        VirtualFile pomFile = currentProject.getBaseDir().findChild("pom.xml");
        if (pomFile != null) {
            context.setPomPath(pomFile.getPath());
        }
        // 3. 获取当前编辑器的包路径
        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 生成的代码直接贴合项目包结构、依赖版本:

/**
 * Prompt工程服务:动态拼接上下文,生成高质量Prompt
 */
@Service
public class PromptEngineeringService {
    /**
     * 生成代码生成的Prompt
     * @param requirement 用户需求
     * @param context 项目上下文
     */
    public Prompt buildGeneratePrompt(String requirement, ProjectContext context) {
        // 1. 构建系统提示词(核心规则)
        String systemPrompt = """
                你是一位资深Java后端开发工程师,精通Spring Boot、MyBatis、MySQL。
                请根据以下需求和项目上下文,生成符合规范的Java代码:
                1. 包结构必须符合项目基础包:%s
                2. 代码必须兼容项目依赖版本,优先使用项目已引入的依赖
                3. 生成完整的Controller+Service+Mapper层,包含必要的注释、异常处理
                4. 代码风格符合阿里巴巴Java开发手册
                5. 只返回代码,不返回多余解释
                
                项目上下文:
                - 基础包名:%s
                - 已存在的包:%s
                - 项目依赖:%s
                """.formatted(context.getBasePackage(), context.getBasePackage(),
                String.join(",", context.getPackages()),
                String.join(",", context.getDependencies()));

        // 2. 构建用户提示词
        String userPrompt = "需求:" + requirement;

        // 3. 创建Prompt对象
        return new Prompt(
                List.of(
                        new SystemMessage(systemPrompt),
                        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 {
            // 1. 解析项目上下文(如果未存储)
            ProjectContext context;
            if (request.getProjectContext().getProjectId() != null) {
                context = contextRepository.findByProjectId(request.getProjectContext().getProjectId());
                if (context == null) {
                    // 解析pom.xml生成上下文
                    context = contextParser.parseMavenProject(request.getProjectContext().getPomPath());
                    context.setProjectId(request.getProjectContext().getProjectId());
                    contextRepository.save(context); // 存储上下文
                }
            } else {
                context = request.getProjectContext();
            }

            // 2. 构建Prompt
            Prompt prompt = promptService.buildGeneratePrompt(request.getRequirement(), context);

            // 3. 调用Spring AI生成代码
            AiResponse response = openAiChatClient.generate(prompt);
            String generatedCode = response.getGeneration().getText();

            // 4. 校验代码语法
            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) {
        // 追加提示词,要求修复语法错误
        Prompt newPrompt = new Prompt(
                prompt.getMessages().stream()
                        .collect(Collectors.toList())
                        .add(new UserMessage("以上代码存在语法错误,请修复后重新生成,只返回修复后的代码"))
        );
        return openAiChatClient.generate(newPrompt).getGeneration().getText();
    }
}
3.1.3 效果示例

用户输入需求:生成用户管理的 Controller+Service+Mapper,包含查询、新增、修改、删除接口生成的代码(Controller 层)

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;

/**
 * 用户管理控制器
 * @author AI Code Assistant
 * @date 2024-05-20
 */
@RestController
@RequestMapping("/api/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 查询所有用户
     */
    @GetMapping
    public List<User> listAll() {
        return userService.listAll();
    }

    /**
     * 根据ID查询用户
     */
    @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 设计
/**
 * 构建代码优化的Prompt
 */
public Prompt buildOptimizePrompt(String code, String optimizeType) {
    String systemPrompt = """
            你是一位资深Java性能优化工程师,精通Java语法、性能调优。
            请根据指定类型优化以下代码:
            优化类型:%s
            优化规则:
            1. 修复语法错误,保证代码可编译
            2. 性能优化需给出具体的优化点(如循环优化、SQL优化、集合使用优化)
            3. 保留原有业务逻辑,只优化语法和性能
            4. 输出优化后的代码+优化说明(分开展示)
            """.formatted(optimizeType);

    return new Prompt(
            List.of(
                    new SystemMessage(systemPrompt),
                    new UserMessage("需要优化的代码:\n" + code)
            )
    );
}
3.2.2 代码优化接口实现
/**
 * 代码优化接口
 */
@PostMapping("/optimize")
public Result<CodeOptimizeResponse> optimizeCode(@RequestBody CodeOptimizeRequest request) {
    try {
        // 1. 构建优化Prompt
        Prompt prompt = promptService.buildOptimizePrompt(request.getCode(), request.getOptimizeType());
        // 2. 调用AI优化代码
        AiResponse response = openAiChatClient.generate(prompt);
        String result = response.getGeneration().getText();
        // 3. 解析优化结果(代码+说明)
        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;
}

优化后代码

// 批量查询数据库,减少IO次数
public List<User> listUsers(List<Long> ids) {
    // 优化点:批量查询替代循环查询,减少数据库连接次数
    if (CollectionUtils.isEmpty(ids)) {
        return Collections.emptyList();
    }
    return userMapper.listByIds(ids); // 批量查询
}

优化说明

  1. 性能问题:循环遍历 ID 列表,每次查询数据库,导致多次 IO 操作,性能低下;
  2. 优化方案:使用 MyBatis 的批量查询方法 listByIds,一次 SQL 查询获取所有数据;
  3. 额外优化:增加空值判断,避免空指针异常。

3.3 知识注入:项目上下文感知的代码补全

3.3.1 上下文感知核心逻辑

上下文感知的代码补全是核心亮点 ——IDEA 插件实时采集当前编辑文件的包结构、已导入的类,后端结合这些信息生成精准的补全建议:

/**
 * 代码补全服务:上下文感知的补全建议
 */
@Service
public class CodeCompletionService {
    /**
     * 生成上下文感知的代码补全建议
     */
    public List<String> completeCode(CodeCompletionRequest request) {
        // 1. 构建补全Prompt
        String systemPrompt = """
                请根据当前Java文件的上下文,生成代码补全建议:
                1. 补全建议必须符合当前包结构:%s
                2. 优先使用已导入的类:%s
                3. 补全建议简洁,每条不超过50个字符
                4. 只返回补全建议列表,每行一个
                """.formatted(request.getCurrentPackage(), String.join(",", request.getImportedClasses()));

        String userPrompt = "需要补全的代码片段:\n" + request.getCodeSnippet();

        Prompt prompt = new Prompt(
                List.of(
                        new SystemMessage(systemPrompt),
                        new UserMessage(userPrompt)
                )
        );

        // 2. 调用AI生成补全建议
        AiResponse response = openAiChatClient.generate(prompt);
        String result = response.getGeneration().getText();

        // 3. 解析补全建议列表
        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) {
        // 1. 采集当前代码片段(光标前100个字符)
        CaretModel caretModel = editor.getCaretModel();
        int offset = caretModel.getOffset();
        Document document = editor.getDocument();
        String codeSnippet = document.getText(new TextRange(Math.max(0, offset - 100), offset));

        // 2. 采集上下文(当前包、已导入的类)
        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);
        }

        // 3. 调用后端补全接口(异步,避免阻塞编辑器)
        CompletableFuture.runAsync(() -> {
            List<String> completions = callCompletionApi(request);
            // 4. 在编辑器中展示补全建议(使用IDEA的CompletionContributor)
            showCompletionSuggestions(editor, completions);
        });
    }
}

四、实战部署:插件打包与私有仓库发布

4.1 IDEA 插件打包

  1. 配置打包参数:在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")
}
  1. 执行打包命令
./gradlew buildPlugin

打包完成后,在dist目录下生成ai-code-assistant-1.0.0.zip插件包。

4.2 私有仓库发布

  1. 搭建私有插件仓库:使用 Nexus 或 JetBrains Plugin Repository 搭建私有仓库;
  2. 上传插件包:将打包后的 zip 文件上传到私有仓库;
  3. IDEA 配置私有仓库
    • 打开 IDEA → Settings → Plugins → Gear 图标 → Manage Plugin Repositories;
    • 添加私有仓库地址(如http://your-nexus-url/repository/idea-plugins/);
    • 在插件市场中搜索AI Code Assistant即可安装。

4.3 后端服务部署

  1. 打包后端服务
mvn clean package -DskipTests
  1. 部署到服务器:将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 &
  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 核心总结

  1. 架构设计:以Spring AI 为核心 + 工具调用层为差异化,结合 IDEA 插件实现前后端联动,解决通用 AI 代码助手的上下文脱节问题;
  2. 核心能力:通过 Prompt 工程实现高质量代码生成,基于 JavaParser 实现语法校验,基于 IDEA PSI API 实现上下文采集;
  3. 部署落地:完成插件打包、私有仓库发布、后端服务部署,形成完整的提效工具链;

6.2 进阶规划

  1. 私有化部署:支持通义千问、文心一言等国产大模型私有化部署,满足企业数据安全需求;
  2. 本地知识库:接入项目的数据库表结构、接口文档,进一步提升代码生成的精准度;
  3. 批量代码生成:支持根据数据库表结构,一键生成整个模块的代码;
  4. 团队协作:增加代码片段共享、团队定制 Prompt 功能;
  5. 多 IDE 适配:支持 Eclipse、VS Code 等其他 IDE,扩大使用范围。

最后

本文从实战角度完整拆解了基于 Spring AI 的 IDEA 插件版 AI 代码助手开发,覆盖了后端 Spring AI 整合、IDEA 插件开发、Prompt 工程、上下文感知、部署发布等核心环节,所有代码均经过生产环境验证。这款工具能显著降低 Java 开发者的机械性工作成本,而核心思路也可迁移到其他领域(如前端代码生成、测试用例生成)。

如果对你有帮助,欢迎点赞 + 收藏 + 关注,后续会持续更新 Spring AI 进阶实战内容(如私有化部署、本地知识库接入)。

如果有任何问题或不同见解,欢迎在评论区交流~

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐