当前位置: 首页 > news >正文

AI 项目详细开发步骤指南

AI 项目详细开发步骤指南

一、环境搭建详解

1. JDK 17 安装与配置

Windows 系统安装步骤:
  1. 访问 Oracle 官网下载 JDK 17 安装包:https://www.oracle.com/java/technologies/downloads/#java17
  2. 下载 Windows x64 Installer 版本
  3. 双击安装包,按照向导完成安装
  4. 配置环境变量:
    • 右键"此电脑" -> 属性 -> 高级系统设置 -> 环境变量
    • 在系统变量中新建 JAVA_HOME,值为 JDK 安装路径(如 C:\Program Files\Java\jdk-17
    • 编辑系统变量 Path,添加 %JAVA_HOME%\bin
  5. 验证安装:
    java -version
    javac -version
    
Linux 系统安装步骤:
  1. 使用包管理器安装:
    # Ubuntu/Debian
    sudo apt update
    sudo apt install openjdk-17-jdk# CentOS/RHEL
    sudo yum install java-17-openjdk-devel
    
  2. 验证安装:
    java -version
    javac -version
    

2. Maven 安装与配置

Windows 系统安装步骤:
  1. 访问 Maven 官网下载二进制包:https://maven.apache.org/download.cgi
  2. 下载 apache-maven-3.9.6-bin.zip
  3. 解压到指定目录(如 C:\Program Files\Apache\maven
  4. 配置环境变量:
    • 新建系统变量 MAVEN_HOME,值为 Maven 解压路径
    • 编辑系统变量 Path,添加 %MAVEN_HOME%\bin
  5. 验证安装:
    mvn -v
    
Linux 系统安装步骤:
  1. 下载 Maven 二进制包:
    wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
    
  2. 解压到指定目录:
    sudo tar -xzf apache-maven-3.9.6-bin.tar.gz -C /opt
    
  3. 创建软链接:
    sudo ln -s /opt/apache-maven-3.9.6 /opt/maven
    
  4. 配置环境变量,编辑 ~/.bashrc~/.zshrc
    export MAVEN_HOME=/opt/maven
    export PATH=$PATH:$MAVEN_HOME/bin
    
  5. 使环境变量生效:
    source ~/.bashrc  # 或 source ~/.zshrc
    
  6. 验证安装:
    mvn -v
    

3. MySQL 安装与配置

Windows 系统安装步骤:
  1. 访问 MySQL 官网下载安装包:https://dev.mysql.com/downloads/installer/
  2. 下载 MySQL Installer
  3. 运行安装程序,选择"Server only"或"Custom"安装类型
  4. 按照向导完成安装,设置 root 密码
  5. 将 MySQL 的 bin 目录添加到系统环境变量 Path 中
  6. 验证安装:
    mysql --version
    mysql -u root -p
    
Linux 系统安装步骤:
  1. 使用包管理器安装:
    # Ubuntu/Debian
    sudo apt update
    sudo apt install mysql-server# CentOS/RHEL
    sudo yum install mysql-server
    
  2. 启动 MySQL 服务:
    # Ubuntu/Debian
    sudo systemctl start mysql
    sudo systemctl enable mysql# CentOS/RHEL
    sudo systemctl start mysqld
    sudo systemctl enable mysqld
    
  3. 设置 root 密码:
    sudo mysql_secure_installation
    
  4. 验证安装:
    mysql --version
    mysql -u root -p
    
创建项目数据库:
  1. 登录 MySQL:
    mysql -u root -p
    
  2. 创建数据库:
    CREATE DATABASE mt_ai CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    
  3. 创建项目用户并授权:
    CREATE USER 'mt_ai_user'@'localhost' IDENTIFIED BY 'your_password';
    GRANT ALL PRIVILEGES ON mt_ai.* TO 'mt_ai_user'@'localhost';
    FLUSH PRIVILEGES;
    

4. IDE 安装与配置

IntelliJ IDEA 安装步骤:
  1. 访问 JetBrains 官网下载 IDEA:https://www.jetbrains.com/idea/download/
  2. 下载 Community 或 Ultimate 版本
  3. 运行安装程序,按照向导完成安装
  4. 首次启动配置:
    • 选择 UI 主题
    • 安装必要插件:
      • Lombok
      • Spring Boot
      • MyBatisX
      • Maven Helper
      • Git Integration
配置 JDK:
  1. 打开 IDEA -> File -> Project Structure
  2. 在 Project 选项卡中设置 Project SDK 为 JDK 17
  3. 在 Modules 选项卡中确保 Language Level 为 17
配置 Maven:
  1. 打开 IDEA -> File -> Settings -> Build, Execution, Deployment -> Build Tools -> Maven
  2. 设置 Maven home directory 为 Maven 安装路径
  3. 设置 User settings file 为 Maven 的 settings.xml 路径
  4. 设置 Local repository 为 Maven 本地仓库路径

二、项目初始化详解

1. 创建 Spring Boot 项目

方法一:使用 Spring Initializr 网站
  1. 访问 https://start.spring.io/
  2. 填写项目信息:
    • Project: Maven
    • Language: Java
    • Spring Boot: 3.4.3
    • Project Metadata:
      • Group: com.maoteng
      • Artifact: maoteng-ai
      • Name: maoteng-ai
      • Description: MT-AI Project
      • Package name: com.maoteng.ai
      • Packaging: Jar
      • Java: 17
  3. 添加依赖:
    • Spring Web
    • Spring Data JPA
    • MySQL Driver
    • Lombok
    • Spring AI
  4. 点击"GENERATE"下载项目压缩包
  5. 解压到工作目录
方法二:使用 IDEA 创建
  1. 打开 IDEA -> File -> New -> Project
  2. 选择 Spring Initializr
  3. 填写项目信息(同上)
  4. 选择依赖(同上)
  5. 点击"Finish"完成创建

2. 配置 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.maoteng</groupId><artifactId>maoteng-ai</artifactId><version>0.0.1-SNAPSHOT</version><name>maoteng-ai</name><description>MT-AI Project</description><properties><java.version>17</java.version><spring-ai.version>1.0.0-M6</spring-ai.version><mybatis-plus.version>3.5.10.1</mybatis-plus.version><lombok.version>1.18.22</lombok.version></properties><dependencies><!-- Spring Boot Starters --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!-- Spring AI --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-ollama-spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-pdf-document-reader</artifactId></dependency><!-- Database --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!-- Tools --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><optional>true</optional></dependency><!-- Test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
</project>

3. 创建基础配置文件

application.yml
server:port: 8080servlet:context-path: /apispring:application:name: mt-ai# 数据库配置datasource:url: jdbc:mysql://localhost:3306/mt_ai?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: mt_ai_userpassword: your_passworddriver-class-name: com.mysql.cj.jdbc.Driverhikari:minimum-idle: 5maximum-pool-size: 15idle-timeout: 30000pool-name: HikariCPmax-lifetime: 1800000connection-timeout: 30000# JPA配置jpa:database-platform: org.hibernate.dialect.MySQL8Dialectshow-sql: truehibernate:ddl-auto: updateproperties:hibernate:format_sql: true# AI配置ai:openai:api-key: your-openai-api-keymodel: gpt-3.5-turbotemperature: 0.7max-tokens: 2000ollama:base-url: http://localhost:11434model: llama2# MyBatis-Plus配置
mybatis-plus:mapper-locations: classpath*:/mapper/**/*.xmltype-aliases-package: com.maoteng.ai.entityconfiguration:map-underscore-to-camel-case: truecache-enabled: falseglobal-config:db-config:id-type: autologic-delete-field: deletedlogic-delete-value: 1logic-not-delete-value: 0# 日志配置
logging:level:root: INFOcom.maoteng.ai: DEBUGorg.springframework.web: INFOorg.hibernate: INFOfile:name: logs/mt-ai.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"# 监控配置
management:endpoints:web:exposure:include: health,info,metricsendpoint:health:show-details: always
application-dev.yml
spring:datasource:url: jdbc:mysql://localhost:3306/mt_ai_dev?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: mt_ai_userpassword: dev_passwordjpa:show-sql: truehibernate:ddl-auto: updatelogging:level:com.maoteng.ai: DEBUG
application-prod.yml
spring:datasource:url: jdbc:mysql://prod-db-server:3306/mt_ai_prod?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: ${DB_USERNAME}password: ${DB_PASSWORD}jpa:show-sql: falsehibernate:ddl-auto: nonelogging:level:com.maoteng.ai: INFO

4. 创建主应用类

package com.maoteng.ai;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;@SpringBootApplication
@ComponentScan(basePackages = "com.maoteng.ai")
public class MtAiApplication {public static void main(String[] args) {SpringApplication.run(MtAiApplication.class, args);}
}

5. 验证项目初始化

  1. 在 IDEA 中打开项目
  2. 等待 Maven 下载依赖
  3. 运行主应用类 MtAiApplication
  4. 查看控制台输出,确认应用启动成功
  5. 访问 http://localhost:8080/api/actuator/health 检查健康状态

三、项目结构搭建详解

1. 创建基础包结构

src/main/java/com/maoteng/ai 目录下创建以下包结构:

src/main/java/com/maoteng/ai/
├── config/         # 配置类
├── constants/      # 常量定义
├── controller/     # 控制器
├── entity/         # 实体类
├── mapper/         # MyBatis映射接口
├── model/          # 数据模型(DTO、VO等)
├── repository/     # 数据访问层
├── service/        # 业务逻辑层
│   └── impl/       # 服务实现类
├── tools/          # 工具类
└── utils/          # 工具类

2. 创建基础配置类

2.1 数据库配置
package com.maoteng.ai.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}
2.2 Web配置
package com.maoteng.ai.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").allowCredentials(true).maxAge(3600);}
}
2.3 AI配置
package com.maoteng.ai.config;import org.springframework.ai.openai.OpenAiApi;
import org.springframework.ai.openai.client.OpenAiClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;@Configuration
public class OpenAiConfig {@Beanpublic OpenAiClient openAiClient() {return OpenAiClient.builder().apiKey(System.getenv("OPENAI_API_KEY")).build();}
}
package com.maoteng.ai.config;import org.springframework.ai.ollama.OllamaApi;
import org.springframework.ai.ollama.client.OllamaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;@Configuration
public class OllamaConfig {@Beanpublic OllamaClient ollamaClient() {return OllamaClient.builder().baseUrl("http://localhost:11434").build();}
}

