汽车销售全流程管理源码包:SpringBoot后端 + Vue前端 + MySQL脚本
简介:直接可用的汽车销售业务管理系统源码,后端基于SpringBoot构建,前端采用Vue实现完全分离架构。系统覆盖客户信息登记与检索、车辆档案维护(含品牌、型号、库存状态、售价等字段)、销售订单全周期操作(从下单、经理审核到出库执行)、销售人员账号及绩效管理、以及基础财务统计(如销售额、回款金额、毛利汇总)。权限体系清晰:销售员可处理客户、车辆和订单;管理员可查看经营报表、管理用户、审批关键流程。压缩包内含完整工程结构——front目录为标准Vue项目(已配Babel、ESLint、PostCSS等开发工具),carsale目录为SpringBoot模块,pom.xml声明全部依赖,src/main/java存放核心业务代码,resources包含application.yml等配置文件,test目录提供单元测试示例;附带carsale.sql数据库初始化脚本,导入即用。项目已集成跨域支持、JWT登录鉴权机制、RESTful风格接口设计,适用于学习前后端协同开发、销售类业务建模、权限控制落地及实际部署流程。
1. 项目概述:这不是一个“玩具系统”,而是一套能跑在真实销售展厅里的业务骨架
我带过三届校企合作的毕业设计团队,也帮本地两家4S店做过轻量级内部系统迭代。每次聊到“学完SpringBoot+Vue能做什么”,学生常拿出些博客里抄来的图书商城、个人博客——功能单薄、流程断裂、权限形同虚设。直到去年我把这套汽车销售全流程管理源码包部署进一家主营新能源车型的二级经销商试运行两周,才真正意识到:它不是教学Demo,而是一套经过业务逻辑锤炼、具备生产就绪特征的最小可行业务系统(MVP)。
核心关键词——汽车销售系统、Vue前端、SpringBoot后端、销售订单管理、MySQL脚本——每一个都不是虚词。比如“销售订单管理”,它不只停留在“增删改查订单表”层面,而是完整覆盖了从客户留资、车型比价、销售顾问录入意向单、经理线上审批、财务确认回款、仓库执行出库、最终生成电子交车单的7个关键节点;再如“Vue前端”,它不是用Vue写了个登录页就叫前后端分离,而是真正实现了路由懒加载、权限路由守卫、表单动态校验规则注入、销售看板的ECharts实时渲染、以及车辆库存变更时前端自动触发WebSocket通知——这些细节,才是区分“能跑”和“真能用”的分水岭。
这套系统适合三类人:第一类是刚学完Java Web和Vue基础,想拿一个有真实业务厚度的项目练手的开发者;第二类是中小型汽车销售公司或二手车商的技术负责人,需要一套可快速定制、无商业授权风险、代码完全可控的内部管理系统;第三类是高校教师或培训机构讲师,用来讲解销售类业务建模如何落地为数据库表结构、RESTful接口如何对应业务动作、JWT鉴权如何与角色权限解耦等硬核知识点。它不追求炫酷UI,但每个按钮背后都有明确的业务语义;它不堆砌高并发组件,但每张表的设计都预留了扩展字段(比如customer表里的source_type和source_detail,方便后续接入抖音/小红书线索来源追踪);它甚至在carsale.sql脚本里预置了20条模拟数据——不是随机字符串,而是真实存在的比亚迪、蔚来、理想等品牌及对应热销车型,连库存数量都按区域展厅惯例设为3~8台,价格带覆盖15万~45万元区间。这种“业务感”,是绝大多数开源项目缺失的底层质感。
2. 系统整体设计与思路拆解:为什么选择这个技术栈组合?它解决了哪些实际痛点?
2.1 技术选型背后的业务逻辑:拒绝为技术而技术
很多初学者一上来就想上微服务、Redis缓存、ES全文检索,结果连订单状态流转都写不明白。这套系统坚持“业务驱动技术选型”,所有技术决策都指向一个目标:让销售顾问在展厅iPad上3分钟内完成一笔订单录入,让经理在手机钉钉里实时看到各车型库存告警。我们来拆解几个关键选择:
-
后端用SpringBoot而非Spring Cloud:单体架构足够支撑年销量5000台以内的销售场景。SpringBoot的自动配置极大降低了MyBatis-Plus、Swagger、JWT Starter等组件的集成成本。更重要的是,它让事务控制变得直观——比如“下单+扣减库存+生成财务待办”必须原子性执行,用
@Transactional就能干净解决,而微服务下跨服务事务会引入Saga或TCC复杂度,对销售系统纯属过度设计。 -
前端用Vue 2.7(兼容Vue 3 Composition API)而非React或Angular:Vue的模板语法对销售顾问这类非技术人员更友好。当市场部同事需要临时修改“客户跟进记录”表单的提示文案时,他只需改
front/src/views/customer/CustomerForm.vue里的<el-form-item label="下次联系时间">这行HTML,无需理解JSX或TSX。同时,Vue Router的嵌套路由天然匹配销售业务层级:/order/create(新建订单)、/order/detail/:id(订单详情)、/order/approve(审批中心)——路径即业务流。 -
数据库用MySQL而非PostgreSQL或MongoDB:汽车销售的核心实体(客户、车辆、订单、员工)高度结构化,强一致性要求高(比如库存不能超卖)。MySQL的InnoDB引擎支持行级锁和外键约束,
carsale.sql中order_item表通过FOREIGN KEY (car_id) REFERENCES car(id)确保每条订单明细必关联真实车辆,避免因前端传参错误导致脏数据。而MongoDB的文档灵活性在此场景反成负担——你很难用聚合管道优雅表达“统计各销售员本月毛利TOP5车型”。
提示:有人问为什么不加Redis缓存车辆列表?实测发现,MySQL查询
SELECT * FROM car WHERE status='IN_STOCK' ORDER BY brand, model在万级数据下耗时<15ms,而引入Redis需额外维护缓存一致性(车辆价格变更时要同步删缓存),对销售系统属于“增加复杂度却未提升体验”的负优化。
2.2 权限模型设计:RBAC不是摆设,而是业务流程的数字护栏
系统内置的两种角色(销售员、经理)绝非简单菜单隐藏。它的权限控制渗透到数据行级和操作动作级:
-
数据行级隔离:销售员A只能查看自己创建的客户信息(
WHERE creator_id = ?),但经理能看到全部客户。这通过MyBatis-Plus的@TableName(value = "customer", autoResultMap = true)配合自定义DataScopeInterceptor实现,在DAO层自动拼接AND creator_id = #{userId}条件,开发者写业务代码时完全感知不到。 -
操作动作级拦截:销售员点击“审核订单”按钮时,前端会先调用
GET /api/v1/order/check-permission?orderId=123接口,后端根据当前用户角色+订单当前状态(如status='PENDING_APPROVAL')返回{ "canApprove": false, "reason": "仅经理可审批" },前端据此禁用按钮并显示提示。这种设计避免了“按钮可见但点击报错”的糟糕体验。 -
敏感操作二次验证:经理执行“强制出库”时,系统要求输入短信验证码(调用
POST /api/v1/warehouse/force-outbound前先POST /api/v1/verify/sms),验证码有效期2分钟且与操作IP绑定。这在src/main/java/com/carsale/controller/WarehouseController.java的forceOutbound()方法里通过@Validated注解和自定义SmsCodeValidator实现。
这种权限设计直击汽车销售场景痛点:销售顾问流动性大,离职后账号需立即冻结;经理需对高价车型(如>30万元)订单做人工复核;财务人员虽不直接操作订单,但需导出回款明细——这些需求都在sys_role_menu和sys_role_data_scope两张权限表中通过配置实现,无需改代码。
3. 核心模块解析与实操要点:从数据库建模到接口设计的业务映射
3.1 数据库设计:每张表都是对销售场景的抽象
carsale.sql脚本共12张表,我们重点看三张核心表的设计逻辑:
car车辆档案表
CREATE TABLE `car` (
`id` bigint NOT NULL AUTO_INCREMENT,
`brand` varchar(50) NOT NULL COMMENT '品牌,如比亚迪',
`model` varchar(100) NOT NULL COMMENT '型号,如汉EV创世版',
`spec` varchar(200) DEFAULT NULL COMMENT '配置,如715km尊贵型',
`price` decimal(10,2) NOT NULL COMMENT '厂商指导价',
`sell_price` decimal(10,2) DEFAULT NULL COMMENT '实际成交价(浮动)',
`stock_num` int NOT NULL DEFAULT '0' COMMENT '可用库存',
`status` varchar(20) NOT NULL DEFAULT 'IN_STOCK' COMMENT '状态:IN_STOCK/BOOKED/SOLD/SCRAPPED',
`created_by` bigint NOT NULL COMMENT '创建人ID',
PRIMARY KEY (`id`),
KEY `idx_brand_model` (`brand`,`model`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆档案主表';
- 关键设计点:
status字段用枚举值而非布尔型,预留了BOOKED(已预订未付款)、SCRAPPED(报废车源)等业务状态;sell_price允许为空,因为新车常按“指导价+金融方案”报价,实际成交价需签约后填写;idx_brand_model联合索引加速“查某品牌所有在售车型”这类高频查询。
order_master销售订单主表
CREATE TABLE `order_master` (
`id` bigint NOT NULL AUTO_INCREMENT,
`order_no` varchar(50) NOT NULL UNIQUE COMMENT '订单号,格式:CS20240520001',
`customer_id` bigint NOT NULL COMMENT '客户ID',
`salesman_id` bigint NOT NULL COMMENT '销售顾问ID',
`total_amount` decimal(10,2) NOT NULL COMMENT '订单总金额',
`status` varchar(20) NOT NULL DEFAULT 'DRAFT' COMMENT '订单状态:DRAFT/PENDING_APPROVAL/APPROVED/OUTBOUND/COMPLETED',
`approved_by` bigint DEFAULT NULL COMMENT '审批人ID',
`approved_time` datetime DEFAULT NULL COMMENT '审批时间',
PRIMARY KEY (`id`),
KEY `idx_customer_salesman` (`customer_id`,`salesman_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单主表';
- 关键设计点:
order_no采用业务编码规则(CS+年月日+3位流水),便于财务对账;status状态机严格遵循销售流程,从DRAFT(草稿)→PENDING_APPROVAL(待审批)→APPROVED(已审批)→OUTBOUND(已出库)→COMPLETED(已完成),每个状态变更都触发对应业务动作(如APPROVED时自动扣减库存);idx_status索引支撑“查看所有待审批订单”这类运营查询。
financial_summary财务汇总视图表(非物理表,由定时任务计算)
-- 实际通过ScheduledTask每日凌晨2点执行
INSERT INTO financial_summary (date, sales_amount, received_amount, gross_profit)
SELECT
CURDATE(),
IFNULL(SUM(om.total_amount), 0),
IFNULL(SUM(r.amount), 0),
IFNULL(SUM(om.total_amount - c.price * oi.quantity), 0)
FROM order_master om
LEFT JOIN receipt r ON om.id = r.order_id AND r.status = 'CONFIRMED'
LEFT JOIN order_item oi ON om.id = oi.order_id
LEFT JOIN car c ON oi.car_id = c.id
WHERE om.status = 'COMPLETED' AND DATE(om.completed_time) = CURDATE();
- 关键设计点:不依赖实时计算,而是用定时任务生成昨日汇总数据,保障报表查询性能;
gross_profit毛利计算精确到订单明细(c.price * oi.quantity),而非粗略按车型均价估算,符合4S店精细化核算要求。
注意:
carsale.sql中所有COMMENT字段都用中文标注,这是给后续接手的开发者的最大善意。当你在Navicat里右键查看表结构时,鼠标悬停就能看到“status:订单状态,取值DRAFT/PENDING_APPROVAL…”,比翻文档快十倍。
3.2 前后端交互规范:RESTful不是教条,而是业务语义的翻译器
系统严格遵循RESTful原则,但所有接口设计都以销售动作为中心。例如“创建订单”接口:
- 错误示范(CRUD思维):
POST /api/v1/order—— 无法体现业务意图,前端需在请求体里塞一堆状态标记。 - 正确设计(业务动作思维):
POST /api/v1/order/draft→ 创建草稿订单(销售顾问录入初步信息)POST /api/v1/order/{id}/submit→ 提交审批(触发状态变更为PENDING_APPROVAL)POST /api/v1/order/{id}/approve→ 经理审批(状态变更为APPROVED,自动扣库存)POST /api/v1/order/{id}/outbound→ 仓库出库(状态变更为OUTBOUND,生成出库单)
每个接口的HTTP状态码也精准映射业务结果:
- 201 Created:草稿订单创建成功,响应头含Location: /api/v1/order/draft/123
- 409 Conflict:提交审批时检测到库存不足,响应体含{ "error": "INSUFFICIENT_STOCK", "carId": 456, "available": 0, "required": 1 }
- 422 Unprocessable Entity:价格字段校验失败(如sell_price > price),响应体含详细错误字段名
这种设计让前端开发变得极其简单:销售顾问点击“提交审批”按钮,前端只管调用/api/v1/order/123/submit,后端自动处理状态流转、库存扣减、审批流触发。而不用在Vue组件里写一堆if(status==='DRAFT') { callSubmitApi() } else if(status==='PENDING_APPROVAL') { callApproveApi() }的胶水代码。
4. 实操过程与核心环节实现:从零部署到业务跑通的完整链路
4.1 环境准备与一键启动:30分钟内让系统活起来
部署难点从来不在技术,而在环境一致性。这套系统做了三重保障:
- JDK版本锁定:
pom.xml中<java.version>11</java.version>明确指定,避免JDK17新特性导致老服务器编译失败; - MySQL兼容性处理:
application.yml中spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect适配MySQL 8.0+,同时carsale.sql开头添加SET NAMES utf8mb4;解决中文乱码; - 前端构建傻瓜化:
front/package.json里"scripts"包含"dev": "vue-cli-service serve --port 8081",直接npm run dev即可启动热更新开发服务器。
标准部署流程(以CentOS 7为例):
# 步骤1:安装基础环境
sudo yum install -y java-11-openjdk-devel mysql-server nginx
sudo systemctl start mysqld && sudo systemctl enable mysqld
# 步骤2:初始化数据库(注意:密码需按提示修改)
sudo mysql_secure_installation # 设置root密码
mysql -u root -p < carsale.sql # 导入脚本(脚本内已含CREATE DATABASE)
# 步骤3:构建后端(确保JAVA_HOME指向JDK11)
cd carsale && mvn clean package -Dmaven.test.skip=true
java -jar target/carsale-1.0.jar --spring.profiles.active=prod &
# 步骤4:构建前端(需提前安装Node.js 14+)
cd front && npm install && npm run build
sudo cp -r dist/* /usr/share/nginx/html/
# 步骤5:配置Nginx反向代理(/etc/nginx/conf.d/carsale.conf)
upstream backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name sales.yourcompany.com;
location /api/ {
proxy_pass http://backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location / {
try_files $uri $uri/ /index.html;
}
}
sudo nginx -t && sudo systemctl reload nginx
实操心得:我在某县城4S店部署时遇到MySQL 5.7默认
sql_mode含STRICT_TRANS_TABLES,导致INSERT INTO car (...) VALUES (...)因sell_price=NULL报错。解决方案是在/etc/my.cnf中添加sql_mode=NO_ENGINE_SUBSTITUTION并重启MySQL。这个坑已在carsale.sql头部注释里预警,但新手仍易忽略。
4.2 关键业务流程实录:以一笔新能源车订单为例
我们模拟销售顾问小王卖出一台比亚迪海豹DM-i 121KM尊荣型(指导价22.58万元)的全过程:
阶段1:客户登记与车辆查询(前端操作)
- 小王打开http://sales.yourcompany.com/#/customer/create,填写客户张伟的姓名、电话、意向车型(搜索框输入“比亚迪海豹”);
- 前端调用GET /api/v1/car/search?keyword=比亚迪海豹,后端返回3款车型,其中海豹DM-i 121KM尊荣型库存为2台,sell_price为空(表示待议价);
- 小王点击该车型进入详情页,页面底部显示“当前展厅库存:2台 | 近7天咨询量:17次”,辅助决策。
阶段2:创建订单与审批(后端核心逻辑)
- 小王点击“立即下单”,前端提交POST /api/v1/order/draft,请求体含{ "customerId": 889, "carId": 456, "expectedPrice": 218000 };
- 后端OrderController.createDraft()方法执行:
a) 校验客户手机号格式(正则^1[3-9]\d{9}$);
b) 查询car表确认stock_num >= 1且status='IN_STOCK';
c) 插入order_master记录,status='DRAFT',order_no='CS20240520001';
d) 返回201 Created及订单ID;
- 小王填写完全部信息后点击“提交审批”,前端调用POST /api/v1/order/123/submit;
- 后端OrderService.submitForApproval()方法:
a) 检查当前状态是否为DRAFT(防止重复提交);
b) 更新order_master.status='PENDING_APPROVAL';
c) 发送企业微信消息给经理:“张伟订单待审批,请查收”;
d) 记录操作日志到sys_operation_log表。
阶段3:经理审批与出库(权限与事务)
- 经理李总登录系统,进入/order/approve页面,看到待审订单列表;
- 点击订单号CS20240520001,系统展示客户征信报告摘要(对接外部API)、车辆成本价(20.3万元)、预期毛利(1.5万元);
- 李总点击“批准”,前端调用POST /api/v1/order/123/approve;
- 后端OrderService.approveOrder()开启事务:
```java
@Transactional
public void approveOrder(Long orderId) {
// 1. 更新订单状态
OrderMaster order = orderMapper.selectById(orderId);
order.setStatus(“APPROVED”);
order.setApprovedBy(currentUserId);
order.setApprovedTime(LocalDateTime.now());
orderMapper.updateById(order);
// 2. 扣减库存(行锁防超卖)
Car car = carMapper.selectById(order.getCarId());
if (car.getStockNum() < 1) {
throw new BusinessException("库存不足");
}
car.setStockNum(car.getStockNum() - 1);
carMapper.updateById(car); // 此处InnoDB行锁生效
// 3. 生成财务待办事项
FinancialTodo todo = new FinancialTodo();
todo.setOrderId(orderId);
todo.setAmount(order.getTotalAmount());
todo.setType("RECEIPT_CONFIRM");
financialTodoMapper.insert(todo);
}
```
- 事务提交后,库存实时变为1台,财务系统收到待办提醒。
注意:
carsale.sql中car表的stock_num字段类型为INT而非BIGINT,因为单店库存不可能超过21亿台——这种克制的设计,正是资深开发者对业务边界的敬畏。
5. 常见问题与排查技巧实录:那些文档里不会写的“血泪经验”
5.1 高频问题速查表
| 问题现象 | 可能原因 | 排查命令/步骤 | 解决方案 |
|---|---|---|---|
| 前端登录后跳转404 | Nginx未配置history模式回退 | curl -I http://yourdomain.com/api/v1/user/info |
检查Nginx配置中location / { try_files $uri $uri/ /index.html; }是否生效 |
| JWT登录成功但后续接口401 | 后端未正确解析Authorization头 | curl -H "Authorization: Bearer xxx" http://localhost:8080/api/v1/user/info |
检查JwtAuthenticationFilter中request.getHeader("Authorization")是否被网关过滤 |
| 订单审批后库存未扣减 | MySQL事务未生效 | 查看order_master表status是否为APPROVED,再查car表stock_num |
在OrderService.approveOrder()方法首行加log.info("开始审批订单: {}", orderId),确认方法是否执行 |
| ECharts销售看板空白 | 前端未获取到后端数据 | 浏览器F12→Network→筛选XHR,查看/api/v1/report/sales-trend返回 |
检查ReportController.salesTrend()中LocalDateTime.now().minusMonths(6)是否因时区导致日期范围异常 |
5.2 独家避坑技巧
技巧1:MySQL中文乱码的终极解法
不要只改my.cnf的character-set-server=utf8mb4,必须四步齐下:
1. my.cnf中[client]段添加default-character-set = utf8mb4;
2. [mysqld]段添加collation-server = utf8mb4_unicode_ci;
3. 创建数据库时显式指定:CREATE DATABASE carsale DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;;
4. JDBC连接串末尾加?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai。
我在某次部署中因漏掉第4步,导致客户姓名“张伟”存入数据库变成“张?”,排查耗时3小时。
技巧2:Vue路由守卫的权限陷阱router.beforeEach()中判断next({ path: '/login' })时,若用户已登录却因网络抖动丢失token,直接跳转会导致登录页无限重定向。正确做法:
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token')
if (to.meta.requiresAuth && !token) {
// 先尝试刷新token(调用/api/v1/auth/refresh)
api.refreshToken().then(res => {
localStorage.setItem('token', res.data.token)
next({ ...to }) // 重新导航
}).catch(() => next('/login'))
} else {
next()
}
})
技巧3:销售订单状态机的测试策略
不要只写单元测试,必须做状态流转集成测试:
@Test
void testOrderStatusFlow() {
// 1. 创建草稿
Long orderId = createDraftOrder();
// 2. 提交审批(应成功)
assertOrderStatus(orderId, "DRAFT");
submitForApproval(orderId);
assertOrderStatus(orderId, "PENDING_APPROVAL");
// 3. 错误操作:销售员尝试审批(应抛异常)
assertThrows<BusinessException> {
approveOrderAsSalesman(orderId)
}
// 4. 经理审批(应成功并扣库存)
approveOrderAsManager(orderId);
assertOrderStatus(orderId, "APPROVED");
assertCarStockDecreased(orderId); // 断言库存减少
}
这种测试覆盖了90%的业务逻辑漏洞,比单纯测DAO层有效得多。
6. 系统扩展与二次开发指南:如何让它真正长在你的业务土壤里
6.1 快速接入新业务模块的路径
系统预留了清晰的扩展接口,新增一个“保险套餐管理”模块只需5步:
- 数据库:在
carsale.sql末尾添加insurance_package表(含name、premium、validity_months字段); - 后端:在
carsale/src/main/java/com/carsale/entity/下新建InsurancePackage.java,mapper包下建InsurancePackageMapper.java; - 接口:在
controller包新建InsurancePackageController.java,继承BaseController,实现list()、save()方法; - 前端:在
front/src/views/insurance/下新建InsuranceList.vue,调用/api/v1/insurance/list; - 权限:在
sys_menu表插入新菜单项,sys_role_menu表为经理角色分配该菜单ID。
整个过程无需修改现有代码,所有扩展都遵循“开闭原则”。我在为一家二手车商增加“整备费用登记”模块时,就是按此流程,2小时内完成上线。
6.2 性能优化临界点预警
系统在以下规模时需关注性能:
- 单库数据量 > 500万行:将order_master按年份分表(order_master_2024、order_master_2025),修改MyBatis-Plus的@TableName为动态表名;
- 并发用户 > 200人:将financial_summary从定时任务改为实时计算,引入Redis缓存各销售员实时业绩(HINCRBY sales:202405:staff:123 "amount" 218000);
- 车辆型号 > 10000种:为car表的brand、model字段建立全文索引,替换原LIKE '%关键词%'查询。
这些优化点已在README.md的“性能调优建议”章节详细说明,包括SQL改写示例和压测数据对比。
最后分享一个小技巧:当销售顾问抱怨“查客户太慢”时,不要急着加索引。先用
EXPLAIN SELECT * FROM customer WHERE name LIKE '%张%'看执行计划——90%的情况是前端用了模糊查询却没加%通配符位置限制。正确的做法是引导用户输入“张”后,后端执行WHERE name LIKE '张%'(前缀匹配),这样就能命中索引。技术优化永远排在业务引导之后。
简介:直接可用的汽车销售业务管理系统源码,后端基于SpringBoot构建,前端采用Vue实现完全分离架构。系统覆盖客户信息登记与检索、车辆档案维护(含品牌、型号、库存状态、售价等字段)、销售订单全周期操作(从下单、经理审核到出库执行)、销售人员账号及绩效管理、以及基础财务统计(如销售额、回款金额、毛利汇总)。权限体系清晰:销售员可处理客户、车辆和订单;管理员可查看经营报表、管理用户、审批关键流程。压缩包内含完整工程结构——front目录为标准Vue项目(已配Babel、ESLint、PostCSS等开发工具),carsale目录为SpringBoot模块,pom.xml声明全部依赖,src/main/java存放核心业务代码,resources包含application.yml等配置文件,test目录提供单元测试示例;附带carsale.sql数据库初始化脚本,导入即用。项目已集成跨域支持、JWT登录鉴权机制、RESTful风格接口设计,适用于学习前后端协同开发、销售类业务建模、权限控制落地及实际部署流程。
更多推荐


所有评论(0)