跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaAIjava

基于 Java 的 AI 图片生成网站开发实践与经验分享

使用 Java Spring Boot 快速构建 AI 图片生成网站的全过程。技术栈包括 Spring Boot 3.2、MyBatis Plus、Redis、Vue 3 及 Stable Diffusion API。核心功能涵盖用户认证、异步任务队列处理、WebSocket 实时进度推送及积分成本控制。文章详细阐述了开发中遇到的并发问题、内存溢出、API 限流及存储成本优化等挑战及其解决方案,并提供了 Docker 部署方案与性能优化建议,旨在为同类项目提供技术参考。

草莓泡芙发布于 2026/3/30更新于 2026/10/24130 浏览
基于 Java 的 AI 图片生成网站开发实践与经验分享

本文介绍了一个基于 Java 的 AI 图片生成网站的开发过程。

一、项目背景

项目初衷源于对最新模型绘画效果的认可,尝试自行实现。设计思路如下:

  • 熟悉 Java 后端技术栈
  • AI 绘画 API 已成熟
  • 市面上的工具要么太贵,要么太复杂
  • 目标是做一个简单好用的工具

二、技术选型

在这里插入图片描述

后端技术

  • Spring Boot 3.2 - 主框架,快速开发
  • MyBatis Plus - 数据库操作
  • Redis - 缓存和队列
  • MySQL 8.0 - 数据存储
  • WebSocket - 实时推送生成进度

前端技术

  • Vue 3 - 前端框架
  • Element Plus - UI 组件库
  • Axios - HTTP 请求

AI 服务

  • Stable Diffusion API - 图片生成
  • 对象存储 - 图片存储(云服务)

部署

  • Docker - 容器化部署
  • Nginx - 反向代理
  • 云服务器 - 2 核 4G 配置

三、核心功能实现

1. 用户系统

常规注册登录功能。

关键代码思路:

// 用户注册
@PostMapping("/register")
public Result register(@RequestBody UserDTO userDTO) {
    // 1. 校验邮箱格式
    // 2. 检查邮箱是否已注册
    // 3. 密码加密(BCrypt)
    // 4. 生成 token
    // 5. 返回用户信息
}

// 用户登录
@PostMapping("/login")
public Result login(@RequestBody LoginDTO loginDTO) {
    // 1. 验证邮箱密码
    // 2. 生成 JWT token
    // 3. 存入 Redis(设置过期时间)
    
}
// 4. 返回 token

注意事项:

  • 使用 JWT 替代 Session,方便扩展
  • 密码必须加密,采用 BCrypt
  • Token 过期时间设置为 7 天,平衡安全与体验

2. 图片生成核心逻辑

采用异步队列方式处理。

为什么用队列?

  • AI 生成图片需要时间(10-30 秒)
  • 避免用户长时间等待
  • 控制并发,防止 API 被打爆

实现思路:

@Service
public class ImageGenerateService {
    // 提交生成任务
    public String submitTask(GenerateRequest request) {
        // 1. 创建任务记录
        Task task = new Task();
        task.setUserId(request.getUserId());
        task.setPrompt(request.getPrompt());
        task.setStatus("pending");
        taskMapper.insert(task);

        // 2. 放入 Redis 队列
        redisTemplate.opsForList().rightPush("task:queue", task.getId());

        // 3. 返回任务 ID
        return task.getId();
    }

    // 异步处理任务
    @Async
    public void processTask() {
        while (true) {
            // 1. 从队列取任务
            String taskId = redisTemplate.opsForList().leftPop("task:queue");
            if (taskId == null) {
                Thread.sleep(1000);
                continue;
            }

            // 2. 调用 AI API 生成图片
            Task task = taskMapper.selectById(taskId);
            String imageUrl = callAIApi(task.getPrompt());

            // 3. 上传到对象存储
            String finalUrl = uploadToOSS(imageUrl);

            // 4. 更新任务状态
            task.setImageUrl(finalUrl);
            task.setStatus("completed");
            taskMapper.updateById(task);

            // 5. 通过 WebSocket 推送给用户
            webSocketService.sendToUser(task.getUserId(), task);
        }
    }
}