3. 创建常量类

package com.maoteng.ai.constants;public class CommonConstants {// 系统常量public static final String SYSTEM_NAME = "MT-AI";public static final String VERSION = "1.0.0";// 状态常量public static final int STATUS_NORMAL = 0;public static final int STATUS_DISABLED = 1;// 分页常量public static final int DEFAULT_PAGE_SIZE = 10;public static final int DEFAULT_PAGE_NUM = 1;// 时间格式public static final String DATE_FORMAT = "yyyy-MM-dd";public static final String TIME_FORMAT = "HH:mm:ss";public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
}
package com.maoteng.ai.constants;public class ResponseConstants {// 响应状态码public static final int SUCCESS = 200;public static final int ERROR = 500;public static final int UNAUTHORIZED = 401;public static final int FORBIDDEN = 403;public static final int NOT_FOUND = 404;// 响应消息public static final String SUCCESS_MSG = "操作成功";public static final String ERROR_MSG = "操作失败";public static final String UNAUTHORIZED_MSG = "未授权";public static final String FORBIDDEN_MSG = "禁止访问";public static final String NOT_FOUND_MSG = "资源不存在";
}

四、核心功能开发详解

1. 实体类开发

1.1 基础实体类
package com.maoteng.ai.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;import jakarta.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;@Data
@Entity
@TableName("base_entity")
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity implements Serializable {private static final long serialVersionUID = 1L;@Id@TableId(type = IdType.AUTO)@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@CreatedDate@Column(nullable = false, updatable = false)private LocalDateTime createTime;@LastModifiedDate@Column(nullable = false)private LocalDateTime updateTime;@TableLogic@Column(nullable = false)private Integer deleted = 0;
}
1.2 用户实体类
package com.maoteng.ai.entity;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;@Data
@Entity
@Table(name = "user")
@TableName("user")
@EqualsAndHashCode(callSuper = true)
public class User extends BaseEntity {@Column(nullable = false, unique = true, length = 50)private String username;@Column(nullable = false, length = 100)private String password;@Column(length = 50)private String nickname;@Column(length = 100)private String email;@Column(length = 20)private String phone;@Column(nullable = false)private Integer status = 0;@Column(length = 500)private String avatar;
}
1.3 聊天记录实体类
package com.maoteng.ai.entity;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;@Data
@Entity
@Table(name = "chat_history")
@TableName("chat_history")
@EqualsAndHashCode(callSuper = true)
public class ChatHistory extends BaseEntity {@Column(nullable = false)private Long userId;@Column(nullable = false, length = 50)private String modelType; // openai, ollama@Column(nullable = false, length = 50)private String modelName; // gpt-3.5-turbo, llama2@Column(nullable = false, columnDefinition = "TEXT")private String userMessage;@Column(nullable = false, columnDefinition = "TEXT")private String aiResponse;@Columnprivate Integer tokens;@Columnprivate Long duration; // 响应时间(毫秒)
}

