简介:这是一套面向高校学生与Java初学者的销售评价系统完整项目资源,适用于毕业设计、课程设计及自学实战场景。项目以Java语言实现,围绕商品与服务评价管理展开,涵盖评价数据记录、后台管理及报表分析等模块,帮助读者理解从需求设计到编码落地的完整开发流程。压缩包共389个文件,约53.74MB,包含19个java源码文件、19个class编译文件、76个xml配置、66个js与22个html前端页面,以及gif、png等界面素材和3个mp4演示视频,另附数据库文档与部署源码,结构清晰便于按模块查阅。目前已有34人学习下载。读者可借助演示视频直观了解系统功能与界面设计,通过部署视频完成本地环境搭建,结合数据库文档掌握后端表结构设计思路,并对照源码学习控制器、实体类与前端交互的实现方式,是提升Java开发与软件工程实践能力的实用参考。
1. 从一份能跑起来的 Java 销售评价系统说起:演示视频、部署视频、数据库文档、部署源码到底各管什么
很多同学做课程设计或接私活时,最头疼的不是写不出增删改查,而是把一堆文件丢给老师或客户后,对方一句「跑不起来」就把你打回原形。基于 Java 的销售评价系统这类项目,真正值钱的不是代码行数,而是那套能让别人独立复现的交付物:演示视频证明功能闭环,部署视频证明环境可搭,数据库文档证明表结构可查,部署源码证明能二次开发。这四样东西凑齐,才算一个能拿得出手的完整作品。它适合计算机专业做课程设计的学生、刚入行的 Java 后端,以及需要快速交付小型评价模块的独立开发者。下面我按「先讲清系统骨架,再动手把环境跑通,最后把坑填平」的顺序,把整套方案拆开讲。
2. 销售评价系统的技术选型与数据库设计:为什么用 Spring Boot + MyBatis 而不是裸 Servlet
2.1 分层架构怎么切:Controller、Service、Mapper 各管什么
一个销售评价系统的核心业务其实就三块:订单完成后触发评价、用户提交评分与文字、后台按商品或销售员聚合评分。业务不复杂,但如果不分层,后期加一个「评价审核」功能就会牵一发动全身。我一般用 Spring Boot 做骨架,Controller 只负责参数校验和返回封装,Service 写业务规则(比如同一订单只能评价一次),Mapper 只做数据库读写。这样切的好处是,面试时被问到「java怎么保证数据一致性」,你可以直接拿评价提交这个场景讲:订单状态更新和评价插入放在同一个@Transactional方法里,任何一步失败都回滚。
@Service public class ReviewServiceImpl implements ReviewService { @Autowired private ReviewMapper reviewMapper; @Autowired private OrderMapper orderMapper; // 提交评价:订单状态校验 + 评价落库,同一事务 @Override @Transactional(rollbackFor = Exception.class) public void submitReview(Long orderId, Long userId, int score, String content) { Order order = orderMapper.selectById(orderId); if (order == null || !order.getUserId().equals(userId)) { throw new BizException("订单不存在或不属于当前用户"); } if (order.getStatus() != OrderStatus.FINISHED.getCode()) { throw new BizException("订单未完成,不能评价"); } // 唯一索引兜底,防止重复评价 Review review = new Review(); review.setOrderId(orderId); review.setUserId(userId); review.setScore(score); review.setContent(content); reviewMapper.insert(review); } }这段代码的关键点有三个:@Transactional的rollbackFor必须写Exception.class,否则遇到受检异常不回滚;订单归属校验放在最前面,避免越权评价;重复评价靠数据库唯一索引兜底,而不是只靠 Java 判断,因为并发下先查后插有窗口期。参数上score建议限制在 1 到 5,content长度在数据库层用VARCHAR(500)卡住,别等到前端传超长文本才报错。
2.2 数据库文档里必须写清的 5 张表与字段约束
数据库文档不是把建表语句贴上去就完事,它要能让接手的人不看代码就知道数据怎么流转。销售评价系统最少需要用户表、商品表、订单表、评价表、销售员表。下面这张表是我一般会写进文档的核心字段说明,重点看约束和索引。
| 表名 | 关键字段 | 类型 | 约束/索引 | 说明 |
|---|---|---|---|---|
| t_user | id, username, password | BIGINT, VARCHAR(50) | 主键,username 唯一 | 密码存 BCrypt 哈希 |
| t_product | id, name, price | BIGINT, VARCHAR(100), DECIMAL(10,2) | 主键 | price 用 DECIMAL 不用 FLOAT |
| t_order | id, user_id, product_id, status | BIGINT, TINYINT | user_id 普通索引 | status 0 待付款 1 已完成 |
| t_review | id, order_id, user_id, score, content | BIGINT, TINYINT, VARCHAR(500) | order_id 唯一索引 | 唯一索引防重复评价 |
| t_salesman | id, name, region | BIGINT, VARCHAR(50) | 主键 | region 用于按区域聚合 |
这里有个血泪经验:t_review的order_id一定要加唯一索引,而不是普通索引。我见过有人只靠 Service 层判断,结果压测时同一订单插进去两条评价,后台统计直接翻倍。另外score用TINYINT就够,别用INT浪费空间。数据库文档里还要写清字符集用utf8mb4,否则用户输入 emoji 会报错,这个坑在评价系统里特别常见。
2.3 评价聚合查询怎么写才不拖垮数据库
后台要看「每个销售员的平均分」和「每个商品的评价数」,如果每次都用SELECT AVG(score) FROM t_review WHERE ...实时算,数据量上万后就会明显变慢。常见做法是加一张汇总表t_review_stat,在评价提交后异步更新,或者用定时任务每十分钟刷一次。如果项目规模小,直接实时查也行,但要在t_review的product_id和salesman_id上建联合索引。
-- 按商品聚合评分,走 product_id 索引 SELECT product_id, COUNT(*) AS cnt, AVG(score) AS avg_score FROM t_review WHERE create_time >= DATE_SUB(NOW(), INTERVAL 30 DAY) GROUP BY product_id ORDER BY avg_score DESC LIMIT 20;这条 SQL 的create_time条件是为了避免全表扫描,配合product_id索引能快速缩小范围。参数上LIMIT 20是防止后台一次拉太多,实际项目里应该加分页。如果发现Using temporary; Using filesort,说明排序没走索引,可以考虑把avg_score冗余到汇总表里。
3. 把部署源码跑起来:从 JDK 安装到数据库文档落地的完整命令
3.1 环境准备:JDK、Maven、MySQL 的版本对齐
部署视频里最容易翻车的地方就是版本不对齐。我一般锁定 JDK 8 或 JDK 17 这两个 LTS 版本,Spring Boot 2.7 配 JDK 8,Spring Boot 3.x 配 JDK 17。如果你看到java: 警告: 源发行版 17 需要目标发行版 17,说明pom.xml里的java.version和本机 JDK 不一致,改一处就行。MySQL 用 5.7 或 8.0 都可以,但 8.0 的驱动类名是com.mysql.cj.jdbc.Driver,5.7 是com.mysql.jdbc.Driver,写错就报ClassNotFoundException。
# 检查 JDK 版本,必须是 8 或 17 java -version # 检查 Maven 是否可用 mvn -v # 登录 MySQL,创建数据库并导入文档里的建表语句 mysql -u root -p CREATE DATABASE sales_review DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE sales_review; source /path/to/database_doc.sql;这几条命令的顺序不能乱:先确认 JDK 和 Maven,再建库导表。utf8mb4字符集必须显式指定,否则默认的latin1会让中文评价变成乱码。导入 SQL 时如果报Unknown command '\'',多半是文件编码不是 UTF-8,用file -i database_doc.sql查一下,转成 UTF-8 再导。
3.2 配置文件里必须改的 4 个参数
部署源码里的application.yml通常留了占位符,直接跑会连不上数据库。下面这 4 个参数是每次部署都要检查的,我一般做成清单贴在部署视频开头。
spring: datasource: url: jdbc:mysql://localhost:3306/sales_review?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 5MB max-request-size: 10MBserverTimezone=Asia/Shanghai不加的话,插入时间会差 8 小时,评价时间显示错乱。max-file-size是评价晒图功能的上传限制,默认 1MB 太小,改成 5MB 比较合理。密码不要写明文提交到仓库,本地用application-dev.yml并加进.gitignore。如果启动报Access denied for user,先确认 MySQL 用户权限,8.0 默认不允许 root 远程登录,本地跑一般没问题。
3.3 打包与启动:一条命令验证部署是否成功
环境配好后,用 Maven 打包再启动,比在 IDE 里点运行更接近生产。打包命令要跳过测试,否则数据库没连上时测试会先失败。
# 跳过测试打包,生成可执行 jar mvn clean package -DskipTests # 启动应用,指定生产配置 java -jar target/sales-review-1.0.0.jar --spring.profiles.active=prod # 验证接口是否通,返回 JSON 即成功 curl http://localhost:8080/api/review/list?productId=1-DskipTests在部署视频里一定要强调,很多新手卡在测试用例连不上库。启动后看日志里有没有Started Application in X seconds,有就说明 Spring 容器起来了。curl返回 404 的话,检查server.port和context-path是否被改过。如果返回 500,看日志里的Caused by,八成是数据库字段和实体类对不上。
4. 演示视频与部署视频怎么录才有说服力:避开 3 个常见翻车点
4.1 演示视频的脚本结构:从登录到评价闭环
演示视频不是把功能点一遍就完事,它要证明「这个系统能解决真实问题」。我一般按这个顺序录:先登录一个普通用户,展示订单列表;然后点进一个已完成订单,提交评分和文字评价;接着切到后台账号,展示评价列表和按商品聚合的评分;最后展示数据库里确实多了一条记录。全程控制在 3 到 5 分钟,不要加速,让看的人能跟上。录之前把测试数据准备好,别现场造数据,容易卡壳。
4.2 部署视频的关键帧:环境检查、导库、改配置、启动
部署视频的价值在于「别人照着做能复现」。关键帧必须包含:java -version的输出、MySQL 建库导表的完整过程、application.yml改动的特写、mvn package的成功输出、java -jar启动后的日志。我见过有人录部署视频时把密码打码,结果看的人不知道要改哪里,这种就是无效交付。密码可以用占位符,但要在视频里说清「这里换成你自己的密码」。另外录屏分辨率别太低,命令行字体调到 16 号以上,否则看的人要眯眼。
4.3 数据库文档的交付格式:SQL 文件加字段说明表
数据库文档最好给两份:一份是可直接执行的.sql文件,一份是 Markdown 或 Word 的字段说明表。SQL 文件里包含建库、建表、索引、初始数据;说明表里写清每个字段的含义、类型、约束和示例值。这样接手的人既能一键导入,又能快速理解结构。如果项目要求交课程设计报告,把字段说明表直接贴进报告的数据设计章节,比截图 ER 图更清晰。
5. 避坑与排查:销售评价系统部署时最容易踩的 5 个坑
5.1 现象:启动报Table 'sales_review.t_review' doesn't exist,原因:数据库文档没导入或导入了错误的库
这个坑几乎每个新手都会踩。现象是应用启动时 MyBatis 报找不到表,或者第一次调接口时抛SQLSyntaxErrorException。原因通常是只建了库没导表,或者导入时没USE sales_review,表建到了默认库里。解决办法是先执行SHOW TABLES;确认当前库里有 5 张表,没有就重新source一遍 SQL 文件。导入前先USE sales_review;,别依赖客户端默认选中的库。
5.2 现象:评价提交后中文变问号,原因:连接串没加characterEncoding=utf8或库字符集不是 utf8mb4
现象是数据库里存进去的中文显示成???,或者前端返回乱码。原因是 JDBC 连接串缺characterEncoding=utf8,或者建库时用了默认字符集。解决办法是连接串加上useUnicode=true&characterEncoding=utf8,建库语句用DEFAULT CHARACTER SET utf8mb4。已经建好的库可以用ALTER DATABASE sales_review CHARACTER SET utf8mb4;补救,但表里的旧数据可能已经损坏,需要重新导入。
5.3 现象:同一订单能提交两次评价,原因:只靠 Service 判断,没加唯一索引
现象是用户快速点两次提交按钮,数据库里出现两条相同order_id的评价。原因是 Service 层的「先查后插」在并发下有窗口期,两个请求都查到「没有评价」,然后都插入。解决办法是在t_review的order_id上加唯一索引,插入时捕获DuplicateKeyException并返回友好提示。前端也要加按钮防抖,但后端唯一索引才是最后一道防线。
5.4 现象:打包后启动报no main manifest attribute,原因:pom 里没配 spring-boot-maven-plugin
现象是java -jar时报no main manifest attribute, in xxx.jar。原因是pom.xml里缺少spring-boot-maven-plugin,打出来的 jar 不是可执行 jar。解决办法是在build节点里加上这个插件,重新mvn package。如果用的是多模块项目,插件要放在启动模块的 pom 里,不是父 pom。
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>5.5 现象:部署视频里能跑,换台机器就报端口占用,原因:8080 被占或配置没改
现象是启动日志报Port 8080 was already in use。原因是本机 8080 被其他程序占用,或者部署视频里改了端口但源码里没同步。解决办法是用netstat -ano | findstr 8080(Windows)或lsof -i:8080(Mac/Linux)找到占用进程,要么杀掉,要么在application.yml里把server.port改成 8081。部署视频里最好演示一次改端口的过程,让看的人知道遇到冲突怎么办。
6. 进阶技巧:用 Java POI 把评价数据导出成带图表的 Word 报告
6.1 为什么选 POI 而不是直接导 Excel
后台运营经常要一份「本月销售评价汇总」的 Word 报告,里面要有表格和评分分布图。有人问 java poi word 能生成图表吗,答案是能,但比 Excel 麻烦。POI 操作 Word 用的是 XWPF 组件,图表需要插入 OOXML 的绘图 XML,代码量大。我的习惯是:表格用 POI 直接生成,图表先用 JFreeChart 生成图片,再作为图片插入 Word。这样代码简单,兼容性也好。
// 用 XWPF 生成评价汇总表格 XWPFDocument doc = new XWPFDocument(); XWPFTable table = doc.createTable(1, 3); table.getRow(0).getCell(0).setText("商品名称"); table.getRow(0).getCell(1).setText("评价数"); table.getRow(0).getCell(2).setText("平均分"); List<ReviewStat> stats = reviewMapper.selectStatLast30Days(); for (ReviewStat stat : stats) { XWPFTableRow row = table.createRow(); row.getCell(0).setText(stat.getProductName()); row.getCell(1).setText(String.valueOf(stat.getCount())); row.getCell(2).setText(String.format("%.1f", stat.getAvgScore())); } // 插入 JFreeChart 生成的评分分布图 XWPFParagraph paragraph = doc.createParagraph(); XWPFRun run = paragraph.createRun(); try (InputStream pic = new FileInputStream("score_chart.png")) { run.addPicture(pic, XWPFDocument.PICTURE_TYPE_PNG, "score_chart.png", Units.toEMU(400), Units.toEMU(250)); } try (FileOutputStream out = new FileOutputStream("review_report.docx")) { doc.write(out); }这段代码的逻辑是:先建一个 1 行 3 列的表头,再按查询结果逐行追加。Units.toEMU把像素转成 Word 的 EMU 单位,400x250 大约是一张半页宽的图。参数上selectStatLast30Days对应前面说的聚合查询,String.format("%.1f")保证平均分只保留一位小数。注意addPicture的流要在 try-with-resources 里关闭,否则文件句柄泄漏,Windows 上会删不掉临时文件。
6.2 导出报告的验证方法与性能边界
生成后一定要打开 Word 确认三件事:表格行数是否和数据库一致、图片是否清晰、中文是否乱码。如果图片模糊,把 JFreeChart 的setWidth和setHeight调大,比如 800x500,再插入时缩小显示。性能上,POI 生成 1000 行以内的表格没问题,超过 5000 行建议改成分页导出或直接导 Excel,因为 XWPF 在内存里构建整个文档,行数太多会 OOM。我一般会在导出接口加个@Async,避免阻塞主线程,导出完成后发站内信通知下载。
6.3 我踩过的坑与固定习惯
最后说个我自己的教训:早期做导出时没加@Transactional(readOnly = true),结果导出过程中有人提交了新评价,导出的数据前后不一致。后来我固定习惯,所有报表查询都加只读事务,并且导出前先flush一次。另外 POI 的版本要和poi-ooxml对齐,别一个 4.1.2 一个 5.2.2,否则报NoSuchMethodError。这套销售评价系统看起来简单,但把部署、文档、视频、导出都做扎实,就是一个能拿得出手的完整项目。希望帮到你。
本文还有配套的精品资源,点击获取