关键点:

  • 使用 Redis List 做队列,简单可靠
  • 异步处理,不阻塞主线程
  • WebSocket 实时推送,提升用户体验

3. WebSocket 实时推送

实现方式:

@ServerEndpoint("/ws/{userId}")
@Component
public class WebSocketServer {
    // 存储所有连接
    private static Map<String, Session> sessions = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        sessions.put(userId, session);
        System.out.println("用户连接:" + userId);
    }

    @OnClose
    public void onClose(@PathParam("userId") String userId) {
        sessions.remove(userId);
        System.out.println("用户断开:" + userId);
    }

    // 发送消息给指定用户
    public void sendToUser(String userId, Object message) {
        Session session = sessions.get(userId);
        if (session != null && session.isOpen()) {
            session.getAsyncRemote().sendText(JSON.toJSONString(message));
        }
    }
}

效果:

  • 用户提交任务后,页面显示'生成中…'
  • 生成完成后,自动刷新显示图片
  • 无需用户手动刷新

4. 积分系统

用于成本控制。

逻辑:

  • 新用户注册送 100 积分
  • 生成一张图消耗 10 积分
  • 支持充值购买积分
@Service
public class CreditService {
    // 扣除积分
    @Transactional
    public boolean deductCredit(Long userId, int amount) {
        User user = userMapper.selectById(userId);
        // 检查余额
        if (user.getCredit() < amount) {
            return false;
        }
        // 扣除积分
        user.setCredit(user.getCredit() - amount);
        userMapper.updateById(user);

        // 记录流水
        CreditLog log = new CreditLog();
        log.setUserId(userId);
        log.setAmount(-amount);
        log.setType("generate");
        creditLogMapper.insert(log);
        return true;
    }
}

注意事项:

  • 必须加事务,避免并发问题
  • 记录详细流水,方便对账
  • 可添加定时任务清理过期积分

四、常见问题与解决方案

坑 1:并发问题

问题: 多个用户同时生成图片,偶尔出现任务丢失。 原因: Redis 队列操作非原子性。 解决: 改用 Redis BLPOP 命令,阻塞式获取,保证原子性。

String taskId = redisTemplate.opsForList().leftPop("task:queue", 10, TimeUnit.SECONDS);

坑 2:内存溢出

问题: 运行几天后服务器内存爆满。 原因: WebSocket 连接未正确关闭,Session 堆积。 解决:

  • 增加心跳检测,定时清理无效连接
  • 设置连接超时时间
  • 限制单个用户最大连接数
@Scheduled(fixedRate = 60000)
public void cleanInvalidSessions() {
    sessions.forEach((userId, session) -> {
        if (!session.isOpen()) {
            sessions.remove(userId);
        }
    });
}

坑 3:AI API 限流

问题: 调用 AI API 过于频繁被限流。 解决:

  • 增加令牌桶限流
  • 控制每秒最多调用 5 次
  • 超过限制的任务延迟处理
@Component
public class RateLimiter {
    private final Semaphore semaphore = new Semaphore(5);

    public boolean tryAcquire() {
        return semaphore.tryAcquire();
    }

    public void release() {
        semaphore.release();
    }
}

坑 4:图片存储成本

问题: 用户生成的图片增多,存储费用上涨。 解决:

  • 定期清理 30 天前的图片
  • 压缩图片质量(从原图 2MB 压到 500KB)
  • 提供本地下载选项

五、性能优化

1. 数据库优化

加索引:

-- 用户表
CREATE INDEX idx_email ON user(email);
-- 任务表
CREATE INDEX idx_user_status ON task(user_id, status);
CREATE INDEX idx_create_time ON task(create_time);

分页查询:

Page<Task> page = new Page<>(pageNum, pageSize);
taskMapper.selectPage(page, new QueryWrapper<Task>()
    .eq("user_id", userId)
    .orderByDesc("create_time"));

2. Redis 缓存

缓存用户信息:

String userJson = redisTemplate.opsForValue().get("user:" + userId);
if (userJson != null) {
    return JSON.parseObject(userJson, User.class);
}
User user = userMapper.selectById(userId);
redisTemplate.opsForValue().set("user:" + userId, JSON.toJSONString(user), 1, TimeUnit.HOURS);

3. 接口优化

批量查询:

// 不好的做法:循环查询
for (Task task : tasks) {
    User user = userMapper.selectById(task.getUserId());
    task.setUser(user);
}

// 好的做法:批量查询
List<Long> userIds = tasks.stream()
    .map(Task::getUserId)
    .collect(Collectors.toList());
List<User> users = userMapper.selectBatchIds(userIds);
Map<Long, User> userMap = users.stream()
    .collect(Collectors.toMap(User::getId, u -> u));
tasks.forEach(task -> task.setUser(userMap.get(task.getUserId())));

六、部署上线

Docker 部署

Dockerfile:

FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

docker-compose.yml:

version: '3'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    depends_on:
      - mysql
      - redis
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: your_password
      MYSQL_DATABASE: image_gen
    volumes:
      - mysql-data:/var/lib/mysql
  redis:
    image: redis:7
    volumes:
      - redis-data:/data
volumes:
  mysql-data:
  redis-data:

一键部署:

docker-compose up -d

七、总结

技术方面

  1. 选熟悉的技术栈:快速上线比技术炫酷更重要。
  2. 异步处理很重要:耗时操作务必异步,队列配合 WebSocket 提升体验。
  3. 做好监控和日志:ELK 收集日志,关键指标监控,便于定位问题。

产品方面

  1. 功能要简单:先验证核心需求,再考虑扩展。
  2. 用户体验第一:实时反馈、加载动画、友好提示。
  3. 控制成本:AI API 昂贵,需通过积分系统和数据清理控制成本。

目录

  1. 一、项目背景
  2. 二、技术选型
  3. 后端技术
  4. 前端技术
  5. AI 服务
  6. 部署
  7. 三、核心功能实现
  8. 1. 用户系统
  9. 2. 图片生成核心逻辑
  10. 3. WebSocket 实时推送
  11. 4. 积分系统
  12. 四、常见问题与解决方案
  13. 坑 1:并发问题
  14. 坑 2:内存溢出
  15. 坑 3:AI API 限流
  16. 坑 4:图片存储成本
  17. 五、性能优化
  18. 1. 数据库优化
  19. 2. Redis 缓存
  20. 3. 接口优化
  21. 六、部署上线
  22. Docker 部署
  23. 七、总结
  24. 技术方面
  25. 产品方面

更多推荐文章

查看全部
  • Waifu Diffusion v1.4 配置与使用指南
  • Whisper-large-v3-turbo 深度解析:8 倍速语音识别技术
  • 鸿蒙金融理财全栈项目:架构设计、数据安全与体验优化
  • 灵感画廊:Stable Diffusion 艺术创作指南
  • 基于 OpenClaw 与飞书集成实现 AI 新闻推送机器人
  • 前端开发:Jenkins 与 Gitee 集成实现持续集成与部署
  • CATIA V5 Python 自动化:pycatia 模块使用指南
  • 基于 Web 的学校田径运动会管理系统开题答辩问答实录
  • C++ 手写 JSON 与 HTTP 协议实现 Web 计算器服务器
  • Clawdbot 部署指南:反向代理与 WebAuth 配置
  • 基于火山引擎即梦 API 的数字人视频生成 Streamlit Demo
  • OpenClaw + cpolar 实现本地 AI 公网访问教程
  • ReAct Agent 与 Agent 编排:从单 Agent 闭环到多 Agent 协作
  • 大模型时代下的私有数据安全与利用
  • TikTok 用户涌入背景下,小红书是否应布局大模型技术
  • Android 开发者如何突破困境:深耕 Framework 实现职业进阶
  • B 站直播间自动化搭建:弹幕机器人功能配置指南
  • Linux 网络基础:协议分层与传输流程
  • Zep Cloud 长期记忆功能集成实战指南
  • Flutter 组件 google_generative_language_api 适配鸿蒙 HarmonyOS 实战
  • 相关免费在线工具

    • 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