2. 数据访问层开发

2.1 用户Mapper
package com.maoteng.ai.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.maoteng.ai.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper
public interface UserMapper extends BaseMapper<User> {@Select("SELECT * FROM user WHERE username = #{username} AND deleted = 0")User findByUsername(String username);
}
2.2 聊天记录Mapper
package com.maoteng.ai.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.maoteng.ai.entity.ChatHistory;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface ChatHistoryMapper extends BaseMapper<ChatHistory> {@Select("SELECT * FROM chat_history WHERE user_id = #{userId} AND deleted = 0 ORDER BY create_time DESC LIMIT #{limit}")List<ChatHistory> findRecentByUserId(Long userId, int limit);
}

3. 服务层开发

3.1 基础服务接口
package com.maoteng.ai.service;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.maoteng.ai.entity.BaseEntity;import java.util.List;public interface BaseService<T extends BaseEntity> extends IService<T> {/*** 分页查询*/IPage<T> page(Page<T> page);/*** 查询所有*/List<T> list();/*** 根据ID查询*/T getById(Long id);/*** 保存*/boolean save(T entity);/*** 更新*/boolean updateById(T entity);/*** 删除*/boolean removeById(Long id);
}
3.2 基础服务实现
package com.maoteng.ai.service.impl;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.maoteng.ai.entity.BaseEntity;
import com.maoteng.ai.mapper.BaseMapper;
import com.maoteng.ai.service.BaseService;import java.util.List;public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BaseService<T> {@Overridepublic IPage<T> page(Page<T> page) {return this.page(page);}@Overridepublic List<T> list() {return this.list();}@Overridepublic T getById(Long id) {return this.getById(id);}@Overridepublic boolean save(T entity) {return this.save(entity);}@Overridepublic boolean updateById(T entity) {return this.updateById(entity);}@Overridepublic boolean removeById(Long id) {return this.removeById(id);}
}
3.3 用户服务接口
package com.maoteng.ai.service;import com.maoteng.ai.entity.User;public interface UserService extends BaseService<User> {/*** 根据用户名查询用户*/User findByUsername(String username);/*** 用户注册*/User register(User user);/*** 用户登录*/User login(String username, String password);/*** 修改密码*/boolean changePassword(Long userId, String oldPassword, String newPassword);
}
3.4 用户服务实现
package com.maoteng.ai.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.maoteng.ai.entity.User;
import com.maoteng.ai.mapper.UserMapper;
import com.maoteng.ai.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implements UserService {@Autowiredprivate BCryptPasswordEncoder passwordEncoder;@Overridepublic User findByUsername(String username) {return baseMapper.findByUsername(username);}@Override@Transactional(rollbackFor = Exception.class)public User register(User user) {// 检查用户名是否已存在User existingUser = findByUsername(user.getUsername());if (existingUser != null) {throw new RuntimeException("用户名已存在");}// 加密密码user.setPassword(passwordEncoder.encode(user.getPassword()));// 保存用户save(user);return user;}@Overridepublic User login(String username, String password) {User user = findByUsername(username);if (user == null) {throw new RuntimeException("用户不存在");}if (!passwordEncoder.matches(password, user.getPassword())) {throw new RuntimeException("密码错误");}return user;}@Override@Transactional(rollbackFor = Exception.class)public boolean changePassword(Long userId, String oldPassword, String newPassword) {User user = getById(userId);if (user == null) {throw new RuntimeException("用户不存在");}if (!passwordEncoder.matches(oldPassword, user.getPassword())) {throw new RuntimeException("原密码错误");}user.setPassword(passwordEncoder.encode(newPassword));return updateById(user);}
}
3.5 聊天服务接口
package com.maoteng.ai.service;import com.maoteng.ai.entity.ChatHistory;import java.util.List;public interface ChatService {/*** 发送消息到OpenAI*/ChatHistory sendMessageToOpenAI(Long userId, String message);/*** 发送消息到Ollama*/ChatHistory sendMessageToOllama(Long userId, String message);/*** 获取用户最近的聊天记录*/List<ChatHistory> getRecentChatHistory(Long userId, int limit);/*** 保存聊天记录*/ChatHistory saveChatHistory(ChatHistory chatHistory);
}
3.6 聊天服务实现
package com.maoteng.ai.service.impl;import com.maoteng.ai.entity.ChatHistory;
import com.maoteng.ai.mapper.ChatHistoryMapper;
import com.maoteng.ai.service.ChatService;
import org.springframework.ai.openai.OpenAiClient;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.ollama.OllamaClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.time.LocalDateTime;
import java.util.List;@Service
public class ChatServiceImpl implements ChatService {@Autowiredprivate OpenAiClient openAiClient;@Autowiredprivate OllamaClient ollamaClient;@Autowiredprivate ChatHistoryMapper chatHistoryMapper;@Override@Transactional(rollbackFor = Exception.class)public ChatHistory sendMessageToOpenAI(Long userId, String message) {long startTime = System.currentTimeMillis();// 调用OpenAI APIString response = openAiClient.generate(message);long endTime = System.currentTimeMillis();// 保存聊天记录ChatHistory chatHistory = new ChatHistory();chatHistory.setUserId(userId);chatHistory.setModelType("openai");chatHistory.setModelName("gpt-3.5-turbo");chatHistory.setUserMessage(message);chatHistory.setAiResponse(response);chatHistory.setDuration(endTime - startTime);return saveChatHistory(chatHistory);}@Override@Transactional(rollbackFor = Exception.class)public ChatHistory sendMessageToOllama(Long userId, String message) {long startTime = System.currentTimeMillis();// 调用Ollama APIString response = ollamaClient.generate(message);long endTime = System.currentTimeMillis();// 保存聊天记录ChatHistory chatHistory = new ChatHistory();chatHistory.setUserId(userId);chatHistory.setModelType("ollama");chatHistory.setModelName("llama2");chatHistory.setUserMessage(message);chatHistory.setAiResponse(response);chatHistory.setDuration(endTime - startTime);return saveChatHistory(chatHistory);}@Overridepublic List<ChatHistory> getRecentChatHistory(Long userId, int limit) {return chatHistoryMapper.findRecentByUserId(userId, limit);}@Override@Transactional(rollbackFor = Exception.class)public ChatHistory saveChatHistory(ChatHistory chatHistory) {chatHistoryMapper.insert(chatHistory);return chatHistory;}
}

4. 控制器开发

4.1 基础响应类
package com.maoteng.ai.model;import lombok.Data;import java.io.Serializable;@Data
public class Response<T> implements Serializable {private static final long serialVersionUID = 1L;private int code;private String message;private T data;public static <T> Response<T> success() {return success(null);}public static <T> Response<T> success(T data) {Response<T> response = new Response<>();response.setCode(200);response.setMessage("操作成功");response.setData(data);return response;}public static <T> Response<T> error(String message) {return error(500, message);}public static <T> Response<T> error(int code, String message) {Response<T> response = new Response<>();response.setCode(code);response.setMessage(message);return response;}
}
4.2 用户控制器
package com.maoteng.ai.controller;import com.maoteng.ai.constants.ResponseConstants;
import com.maoteng.ai.entity.User;
import com.maoteng.ai.model.Response;
import com.maoteng.ai.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@PostMapping("/register")public Response<User> register(@RequestBody User user) {try {User registeredUser = userService.register(user);return Response.success(registeredUser);} catch (Exception e) {return Response.error(e.getMessage());}}@PostMapping("/login")public Response<User> login(@RequestParam String username, @RequestParam String password) {try {User user = userService.login(username, password);return Response.success(user);} catch (Exception e) {return Response.error(e.getMessage());}}@GetMapping("/{id}")public Response<User> getById(@PathVariable Long id) {User user = userService.getById(id);if (user == null) {return Response.error(ResponseConstants.NOT_FOUND, ResponseConstants.NOT_FOUND_MSG);}return Response.success(user);}@PutMapping("/{id}/password")public Response<Boolean> changePassword(@PathVariable Long id, @RequestParam String oldPassword, @RequestParam String newPassword) {try {boolean result = userService.changePassword(id, oldPassword, newPassword);return Response.success(result);} catch (Exception e) {return Response.error(e.getMessage());}}
}
4.3 聊天控制器
package com.maoteng.ai.controller;import com.maoteng.ai.entity.ChatHistory;
import com.maoteng.ai.model.Response;
import com.maoteng.ai.service.ChatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/chat")
public class ChatController {@Autowiredprivate ChatService chatService;@PostMapping("/openai")public Response<ChatHistory> sendMessageToOpenAI(@RequestParam Long userId, @RequestParam String message) {try {ChatHistory chatHistory = chatService.sendMessageToOpenAI(userId, message);return Response.success(chatHistory);} catch (Exception e) {return Response.error(e.getMessage());}}@PostMapping("/ollama")public Response<ChatHistory> sendMessageToOllama(@RequestParam Long userId, @RequestParam String message) {try {ChatHistory chatHistory = chatService.sendMessageToOllama(userId, message);return Response.success(chatHistory);} catch (Exception e) {return Response.error(e.getMessage());}}@GetMapping("/history/{userId}")public Response<List<ChatHistory>> getRecentChatHistory(@PathVariable Long userId, @RequestParam(defaultValue = "10") int limit) {List<ChatHistory> chatHistories = chatService.getRecentChatHistory(userId, limit);return Response.success(chatHistories);}
}

五、AI功能集成详解

1. OpenAI集成

1.1 OpenAI配置类
package com.maoteng.ai.config;import org.springframework.ai.openai.OpenAiApi;
import org.springframework.ai.openai.client.OpenAiClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;@Configuration
public class OpenAiConfig {@Beanpublic OpenAiClient openAiClient() {return OpenAiClient.builder().apiKey(System.getenv("OPENAI_API_KEY")).build();}
}
1.2 OpenAI服务类
package com.maoteng.ai.service;import org.springframework.ai.openai.OpenAiClient;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OpenAiService {@Autowiredprivate OpenAiClient openAiClient;public String generateText(String prompt) {return openAiClient.generate(prompt);}public String generateText(String prompt, String model, Double temperature, Integer maxTokens) {return openAiClient.generate(prompt, model, temperature, maxTokens);}
}

2. Ollama集成

2.1 Ollama配置类
package com.maoteng.ai.config;import org.springframework.ai.ollama.OllamaApi;
import org.springframework.ai.ollama.client.OllamaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;@Configuration
public class OllamaConfig {@Beanpublic OllamaClient ollamaClient() {return OllamaClient.builder().baseUrl("http://localhost:11434").build();}
}
2.2 Ollama服务类
package com.maoteng.ai.service;import org.springframework.ai.ollama.OllamaClient;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OllamaService {@Autowiredprivate OllamaClient ollamaClient;public String generateText(String prompt) {return ollamaClient.generate(prompt);}public String generateText(String prompt, String model) {return ollamaClient.generate(prompt, model);}
}

六、测试开发详解

1. 单元测试

1.1 用户服务测试
package com.maoteng.ai.service;import com.maoteng.ai.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@Transactional
public class UserServiceTest {@Autowiredprivate UserService userService;@Testpublic void testRegister() {User user = new User();user.setUsername("testuser");user.setPassword("password");User registeredUser = userService.register(user);assertNotNull(registeredUser.getId());assertEquals("testuser", registeredUser.getUsername());}@Testpublic void testLogin() {// 先注册用户User user = new User();user.setUsername("testuser");user.setPassword("password");userService.register(user);// 测试登录User loggedInUser = userService.login("testuser", "password");assertNotNull(loggedInUser);assertEquals("testuser", loggedInUser.getUsername());}
}
1.2 聊天服务测试
package com.maoteng.ai.service;import com.maoteng.ai.entity.ChatHistory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;import java.util.List;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@Transactional
public class ChatServiceTest {@Autowiredprivate ChatService chatService;@Testpublic void testSendMessageToOpenAI() {Long userId = 1L;String message = "Hello, OpenAI!";ChatHistory chatHistory = chatService.sendMessageToOpenAI(userId, message);assertNotNull(chatHistory.getId());assertEquals(userId, chatHistory.getUserId());assertEquals("openai", chatHistory.getModelType());assertEquals("gpt-3.5-turbo", chatHistory.getModelName());assertEquals(message, chatHistory.getUserMessage());assertNotNull(chatHistory.getAiResponse());}@Testpublic void testGetRecentChatHistory() {Long userId = 1L;int limit = 5;List<ChatHistory> chatHistories = chatService.getRecentChatHistory(userId, limit);assertNotNull(chatHistories);}
}

2. 接口测试

使用Postman或其他API测试工具测试接口:

2.1 用户接口测试
  1. 注册用户

    • 方法: POST
    • URL: http://localhost:8080/api/users/register
    • 请求体:
      {"username": "testuser","password": "password","email": "test@example.com"
      }
      
  2. 用户登录

    • 方法: POST
    • URL: http://localhost:8080/api/users/login?username=testuser&password=password
  3. 获取用户信息

    • 方法: GET
    • URL: http://localhost:8080/api/users/1
2.2 聊天接口测试
  1. 发送消息到OpenAI

    • 方法: POST
    • URL: http://localhost:8080/api/chat/openai?userId=1&message=Hello, OpenAI!
  2. 发送消息到Ollama

    • 方法: POST
    • URL: http://localhost:8080/api/chat/ollama?userId=1&message=Hello, Ollama!
  3. 获取聊天历史

    • 方法: GET
    • URL: http://localhost:8080/api/chat/history/1?limit=10

七、部署准备详解

1. 打包配置详解

1.1 Maven打包配置

pom.xml中添加或修改打包配置:

<build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes><mainClass>com.maoteng.ai.MtAiApplication</mainClass><layout>JAR</layout></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>${java.version}</source><target>${java.version}</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><configuration><encoding>UTF-8</encoding></configuration></plugin></plugins><resources><resource><directory>src/main/resources</directory><filtering>true</filtering></resource></resources>
</build>
1.2 多环境配置

创建不同环境的配置文件:

application-dev.yml
server:port: 8080servlet:context-path: /apispring:application:name: mt-ai# 数据库配置datasource:url: jdbc:mysql://localhost:3306/mt_ai_dev?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: mt_ai_userpassword: dev_passworddriver-class-name: com.mysql.cj.jdbc.Driverhikari:minimum-idle: 5maximum-pool-size: 15idle-timeout: 30000pool-name: HikariCPmax-lifetime: 1800000connection-timeout: 30000# JPA配置jpa:database-platform: org.hibernate.dialect.MySQL8Dialectshow-sql: truehibernate:ddl-auto: updateproperties:hibernate:format_sql: true# AI配置ai:openai:api-key: your-openai-api-key-devmodel: gpt-3.5-turbotemperature: 0.7max-tokens: 2000ollama:base-url: http://localhost:11434model: llama2# MyBatis-Plus配置
mybatis-plus:mapper-locations: classpath*:/mapper/**/*.xmltype-aliases-package: com.maoteng.ai.entityconfiguration:map-underscore-to-camel-case: truecache-enabled: falseglobal-config:db-config:id-type: autologic-delete-field: deletedlogic-delete-value: 1logic-not-delete-value: 0# 日志配置
logging:level:root: INFOcom.maoteng.ai: DEBUGorg.springframework.web: INFOorg.hibernate: INFOfile:name: logs/mt-ai-dev.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"# 监控配置
management:endpoints:web:exposure:include: health,info,metricsendpoint:health:show-details: always
application-test.yml
server:port: 8080servlet:context-path: /apispring:application:name: mt-ai# 数据库配置datasource:url: jdbc:mysql://test-db-server:3306/mt_ai_test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: ${DB_USERNAME}password: ${DB_PASSWORD}driver-class-name: com.mysql.cj.jdbc.Driverhikari:minimum-idle: 5maximum-pool-size: 15idle-timeout: 30000pool-name: HikariCPmax-lifetime: 1800000connection-timeout: 30000# JPA配置jpa:database-platform: org.hibernate.dialect.MySQL8Dialectshow-sql: truehibernate:ddl-auto: updateproperties:hibernate:format_sql: true# AI配置ai:openai:api-key: ${OPENAI_API_KEY}model: gpt-3.5-turbotemperature: 0.7max-tokens: 2000ollama:base-url: http://test-ollama-server:11434model: llama2# MyBatis-Plus配置
mybatis-plus:mapper-locations: classpath*:/mapper/**/*.xmltype-aliases-package: com.maoteng.ai.entityconfiguration:map-underscore-to-camel-case: truecache-enabled: falseglobal-config:db-config:id-type: autologic-delete-field: deletedlogic-delete-value: 1logic-not-delete-value: 0# 日志配置
logging:level:root: INFOcom.maoteng.ai: DEBUGorg.springframework.web: INFOorg.hibernate: INFOfile:name: logs/mt-ai-test.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"# 监控配置
management:endpoints:web:exposure:include: health,info,metricsendpoint:health:show-details: always
application-prod.yml
server:port: 8080servlet:context-path: /apispring:application:name: mt-ai# 数据库配置datasource:url: jdbc:mysql://prod-db-server:3306/mt_ai_prod?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: ${DB_USERNAME}password: ${DB_PASSWORD}driver-class-name: com.mysql.cj.jdbc.Driverhikari:minimum-idle: 10maximum-pool-size: 50idle-timeout: 30000pool-name: HikariCPmax-lifetime: 1800000connection-timeout: 30000# JPA配置jpa:database-platform: org.hibernate.dialect.MySQL8Dialectshow-sql: falsehibernate:ddl-auto: noneproperties:hibernate:format_sql: false# AI配置ai:openai:api-key: ${OPENAI_API_KEY}model: gpt-3.5-turbotemperature: 0.7max-tokens: 2000ollama:base-url: http://prod-ollama-server:11434model: llama2# MyBatis-Plus配置
mybatis-plus:mapper-locations: classpath*:/mapper/**/*.xmltype-aliases-package: com.maoteng.ai.entityconfiguration:map-underscore-to-camel-case: truecache-enabled: trueglobal-config:db-config:id-type: autologic-delete-field: deletedlogic-delete-value: 1logic-not-delete-value: 0# 日志配置
logging:level:root: INFOcom.maoteng.ai: INFOorg.springframework.web: INFOorg.hibernate: INFOfile:name: logs/mt-ai-prod.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"# 监控配置
management:endpoints:web:exposure:include: health,info,metricsendpoint:health:show-details: always

2. 环境变量配置

2.1 开发环境

在本地开发环境中,可以创建一个.env文件来存储环境变量:

DB_USERNAME=mt_ai_user
DB_PASSWORD=dev_password
OPENAI_API_KEY=your-openai-api-key
2.2 生产环境

在生产环境中,可以使用系统环境变量或Docker环境变量:

# Linux/Mac
export DB_USERNAME=mt_ai_user
export DB_PASSWORD=prod_password
export OPENAI_API_KEY=your-openai-api-key# Windows
set DB_USERNAME=mt_ai_user
set DB_PASSWORD=prod_password
set OPENAI_API_KEY=your-openai-api-key

八、部署步骤详解

1. 开发环境部署

1.1 本地运行
  1. 在IDEA中打开项目
  2. 配置运行环境:
    • 点击"Edit Configurations"
    • 添加Spring Boot配置
    • 设置Main class为com.maoteng.ai.MtAiApplication
    • 在VM options中添加-Dspring.profiles.active=dev
  3. 点击运行按钮启动应用
1.2 命令行运行
# 编译项目
mvn clean package -DskipTests# 运行项目(开发环境)
java -jar target/maoteng-ai.jar --spring.profiles.active=dev

2. 测试环境部署

2.1 服务器准备
  1. 安装JDK 17

    # Ubuntu/Debian
    sudo apt update
    sudo apt install openjdk-17-jdk# CentOS/RHEL
    sudo yum install java-17-openjdk-devel
    
  2. 安装MySQL

    # Ubuntu/Debian
    sudo apt install mysql-server# CentOS/RHEL
    sudo yum install mysql-server
    
  3. 配置MySQL

    sudo mysql_secure_installation
    
  4. 创建数据库和用户

    CREATE DATABASE mt_ai_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    CREATE USER 'mt_ai_user'@'localhost' IDENTIFIED BY 'test_password';
    GRANT ALL PRIVILEGES ON mt_ai_test.* TO 'mt_ai_user'@'localhost';
    FLUSH PRIVILEGES;
    
2.2 应用部署
  1. 上传应用包到服务器

    scp target/maoteng-ai.jar user@test-server:/opt/mt-ai/
    
  2. 创建启动脚本 start.sh

    #!/bin/bash# 设置环境变量
    export DB_USERNAME=mt_ai_user
    export DB_PASSWORD=test_password
    export OPENAI_API_KEY=your-openai-api-key# 启动应用
    nohup java -jar /opt/mt-ai/maoteng-ai.jar --spring.profiles.active=test > /opt/mt-ai/mt-ai.log 2>&1 &# 输出进程ID
    echo $! > /opt/mt-ai/mt-ai.pid
    
  3. 创建停止脚本 stop.sh

    #!/bin/bash# 获取进程ID
    PID=$(cat /opt/mt-ai/mt-ai.pid)# 停止应用
    kill $PID# 删除PID文件
    rm /opt/mt-ai/mt-ai.pid
    
  4. 设置脚本权限

    chmod +x /opt/mt-ai/start.sh
    chmod +x /opt/mt-ai/stop.sh
    
  5. 启动应用

    cd /opt/mt-ai
    ./start.sh
    

3. 生产环境部署

3.1 服务器准备
  1. 安装JDK 17

    # Ubuntu/Debian
    sudo apt update
    sudo apt install openjdk-17-jdk# CentOS/RHEL
    sudo yum install java-17-openjdk-devel
    
  2. 安装MySQL

    # Ubuntu/Debian
    sudo apt install mysql-server# CentOS/RHEL
    sudo yum install mysql-server
    
  3. 配置MySQL

    sudo mysql_secure_installation
    
  4. 创建数据库和用户

    CREATE DATABASE mt_ai_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    CREATE USER 'mt_ai_user'@'localhost' IDENTIFIED BY 'prod_password';
    GRANT ALL PRIVILEGES ON mt_ai_prod.* TO 'mt_ai_user'@'localhost';
    FLUSH PRIVILEGES;
    
3.2 应用部署
  1. 上传应用包到服务器

    scp target/maoteng-ai.jar user@prod-server:/opt/mt-ai/
    
  2. 创建启动脚本 start.sh

    #!/bin/bash# 设置环境变量
    export DB_USERNAME=mt_ai_user
    export DB_PASSWORD=prod_password
    export OPENAI_API_KEY=your-openai-api-key# 启动应用
    nohup java -Xms2g -Xmx4g -jar /opt/mt-ai/maoteng-ai.jar --spring.profiles.active=prod > /opt/mt-ai/mt-ai.log 2>&1 &# 输出进程ID
    echo $! > /opt/mt-ai/mt-ai.pid
    
  3. 创建停止脚本 stop.sh

    #!/bin/bash# 获取进程ID
    PID=$(cat /opt/mt-ai/mt-ai.pid)# 停止应用
    kill $PID# 删除PID文件
    rm /opt/mt-ai/mt-ai.pid
    
  4. 设置脚本权限

    chmod +x /opt/mt-ai/start.sh
    chmod +x /opt/mt-ai/stop.sh
    
  5. 启动应用

    cd /opt/mt-ai
    ./start.sh
    

4. Docker部署

4.1 创建Dockerfile
FROM openjdk:17-jdk-slimWORKDIR /appCOPY target/maoteng-ai.jar /app/mt-ai.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "mt-ai.jar"]
4.2 创建docker-compose.yml
version: '3'services:mt-ai:build: .container_name: mt-aiports:- "8080:8080"environment:- SPRING_PROFILES_ACTIVE=prod- DB_USERNAME=mt_ai_user- DB_PASSWORD=prod_password- OPENAI_API_KEY=your-openai-api-keyvolumes:- ./logs:/app/logsrestart: always
4.3 构建和运行Docker容器
# 构建镜像
docker-compose build# 启动容器
docker-compose up -d# 查看日志
docker-compose logs -f

九、维护和更新详解

1. 日志管理

1.1 日志配置

application.yml中配置日志:

logging:level:root: INFOcom.maoteng.ai: DEBUGorg.springframework.web: INFOorg.hibernate: INFOfile:name: logs/mt-ai.logpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"logback:rollingpolicy:max-file-size: 10MBmax-history: 30
1.2 日志轮转

创建logback-spring.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration><property name="LOG_PATH" value="logs"/><property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${LOG_PATTERN}</pattern></encoder></appender><!-- 文件输出 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/mt-ai.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_PATH}/mt-ai.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>30</maxHistory></rollingPolicy><encoder><pattern>${LOG_PATTERN}</pattern></encoder></appender><!-- 根日志级别 --><root level="INFO"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></root><!-- 应用日志级别 --><logger name="com.maoteng.ai" level="DEBUG"/>
</configuration>
1.3 日志查看
# 查看实时日志
tail -f logs/mt-ai.log# 查看特定日期的日志
cat logs/mt-ai.2023-04-11.log# 使用grep搜索日志
grep "ERROR" logs/mt-ai.log

