【Java AI Agent智能存库调拨+BI问答】第三章 智能库存调拨优化系统——前置准备与基础框架
第三章 智能库存调拨优化系统——前置准备与基础框架
一、系统概述
1.1 业务场景
在多仓库的仓储管理体系中,不同仓库之间的库存往往存在不平衡的问题:某些仓库某种商品积压严重,而另一些仓库却面临缺货风险。传统的人工调拨方式依赖管理员经验判断,存在响应慢、决策主观、成本高等问题。
本系统通过引入大语言模型(LLM)技术,构建一套ERP智能库存调拨系统,实现以下核心价值:
- AI智能预测:LLM分析历史销售数据与库存分布,自动预测缺货风险
- 人类反馈闭环:AI生成调拨建议后,由人工审核确认,确保决策可靠性
- 自动化调拨流程:审核通过后自动生成库存调拨单,实现从分析到执行的全链路自动化
- 效率提升:大幅降低人工分析成本,提升仓储调拨效率和准确性
1.2 系统功能模块
| 模块 | 功能描述 |
|---|---|
| 库存分析 | 实时汇总各仓库库存分布情况 |
| 销售预测 | 基于历史销售数据预测未来缺货风险 |
| 调拨建议 | AI综合分析后生成智能调拨建议 |
| 人工审核 | 提供调拨建议的审核界面,支持通过/驳回 |
| 调拨执行 | 审核通过后自动生成调拨单并扣减库存 |
| 库存日志 | 记录所有库存变动操作,确保可追溯 |
1.3 系统亮点
- AI预测 + 人类反馈(Human-in-the-Loop):结合AI的智能分析能力与人类的业务经验,既保证效率又确保准确性
- 自动化流程:从数据分析到调拨单生成的全流程自动化,减少人工干预
- 完整的库存追踪:通过库存操作日志表记录每一次库存变动,确保库存数据可追溯
二、表结构设计
本节将创建6张核心表,涵盖仓库、商品、销售记录、库存、调拨单和库存日志。这些表构成了智能库存调拨系统的数据基础。
2.1 仓库信息表(bb_warehouse)
用于存放仓库的基本信息,包括仓库编码、名称、位置和负责人。
CREATE TABLE bb_warehouse (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
warehouse_code VARCHAR(50) NOT NULL UNIQUE COMMENT '仓库编码',
warehouse_name VARCHAR(100) NOT NULL COMMENT '仓库名称',
location VARCHAR(255) DEFAULT NULL COMMENT '仓库位置描述',
manager VARCHAR(50) DEFAULT NULL COMMENT '负责人',
status TINYINT DEFAULT 1 COMMENT '状态(1:启用,0:停用)',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='仓库信息表';
2.2 商品信息表(bb_product)
记录商品的基本信息,包括商品编码、名称、规格型号、计量单位和分类。
CREATE TABLE bb_product (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
product_code VARCHAR(50) NOT NULL UNIQUE COMMENT '商品编码',
product_name VARCHAR(100) NOT NULL COMMENT '商品名称',
spec VARCHAR(100) DEFAULT NULL COMMENT '规格型号',
unit VARCHAR(20) DEFAULT '件' COMMENT '计量单位',
category VARCHAR(50) DEFAULT NULL COMMENT '分类',
status TINYINT DEFAULT 1 COMMENT '状态(1:启用,0:停用)',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品信息表';
2.3 商品销售记录表(bb_sales_record)
记录每个仓库中每种商品的销售数据,是AI进行销售趋势分析和缺货预测的核心数据源。
CREATE TABLE bb_sales_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
warehouse_id BIGINT NOT NULL COMMENT '仓库ID',
product_id BIGINT NOT NULL COMMENT '商品ID',
sale_date DATE NOT NULL COMMENT '销售日期',
quantity DECIMAL(18,2) NOT NULL COMMENT '销售数量',
revenue DECIMAL(18,2) DEFAULT 0 COMMENT '销售金额',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品销售记录表';
2.4 库存表(bb_inventory)
记录每个仓库中每种商品的当前库存数量和锁定库存数量。锁定库存用于标识调拨中未完成的部分,避免超卖。
CREATE TABLE bb_inventory (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
warehouse_id BIGINT NOT NULL COMMENT '仓库ID',
product_id BIGINT NOT NULL COMMENT '商品ID',
quantity DECIMAL(18,2) DEFAULT 0 COMMENT '当前库存数量',
locked_quantity DECIMAL(18,2) DEFAULT 0 COMMENT '锁定库存数量(例如调拨中未完成的部分)',
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
UNIQUE KEY uk_inventory_wh_prod (warehouse_id, product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存表';
设计说明:
uk_inventory_wh_prod唯一索引确保同一仓库中同一商品只有一条库存记录,locked_quantity字段用于处理并发调拨场景。
2.5 调拨单主表(bb_transfer_order)
调拨单主表记录调拨的基本信息,包括调出仓库、调入仓库、调拨状态和类型。
CREATE TABLE bb_transfer_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
order_no VARCHAR(50) NOT NULL UNIQUE COMMENT '调拨单号',
source_warehouse_id BIGINT NOT NULL COMMENT '调出仓库ID',
target_warehouse_id BIGINT NOT NULL COMMENT '调入仓库ID',
status TINYINT DEFAULT 0 COMMENT '状态(0:待审核,1:已审核,2:调拨中,3:已完成,4:已取消)',
transfer_type INT DEFAULT 0 COMMENT '调拨类型:1智能,0人工',
transfer_date DATE DEFAULT NULL COMMENT '调拨日期',
comment TEXT COMMENT '说明',
created_by VARCHAR(50) DEFAULT NULL COMMENT '创建人',
approved_by VARCHAR(50) DEFAULT NULL COMMENT '审核人',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='调拨单主表';
字段说明:
transfer_type字段区分AI智能调拨(值为1)和传统人工调拨(值为0),便于后续统计分析。
2.6 调拨单明细表(bb_transfer_order_item)
调拨单明细表记录每张调拨单中具体调拨的商品和数量。
CREATE TABLE bb_transfer_order_item (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
transfer_order_id BIGINT NOT NULL COMMENT '调拨单ID',
product_id BIGINT NOT NULL COMMENT '商品ID',
transfer_quantity DECIMAL(18,2) NOT NULL COMMENT '调拨数量',
actual_quantity DECIMAL(18,2) DEFAULT 0 COMMENT '实际到货数量',
remark VARCHAR(255) DEFAULT NULL COMMENT '备注'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='调拨单明细表';
2.7 库存操作日志表(bb_inventory_log)
用于追踪所有库存变动操作,确保库存数据的完整性和可追溯性。
CREATE TABLE bb_inventory_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
warehouse_id BIGINT NOT NULL COMMENT '仓库ID',
product_id BIGINT NOT NULL COMMENT '商品ID',
change_type VARCHAR(50) NOT NULL COMMENT '变动类型(IN:入库,OUT:出库,TRANSFER_OUT:调拨出库,TRANSFER_IN:调拨入库)',
quantity_change DECIMAL(18,2) NOT NULL COMMENT '变动数量(正为增加,负为减少)',
reference_no VARCHAR(50) DEFAULT NULL COMMENT '关联单据号(如调拨单号)',
created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
remark VARCHAR(255) DEFAULT NULL COMMENT '备注'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存操作日志表';
设计说明:库存操作日志表采用"仅插入"设计模式,所有库存变动都记录为一条新记录,通过
change_type区分操作类型,便于后续审计和分析。
2.8 表关系说明
各表之间的关系如下图所示:
bb_warehouse (仓库) bb_product (商品)
| |
| 1:N | 1:N
v v
bb_inventory (库存) <------- bb_sales_record (销售记录)
|
|
v
bb_transfer_order (调拨单主表) ----> bb_transfer_order_item (调拨单明细)
|
| (触发记录)
v
bb_inventory_log (库存操作日志)
三、数据初始化
3.1 仓库样例数据
创建3个区域仓库,分别位于华北、华东和华南:
INSERT INTO bb_warehouse (warehouse_code, warehouse_name, location, manager)
VALUES
('WH001', '华北仓', '北京', '张三'),
('WH002', '华东仓', '上海', '李四'),
('WH003', '华南仓', '广州', '王五');
3.2 商品样例数据
创建5种不同类别的商品,涵盖电子产品、家具和外设:
INSERT INTO bb_product (product_code, product_name, spec, unit, category)
VALUES
('P001', '智能手机', '6.5英寸 128G', '台', '电子产品'),
('P002', '蓝牙耳机', '入耳式', '副', '电子产品'),
('P003', '办公椅', '可调节靠背', '张', '家具'),
('P004', '显示器', '27寸 IPS', '台', '电子产品'),
('P005', '机械键盘', '104键 RGB', '个', '外设');
3.3 库存初始数据
为每个仓库的每种商品初始化库存,数量在100到300之间随机生成:
INSERT INTO bb_inventory (warehouse_id, product_id, quantity, locked_quantity)
SELECT w.id, p.id, FLOOR(RAND() * 200 + 100), 0
FROM bb_warehouse w, bb_product p;
说明:
FLOOR(RAND() * 200 + 100)生成100到300之间的随机整数,模拟各仓库初始库存不平衡的场景。
3.4 历史销售数据
生成2023年至2025年的季度销售数据,为AI分析提供历史依据:
-- 创建过去三年的季度销售数据(2023-2025)
SET @start_date = '2023-01-01';
SET @end_date = '2025-12-31';
INSERT INTO bb_sales_record (warehouse_id, product_id, sale_date, quantity, revenue)
SELECT *
FROM (
SELECT
w.id AS warehouse_id,
p.id AS product_id,
DATE_ADD('2023-01-01', INTERVAL (FLOOR(RAND()*12*3)) MONTH) AS sale_date,
ROUND(RAND()*500 + 50, 2) AS quantity,
ROUND(RAND()*50000 + 5000, 2) AS revenue
FROM bb_warehouse w, bb_product p, (SELECT 1 FROM dual UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) q
) t
WHERE t.sale_date BETWEEN @start_date AND @end_date;
说明:通过交叉连接(Cross Join)生成每个仓库每种商品的多条销售记录,
RAND()函数模拟不同的销售数量和金额,使数据更接近真实业务场景。
四、工程搭建
4.1 项目结构概览
项目采用Maven多模块结构,ai-agent 作为父模块,统一管理依赖版本,ai-inventory-transfer 作为子模块实现具体的库存调拨业务。
ai-agent/ <-- 父模块(根目录)
├── pom.xml <-- 父POM文件
└── ai-inventory-transfer/ <-- 库存调拨子模块
├── pom.xml <-- 子模块POM文件
├── src/
│ ├── main/
│ │ ├── java/com/carl/ai/inventory/
│ │ │ ├── AiInventoryTransferApplication.java
│ │ │ ├── config/ <-- 配置类
│ │ │ ├── controller/ <-- 控制器层
│ │ │ ├── service/ <-- 业务逻辑层
│ │ │ ├── entity/ <-- 实体类
│ │ │ ├── mapper/ <-- 数据访问层
│ │ │ ├── transfer/ <-- 调拨业务模块
│ │ │ └── utils/ <-- 工具类
│ │ └── resources/
│ │ ├── application.yml <-- 配置文件
│ │ ├── logback-spring.xml <-- 日志配置
│ │ ├── templates/ <-- Thymeleaf模板
│ │ └── mapper/ <-- MyBatis映射文件
│ └── test/
└── ...
4.2 父POM文件
父POM负责统一管理依赖版本和公共依赖,确保子模块版本一致性。
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Spring Boot 父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/>
</parent>
<groupId>com.carl</groupId>
<artifactId>ai-agent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>ai-agent</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<mapstruct.version>1.6.2</mapstruct.version>
<lombok.version>1.18.30</lombok.version>
<hutool-all.version>5.8.23</hutool-all.version>
<spring-ai.version>1.0.3</spring-ai.version>
<spring-ai-alibaba.version>1.0.0.4</spring-ai-alibaba.version>
</properties>
<!-- 公共依赖,所有子模块自动继承 -->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
</dependencies>
<!-- 依赖版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-bom</artifactId>
<version>${spring-ai-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
版本说明:
spring-ai-alibaba.version:Spring AI Alibaba BOM,提供阿里云大模型接入能力spring-ai.version:Spring AI BOM,提供统一的AI编程抽象mapstruct:对象映射工具,用于DTO和Entity之间的转换lombok:简化Java代码,自动生成getter/setter等方法hutool-all:Java工具类库,提供丰富的实用工具方法
4.3 子模块POM文件
子模块 ai-inventory-transfer 依赖父模块,并引入业务所需的特定依赖。
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.carl</groupId>
<artifactId>ai-agent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>ai-inventory-transfer</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>ai-inventory-transfer</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<mysql.version>8.0.32</mysql.version>
<mybatis-plus.verion>3.5.14</mybatis-plus.verion>
<redisson-verion>3.23.4</redisson-verion>
</properties>
<dependencies>
<!-- Web启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.verion}</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- Redis (Redisson) -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson-verion}</version>
</dependency>
<!-- 邮件服务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- Thymeleaf模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring AI Alibaba Graph Core -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-graph-core</artifactId>
</dependency>
<!-- Spring AI OpenAI自动配置 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-openai</artifactId>
</dependency>
<!-- Spring AI Chat Client自动配置 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-client</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
依赖说明:
mybatis-plus-spring-boot3-starter:MyBatis Plus Spring Boot 3 启动器,简化数据访问层开发redisson-spring-boot-starter:Redisson Redis客户端,用于分布式锁和缓存spring-boot-starter-mail:邮件发送功能,用于调拨通知spring-boot-starter-thymeleaf:模板引擎,用于邮件模板渲染spring-ai-alibaba-graph-core:Spring AI Alibaba 图核心库,用于构建AI工作流
五、项目配置
5.1 application.yml
spring:
application:
name: ai-inventory-transfer
# AI 配置:接入阿里云通义千问大模型
ai:
openai:
api-key: sk-e836ecd744a14caca23c9d06b9bd1f1f
base-url: https://dashscope.aliyuncs.com/compatible-mode
chat:
options:
model: qwen3-max
temperature: 0.6
# 数据源配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ai-inventory-transfer?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: 123456
# Redis配置
data:
redis:
database: 0
host: localhost
port: 6379
timeout: 5s
connect-timeout: 5s
# 邮件配置
mail:
host: smtp.qq.com
port: 587
username: 1525761478@qq.com
password: efwvvempkglygcjg
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
# Thymeleaf模板配置
thymeleaf:
cache: true
check-template: true
check-template-location: true
content-type: text/html
enabled: true
encoding: UTF-8
mode: HTML
prefix: classpath:/templates/
suffix: .html
# 服务端口
server:
port: 8876
# 日志配置
logging:
file:
path: ./logs
level:
root: info
com.carl: info
# MyBatis Plus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
配置要点:
temperature: 0.6:控制AI输出的随机性,值越低输出越确定,适合库存分析场景model: qwen3-max:使用阿里云通义千问Max模型,提供强大的分析能力base-url:阿里云DashScope兼容模式接口地址
六、基础框架封装
6.1 统一响应体(R类)
统一响应体用于封装API接口的返回结果,确保前后端交互的数据格式一致性。
package com.carl.ai.inventory.utils;
import lombok.Data;
import java.io.Serializable;
/**
* 统一响应体
* @param <T> 数据类型
*/
@Data
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 响应码:200成功,其他为失败
*/
private Integer code;
/**
* 响应消息
*/
private String msg;
/**
* 响应数据
*/
private T data;
/**
* 时间戳
*/
private Long timestamp;
public R() {
this.timestamp = System.currentTimeMillis();
}
public R(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
this.timestamp = System.currentTimeMillis();
}
/**
* 成功响应(无数据)
*/
public static <T> R<T> ok() {
return new R<>(200, "操作成功", null);
}
/**
* 成功响应(有数据)
*/
public static <T> R<T> ok(T data) {
return new R<>(200, "操作成功", data);
}
/**
* 成功响应(自定义消息)
*/
public static <T> R<T> ok(String msg, T data) {
return new R<>(200, msg, data);
}
/**
* 失败响应
*/
public static <T> R<T> error(String msg) {
return new R<>(500, msg, null);
}
/**
* 失败响应(自定义状态码)
*/
public static <T> R<T> error(Integer code, String msg) {
return new R<>(code, msg, null);
}
/**
* 判断是否成功
*/
public boolean isSuccess() {
return Integer.valueOf(200).equals(this.code);
}
}
6.2 业务异常类(BusinessException)
自定义业务异常,用于区分系统异常和业务逻辑异常。
package com.carl.ai.inventory.exception;
import lombok.Getter;
/**
* 业务异常
*/
@Getter
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误消息
*/
private String msg;
public BusinessException(String msg) {
super(msg);
this.code = 500;
this.msg = msg;
}
public BusinessException(Integer code, String msg) {
super(msg);
this.code = code;
this.msg = msg;
}
public BusinessException(String msg, Throwable cause) {
super(msg, cause);
this.code = 500;
this.msg = msg;
}
}
6.3 全局异常处理器(GlobalExceptionHandler)
统一捕获和处理系统中抛出的各类异常,将异常信息封装为统一响应格式返回给前端。
package com.carl.ai.inventory.exception;
import com.carl.ai.inventory.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理器
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理业务异常
*/
@ExceptionHandler(BusinessException.class)
public R<Void> handleBusinessException(BusinessException e) {
log.warn("业务异常:{}", e.getMsg());
return R.error(e.getCode(), e.getMsg());
}
/**
* 处理参数绑定异常
*/
@ExceptionHandler(BindException.class)
public R<Void> handleBindException(BindException e) {
String msg = e.getAllErrors().get(0).getDefaultMessage();
log.warn("参数校验失败:{}", msg);
return R.error(400, msg);
}
/**
* 处理其他所有异常
*/
@ExceptionHandler(Exception.class)
public R<Void> handleException(Exception e) {
log.error("系统异常:", e);
return R.error(500, "系统繁忙,请稍后重试");
}
}
6.4 日志配置(logback-spring.xml)
日志配置采用分层的输出策略,支持控制台输出、文件输出和JSON格式输出(可选,用于对接ELK等日志系统)。
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds">
<!-- 1. 定义日志文件存放路径 -->
<property name="LOG_HOME" value="logs"/>
<property name="APP_NAME" value="inventory-transfer-system"/>
<!-- 2. 控制台日志输出格式 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 3. 文件日志输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天生成一个日志文件,保留30天 -->
<fileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- 4. JSON 文件日志(可选,用于 ELK 等日志系统) -->
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}.json</file>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp/>
<pattern>
<pattern>
{
"level": "%level",
"thread": "%thread",
"logger": "%logger",
"message": "%message",
"exception": "%exception"
}
</pattern>
</pattern>
</providers>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.json</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>
<!-- 5. 日志级别控制 -->
<logger name="org.springframework" level="INFO"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="com.zaxxer.hikari" level="WARN"/>
<logger name="com.carl" level="DEBUG"/>
<!-- 6. 根日志输出到控制台与文件 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<!-- 如需JSON日志,则打开下一行 -->
<!-- <appender-ref ref="JSON_FILE"/> -->
</root>
</configuration>
配置说明:
scan="true":开启自动扫描配置变更,60秒检查一次- 控制台输出使用
%-5level使日志级别左对齐,便于阅读- 文件日志按天滚动,保留30天历史记录
- JSON日志默认关闭,需要对接ELK日志系统时可启用
com.carl包下日志级别设为DEBUG,方便开发调试
七、代码生成器使用说明
本项目使用 MyBatisX 插件自动生成基础的CRUD代码,包括Entity实体类、Mapper接口、Service接口及实现类、Controller控制器。这大大减少了重复的模板代码编写工作,让开发者可以专注于业务逻辑的实现。
7.1 MyBatisX插件安装
- 打开 IntelliJ IDEA,进入 File > Settings > Plugins
- 在 Marketplace 中搜索 MyBatisX
- 点击 Install 安装插件,重启IDEA
7.2 数据库连接配置
- 打开 IDEA 右侧的 Database 工具窗口
- 点击 + 号,选择 Data Source > MySQL
- 填写数据库连接信息:
- Host:
localhost - Port:
3306 - User:
root - Password:
123456 - Database:
ai-inventory-transfer
- Host:
- 点击 Test Connection 测试连接,确认无误后点击 OK
7.3 代码生成步骤
- 在 Database 工具窗口中,展开数据库连接,找到需要生成代码的表(如
bb_warehouse、bb_product等) - 选中需要生成代码的表(可多选),右键点击选择 MyBatisX > Generate MyBatis-Plus
- 在弹出的配置窗口中填写以下信息:
- module path: 选择
ai-inventory-transfer模块路径 - base package: 填写
com.carl.ai.inventory - relative package: 填写
entity(实体类存放包) - encoding: 选择
UTF-8 - template: 选择
MyBatis-Plus模板
- module path: 选择
- 在选项配置中勾选需要生成的代码类型:
- 勾选 Entity:生成实体类
- 勾选 Mapper:生成Mapper接口
- 勾选 Service:生成Service接口和实现类
- 勾选 Controller:生成Controller控制器
- 点击 Finish,MyBatisX 将自动生成对应的代码文件
7.4 生成后的代码结构
以 bb_warehouse 表为例,MyBatisX 会生成以下文件:
com/carl/ai/inventory/
├── entity/
│ └── Warehouse.java <-- 实体类
├── mapper/
│ └── WarehouseMapper.java <-- Mapper接口
├── service/
│ ├── WarehouseService.java <-- Service接口
│ └── impl/
│ └── WarehouseServiceImpl.java <-- Service实现
└── controller/
└── WarehouseController.java <-- 控制器
7.5 生成后的调整建议
代码生成后,建议根据实际业务需求进行以下调整:
- 实体类:检查字段类型是否与业务匹配,可添加
@TableField注解进行字段映射配置 - Controller:统一返回类型为
R<T>,添加必要的参数校验注解(如@Valid、@NotNull) - Service:在生成的CRUD方法基础上,添加业务逻辑方法
- Mapper:如需复杂查询,可在Mapper接口中添加自定义方法,并在对应的XML文件中编写SQL
八、本章小结
本章完成了智能库存调拨系统的前置准备工作,主要内容包括:
- 系统概述:明确了AI智能库存调拨系统的业务场景、功能模块和核心价值
- 表结构设计:创建了6张核心表(仓库、商品、销售记录、库存、调拨单主表、调拨单明细、库存操作日志),构成了完整的数据模型
- 数据初始化:通过SQL脚本插入了仓库、商品、库存和历史销售数据,为后续AI分析提供了数据基础
- 工程搭建:使用Maven多模块结构搭建了项目框架,父POM统一管理依赖版本,子POM引入业务所需依赖
- 项目配置:配置了AI大模型(通义千问)、MySQL数据库、Redis、邮件服务和Thymeleaf模板引擎
- 基础框架封装:实现了统一响应体(R类)、业务异常类、全局异常处理器和日志配置
- 代码生成:介绍了使用MyBatisX插件自动生成基础CRUD代码的方法和步骤
完成上述准备工作后,下一章将开始实现AI智能调拨建议的核心业务逻辑。
更多推荐

所有评论(0)