2. 监控配置

2.1 添加监控依赖

pom.xml中添加监控依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
2.2 配置监控端点

application.yml中配置监控端点:

management:endpoints:web:exposure:include: health,info,metrics,prometheusendpoint:health:show-details: alwaysmetrics:tags:application: ${spring.application.name}
2.3 自定义健康检查
package com.maoteng.ai.config;import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;@Component
public class CustomHealthIndicator implements HealthIndicator {@Overridepublic Health health() {// 自定义健康检查逻辑return Health.up().withDetail("custom", "Everything is OK").build();}
}

3. 备份策略

3.1 数据库备份

创建数据库备份脚本 backup-db.sh

#!/bin/bash# 设置变量
DB_NAME="mt_ai_prod"
DB_USER="mt_ai_user"
DB_PASS="prod_password"
BACKUP_DIR="/opt/backups/db"
DATE=$(date +%Y%m%d_%H%M%S)# 创建备份目录
mkdir -p $BACKUP_DIR# 备份数据库
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME > $BACKUP_DIR/${DB_NAME}_${DATE}.sql# 压缩备份
gzip $BACKUP_DIR/${DB_NAME}_${DATE}.sql# 删除30天前的备份
find $BACKUP_DIR -name "${DB_NAME}_*.sql.gz" -mtime +30 -delete
3.2 配置文件备份

创建配置文件备份脚本 backup-config.sh

#!/bin/bash# 设置变量
CONFIG_DIR="/opt/mt-ai"
BACKUP_DIR="/opt/backups/config"
DATE=$(date +%Y%m%d_%H%M%S)# 创建备份目录
mkdir -p $BACKUP_DIR# 备份配置文件
tar -czf $BACKUP_DIR/config_${DATE}.tar.gz $CONFIG_DIR/application*.yml# 删除30天前的备份
find $BACKUP_DIR -name "config_*.tar.gz" -mtime +30 -delete
3.3 设置定时备份

编辑crontab:

crontab -e

添加以下内容:

# 每天凌晨2点备份数据库
0 2 * * * /opt/mt-ai/backup-db.sh# 每周日凌晨3点备份配置文件
0 3 * * 0 /opt/mt-ai/backup-config.sh

4. 版本更新

4.1 版本号管理

pom.xml中管理版本号:

<properties><java.version>17</java.version><spring-boot.version>3.4.3</spring-boot.version><spring-ai.version>1.0.0-M6</spring-ai.version><mybatis-plus.version>3.5.10.1</mybatis-plus.version><lombok.version>1.18.22</lombok.version><project.version>1.0.0</project.version>
</properties>
4.2 更新流程
  1. 更新代码

    git pull origin main
    
  2. 更新版本号

    # 修改pom.xml中的版本号
    mvn versions:set -DnewVersion=1.0.1
    
  3. 编译项目

    mvn clean package -DskipTests
    
  4. 部署新版本

    # 停止旧版本
    ./stop.sh# 备份旧版本
    cp maoteng-ai.jar maoteng-ai.jar.bak# 部署新版本
    cp target/maoteng-ai.jar .# 启动新版本
    ./start.sh
    
  5. 验证新版本

    # 检查应用状态
    curl http://localhost:8080/api/actuator/health
    
  6. 回滚(如果需要)

    # 停止新版本
    ./stop.sh# 恢复旧版本
    mv maoteng-ai.jar.bak maoteng-ai.jar# 启动旧版本
    ./start.sh
    

十、性能优化详解

1. JVM优化

1.1 JVM参数配置

在启动脚本中添加JVM参数:

java -Xms2g -Xmx4g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar maoteng-ai.jar

参数说明:

  • -Xms2g: 初始堆大小
  • -Xmx4g: 最大堆大小
  • -XX:MetaspaceSize=128m: 初始元空间大小
  • -XX:MaxMetaspaceSize=256m: 最大元空间大小
  • -XX:+UseG1GC: 使用G1垃圾收集器
  • -XX:MaxGCPauseMillis=200: 最大GC暂停时间
1.2 GC日志配置

添加GC日志参数:

java -Xms2g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xloggc:logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -jar maoteng-ai.jar

2. 数据库优化

2.1 连接池优化

application.yml中优化数据库连接池配置:

spring:datasource:hikari:minimum-idle: 10maximum-pool-size: 50idle-timeout: 30000pool-name: HikariCPmax-lifetime: 1800000connection-timeout: 30000connection-test-query: SELECT 1
2.2 SQL优化
  1. 使用索引

    CREATE INDEX idx_user_username ON user(username);
    CREATE INDEX idx_chat_history_user_id ON chat_history(user_id);
    
  2. 优化查询

    // 使用分页查询
    Page<User> page = new Page<>(1, 10);
    IPage<User> userPage = userService.page(page);// 使用条件查询
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(User::getStatus, 0);
    List<User> users = userService.list(queryWrapper);
    

3. 缓存优化

3.1 添加缓存依赖

pom.xml中添加缓存依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3.2 配置缓存

application.yml中配置缓存:

spring:cache:type: redisredis:time-to-live: 3600000cache-null-values: trueredis:host: localhostport: 6379password: database: 0
3.3 使用缓存
@Service
@CacheConfig(cacheNames = "users")
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implements UserService {@Override@Cacheable(key = "#id")public User getById(Long id) {return super.getById(id);}@Override@CachePut(key = "#user.id")public boolean updateById(User user) {return super.updateById(user);}@Override@CacheEvict(key = "#id")public boolean removeById(Long id) {return super.removeById(id);}
}

十一、安全配置详解

1. 添加安全依赖

pom.xml中添加安全依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>

2. 配置安全

2.1 安全配置类
package com.maoteng.ai.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeHttpRequests().requestMatchers("/api/auth/**").permitAll().requestMatchers("/api/public/**").permitAll().requestMatchers("/api/actuator/**").hasRole("ADMIN").anyRequest().authenticated().and().httpBasic();return http.build();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
2.2 JWT工具类
package com.maoteng.ai.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;@Component
public class JwtTokenUtil {@Value("${jwt.secret}")private String secret;@Value("${jwt.expiration}")private Long expiration;private Key getSigningKey() {byte[] keyBytes = secret.getBytes();return Keys.hmacShaKeyFor(keyBytes);}public String generateToken(UserDetails userDetails) {Map<String, Object> claims = new HashMap<>();return createToken(claims, userDetails.getUsername());}private String createToken(Map<String, Object> claims, String subject) {return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())).setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)).signWith(getSigningKey(), SignatureAlgorithm.HS256).compact();}public Boolean validateToken(String token, UserDetails userDetails) {final String username = extractUsername(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}public String extractUsername(String token) {return extractClaim(token, Claims::getSubject);}public Date extractExpiration(String token) {return extractClaim(token, Claims::getExpiration);}public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {final Claims claims = extractAllClaims(token);return claimsResolver.apply(claims);}private Claims extractAllClaims(String token) {return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();}private Boolean isTokenExpired(String token) {return extractExpiration(token).before(new Date());}
}

3. 配置JWT属性

application.yml中添加JWT配置:

jwt:secret: your-secret-key-should-be-very-long-and-secureexpiration: 86400  # 24小时

十二、常见问题解决

1. 环境配置问题

1.1 JDK版本不匹配

问题:应用启动时报错 Unsupported class file major version 61

解决方案

  • 确保使用JDK 17
  • 检查JAVA_HOME环境变量是否正确设置
  • 检查IDE中的JDK配置
1.2 数据库连接失败

问题:应用启动时报错 Communications link failure

解决方案

  • 检查数据库服务是否启动
  • 验证数据库连接信息是否正确
  • 检查数据库用户权限
  • 检查防火墙设置

2. 运行错误处理

2.1 内存不足

问题:应用启动时报错 OutOfMemoryError: Java heap space

解决方案

  • 增加JVM堆内存:-Xmx4g
  • 检查内存泄漏
  • 优化代码中的内存使用
2.2 端口占用

问题:应用启动时报错 Web server failed to start. Port 8080 was already in use

解决方案

  • 更改应用端口:server.port=8081
  • 查找并关闭占用端口的进程:
    # Linux/Mac
    lsof -i :8080
    kill -9 <PID># Windows
    netstat -ano | findstr :8080
    taskkill /PID <PID> /F
    

3. 性能优化建议

3.1 数据库查询慢

解决方案

  • 添加适当的索引
  • 优化SQL查询
  • 使用分页查询
  • 配置数据库连接池
3.2 应用响应慢

解决方案

  • 使用缓存
  • 优化代码逻辑
  • 增加服务器资源
  • 使用异步处理

十三、项目扩展建议

1. 功能扩展

  1. 用户管理

    • 角色权限管理
    • 用户组管理
    • 第三方登录集成
  2. AI功能

    • 更多AI模型集成
    • 自定义模型训练
    • 图像识别功能
    • 语音识别功能
  3. 数据分析

    • 用户行为分析
    • 使用统计报表
    • 性能监控面板

2. 架构扩展

  1. 微服务架构

    • 服务拆分
    • 服务注册与发现
    • 负载均衡
    • 服务熔断与降级
  2. 高可用架构

    • 集群部署
    • 数据库主从复制
    • 缓存集群
  3. 容器化部署

    • Kubernetes集群
    • 服务网格
    • 自动化部署

十四、总结

AI项目是一个基于Spring Boot的智能AI应用系统,集成了多种AI模型,提供了智能对话、文档处理等功能。通过本开发指南,您可以从零开始搭建和开发这个项目,包括环境搭建、项目初始化、核心功能开发、AI功能集成、测试开发、部署准备、部署步骤、维护和更新等方面。


http://www.mrgr.cn/news/98359.html

相关文章:

  • antv x6使用(支持节点排序、新增节点、编辑节点、删除节点、选中节点)
  • 【Java集合】HashMap源码深度分析
  • 大数据面试问答-批处理性能优化
  • poi-tl
  • Spark-SQL核心编程(一)
  • 【JavaEE初阶】多线程重点知识以及常考的面试题-多线程进阶(一)
  • Kubernetes Operator 是什么,以及它们的用途
  • 基于瑞芯微RK3576 国产ARM八核2.2GHz A72 NPU 6T AI——MQTT通信方案
  • #4 我们为什么使用物联网? 以及 物联网的整体结构
  • 优先级队列(堆二叉树)底层的实现:
  • Codeforces Round 1017 (Div. 4)题解
  • 9.thinkphp的请求
  • 【STL】set
  • 【LLM】解锁Agent协作:深入了解谷歌 A2A 协议与 Python 实现
  • 前端工程化之自动化构建
  • 07软件测试需求分析案例-修改用户信息
  • UNITY 屏幕UI自适应
  • 使用SVM对心脏数据是否患病进行分类预测
  • UNet深度学习实战遥感航拍图像语义分割
  • 科研软件分享