news 2026/9/23 1:07:18

Java垃圾分类管理系统源码与数据库设计实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java垃圾分类管理系统源码与数据库设计实战

简介:面向高校计算机相关专业毕业设计、课程设计与期末大作业场景,这套城市垃圾分类回收管理系统源码数据库整合包,提供从前端页面到后端服务、数据库脚本的完整方案。后端采用 Java 技术栈,前端包含 HTML、CSS、JavaScript,并配有大量 GIF 操作演示,便于理解垃圾分类、回收点管理、用户积分等核心业务逻辑。资源共 218 个文件,包含 52 个 Java 源码、28 个 JS 交互脚本、17 个 HTML 页面、9 个 CSS 样式,同时提供 SQL 数据库脚本与 Maven 配置,压缩包仅 2.43MB,轻量易部署。目前已有 209 人学习下载,适合需要快速搭建高分毕设项目的同学参考。资源中附带 SQL 数据库脚本与 yml 配置文件,源码和静态资源按目录清晰划分,方便导入开发工具二次修改;既可作为毕业设计答辩演示,也能改造成小区垃圾分类监管平台或课程设计作品。

1. 一份Java垃圾分类管理系统源码,压缩包里到底装了什么

拿到“Java城市垃圾分类回收管理系统源码+数据库(毕业设计).zip”这个压缩包,很多人第一反应是解压后直接跑起来看页面。但作为IT从业者,看到这个标题更应该清楚,它代表的是Java Web开发里最典型的一条交付链路:源码、数据库脚本、配置文件打包进一个zip,交给别人部署。系统本身要解决的业务问题很具体:居民知道垃圾该扔进哪个桶,回收人员能接到上门回收订单,后台能看到各小区回收量。技术点也正好覆盖Java基础面试题里高频出现的枚举、事务、关联查询和分页。我按自己跑通同类项目的顺序,用Spring Boot 2.x + MyBatis + MySQL 8.0组合,把解压zip、导入数据库、改参数、验证核心功能的完整路径讲清楚。适合正在做java课程设计或接手遗留源码的开发者。

2. 分解垃圾分类回收管理系统的表结构:从zip里的SQL脚本看数据库设计

系统里真正决定业务边界的是数据库表。很多人在源码里写了一大堆Controller却立不住,因为表结构没有围绕“人-小区-垃圾桶-分类记录-积分”这条主线展开。我一般先看zip里附带的.sql脚本,如果没有单独脚本,就从application.yml里找到mapper目录下的建表语句。以MySQL 8.0为例,表设计会集中在以下七张表:community、garbage_user、trash_bin、waste_category、waste_record、recycle_order、points_log。字符集统一使用utf8mb4,排序规则用utf8mb4_unicode_ci,这样投放备注里的生僻字不会被截断。

2.1 用户、小区与垃圾桶:基础表如何支撑多小区部署

用户体系不需要一上来就接微信登录。毕业设计源码里最常见的是用一个garbage_user表保存手机号、所属小区和积分余额。先用小区把数据隔离起来,再谈角色权限。

CREATE DATABASE IF NOT EXISTS garbage_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE garbage_system; CREATE TABLE community ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', name VARCHAR(64) NOT NULL COMMENT '小区名称', address VARCHAR(128) NOT NULL DEFAULT '' COMMENT '地址', admin_phone VARCHAR(20) DEFAULT NULL COMMENT '负责人电话', longitude DECIMAL(10,6) DEFAULT NULL COMMENT '经度', latitude DECIMAL(10,6) DEFAULT NULL COMMENT '纬度', created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) ENGINE=InnoDB COMMENT='小区表'; CREATE TABLE garbage_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', community_id BIGINT NOT NULL COMMENT '所属小区', open_id VARCHAR(64) DEFAULT NULL COMMENT '微信openid', phone VARCHAR(20) NOT NULL COMMENT '手机号', balance_points INT NOT NULL DEFAULT 0 COMMENT '剩余积分', status TINYINT NOT NULL DEFAULT 1 COMMENT '0禁用 1正常', created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间', KEY idx_community (community_id) ) ENGINE=InnoDB COMMENT='居民用户表'; CREATE TABLE trash_bin ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', community_id BIGINT NOT NULL COMMENT '所属小区', bin_type TINYINT NOT NULL COMMENT '1可回收 2有害 3厨余 4其他', code VARCHAR(32) NOT NULL COMMENT '垃圾桶编号', location_desc VARCHAR(128) DEFAULT NULL COMMENT '位置描述', capacity_kg DECIMAL(8,2) NOT NULL DEFAULT 100.00 COMMENT '额定容量kg', last_clear_time DATETIME DEFAULT NULL COMMENT '最近清运时间', KEY idx_community_type (community_id, bin_type) ) ENGINE=InnoDB COMMENT='垃圾桶表';

建表时的几个参数值得说明:DECIMAL(10,6)存经纬度,计算“附近回收点”时精度足够,同时避免用DOUBLE的浮点误差;手机号字段用VARCHAR(20)而不是BIGINT,因为前端表单可能传进来+86前缀,BIGINT转换会直接报错。垃圾桶表里的bin_type用TINYINT,配合waste_category字典表解释含义,不要直接在业务表里写中文,否则后面做统计和扩展都费劲。

在设计garbage_user时,status字段的默认值必须为1,避免注册逻辑漏设状态导致新用户无法登录。community_id加普通索引就够,不用建唯一索引,因为一个小区可以有多个用户。

2.2 垃圾类别、投放记录与积分流水:核心业务表的关联关系

垃圾分类业务需要四张表相互配合。waste_category是字典表,存四分类;waste_record是事实表,存一次投放行为;points_log是流水表,存积分变动;recycle_order处理上门回收订单。

CREATE TABLE waste_category ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', category_name VARCHAR(16) NOT NULL COMMENT '四分类名', recycle_ratio DECIMAL(4,2) NOT NULL DEFAULT 1.00 COMMENT '积分倍率', icon_url VARCHAR(255) DEFAULT NULL COMMENT '图标地址', sort_no INT NOT NULL DEFAULT 0 COMMENT '排序号' ) ENGINE=InnoDB COMMENT='垃圾类别字典表'; CREATE TABLE waste_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', user_id BIGINT NOT NULL COMMENT '投放人', bin_id BIGINT NOT NULL COMMENT '垃圾桶', category_id BIGINT NOT NULL COMMENT '垃圾类别', image_url VARCHAR(255) DEFAULT NULL COMMENT '现场照片', weight_kg DECIMAL(8,3) NOT NULL COMMENT '投放重量kg', status TINYINT NOT NULL DEFAULT 0 COMMENT '0待审核 1有效 2无效', created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '投放时间', KEY idx_user_time (user_id, created_time), KEY idx_category_time (category_id, created_time) ) ENGINE=InnoDB COMMENT='垃圾投放记录表'; CREATE TABLE points_log ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', user_id BIGINT NOT NULL COMMENT '用户', record_id BIGINT NOT NULL COMMENT '关联业务记录', change_points INT NOT NULL COMMENT '变动值', points_type TINYINT NOT NULL COMMENT '1投放奖励 2兑换扣减 3签到', remark VARCHAR(128) DEFAULT NULL COMMENT '备注', created_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '变动时间', KEY idx_user (user_id) ) ENGINE=InnoDB COMMENT='积分流水表';

这组表结构的核心在索引。idx_user_time让投递记录的“用户+时间”范围查询走索引,后台查询“某用户最近一个月扔了多少次”时不会全表扫描;idx_category_time用来支持按类别汇总,统计可回收物回收量时直接按category_id分组。points_log里的record_id虽然关联waste_record,但并不建外键约束,这是MySQL在线业务里常见做法:保留逻辑关联,避免外键带来的插入锁开销。如果要恢复数据,可以用JOIN查询,但分页时先查主表再关联流水,避免驱动表太大。

每个分类的回收积分如何定,建议在waste_category里增加recycle_ratio字段而不是硬编码。比如厨余垃圾积分倍率0.5,可回收物1.0,有害垃圾0,这样后台运营人员可以通过一个数据库更新操作调整规则,而不需要改代码重新部署。

2.3 初始化数据SQL:让页面启动后有内容可看

只有空表结构,系统登录后什么都看不到。一个可演示的数据库至少要有四类垃圾字典、一个小区、两个测试用户和几条投放记录。初始化脚本如下:

INSERT INTO waste_category (category_name, recycle_ratio, sort_no) VALUES ('可回收物', 1.00, 1), ('有害垃圾', 0.00, 2), ('厨余垃圾', 0.50, 3), ('其他垃圾', 0.20, 4); INSERT INTO community (name, address) VALUES ('锦绣小区', '滨河路128号'); INSERT INTO garbage_user (community_id, phone, balance_points, status) VALUES (1, '13800001111', 100, 1), (1, '13900002222', 20, 1); INSERT INTO waste_record (user_id, bin_id, category_id, weight_kg, status) VALUES (1, 1, 1, 2.500, 1), (2, 2, 3, 1.200, 1);

初始化参数说明:有害垃圾的倍率设为0,因为这类垃圾不应给居民积分,避免系统被误用成积分刷分入口。测试账号的密码字段没有在上面的INSERT里出现,因为生产环境应该用BCrypt存储,开发阶段可以先使用固定的加密串,不要在SQL里直接写明文密码。这里故意只写了少量初始化记录,后续测试分页和统计时再通过业务接口造数据,这样能验证新增逻辑是否真的写入数据库。

插入完成后,用一条统计SQL检查数据能否正确关联:

SELECT c.category_name, COUNT(r.id) AS cnt, ROUND(SUM(r.weight_kg), 2) AS total_kg FROM waste_record r JOIN waste_category c ON r.category_id = c.id GROUP BY c.category_name;

这条SQL把投递记录按类别分组,统计条数和总重量,是垃圾分类管理后台最常用的查询之一。如果返回结果为空,先检查waste_record里是否有外键连接错误。关联查询时,注意表别名要清晰,避免在后期增加join条件时出现字段歧义。

3. 从zip解压到Spring Boot启动:把数据库和源码真正跑通

拿到压缩包后先别急着双击,很多问题都出在解压阶段。标题里的.zip既是分发格式,也是最容易被忽略的故障点。常见做法是:在Linux上使用unzip命令,在Windows上使用7-Zip或自带资源管理器,但无论用哪种方式,解压后要立刻检查目录层次,避免出现“压缩包里套同名文件夹”的情况,那会让后续的路径配置全部偏移。

3.1 解压zip并识别项目类型

先执行下面的命令,把项目解压到单独目录:

unzip "Java城市垃圾分类回收管理系统源码+数据库(毕业设计).zip" -d garbage-system cd garbage-system ls -la

参数说明:-d指定解压目标目录,防止文件散落在当前目录;ls -la可以看到项目根目录内容。如果unzip命令提示“command not found”,在Debian系系统上执行apt install unzip安装,在CentOS上执行yum install unzip。Windows环境没有unzip命令,可以把7-Zip的7z.exe加入PATH,然后使用7z x 文件名.zip -ogarbage-system。无论用哪种方式,目标目录应直接出现pom.xml或build.gradle,如果有classes目录和SQL脚本但没有pom.xml,说明这是一份只编译未打包的产物,后续需要先还原项目结构。

常见的项目结构长这样:

garbage-system/ ├── pom.xml ├── src/main/java/com/garbage/ ├── src/main/resources/application.yml ├── src/main/resources/mapper/*.xml ├── sql/garbage_system.sql └── README.md

从这个结构能看出项目基于Maven管理依赖,数据库脚本独立放sql目录,Mapper XML和配置文件都在resources下。如果script目录出现的是.sql和.db文件并存,不要直接复制.db文件,数据库文件是二进制格式,和本机MySQL版本可能不匹配,正确做法是只导入.sql脚本。

3.2 检查JDK、Maven和MySQL版本是否匹配

在运行之前,把环境变量配置检查一遍。很多java课程设计项目在运行时报ClassNotFoundException或UnsupportedClassVersionError,都是版本不匹配造成的。

java -version mvn -v mysql --version

版本匹配的参考组合见下表:

组件推荐版本常见问题
JDK8 / 11JDK 17跑Spring Boot 2.x会有兼容问题
Maven3.6.3+老版本无法下载新版依赖
MySQL5.7 / 8.08.0需要显式指定时区和驱动
Spring Boot2.7.x与JDK 8搭配最稳

参数说明:JDK 8是Spring Boot 2.x最主流的运行环境;如果本机同时装了多个JDK,在IDEA里Project Structure切到对应版本,在命令行用JAVA_HOME指定路径。MySQL 8.0默认认证插件是caching_sha2_password,老版驱动连接时会报Public Key Retrieval is not allowed,需要把驱动升级到mysql-connector-java 8.0.33以上,同时在JDBC URL中加allowPublicKeyRetrieval=true。

查看项目的Spring Boot版本可以执行:

mvn help:evaluate -Dexpression=project.parent.version -q -DforceStdout

输出显示的版本号会直接决定JDK选择。如果显示3.x,本机必须安装JDK 17;如果是2.x,JDK 8或11都能用。

3.3 导入数据库脚本与修改数据源参数

数据库结构已经在前一章建好。如果zip里的sql脚本自带建库语句,直接执行:

mysql -u root -p -f < sql/garbage_system.sql

参数说明:-f表示遇到SQL错误继续执行,适合首次导入时跳过重复建表错误。如果脚本里没有CREATE DATABASE语句,需要手动先建库,再把sql文件导进去。导入后立刻检查表数量和字符集:

USE garbage_system; SHOW TABLES; SELECT @@character_set_database;

如果查询结果里所有中文都是问号,说明导入时客户端字符集不对。重新执行导入并指定字符集:

mysql -u root -p --default-character-set=utf8mb4 < sql/garbage_system.sql

然后修改项目的application.yml。绝大多数源码都通过Spring Boot的配置文件读取数据库连接,位置在src/main/resources/application.yml:

spring: datasource: url: jdbc:mysql://localhost:3306/garbage_system?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.garbage.entity logging: level: com.garbage.mapper: DEBUG

这里的参数值得逐项说明:characterEncoding=utf8mb4保证中文正常读写;serverTimezone=Asia/Shanghai防止JDBC与MySQL时区不一致导致时间字段偏移8小时;useSSL=false跳过本地环境无用的加密握手,减少警告。multipart段控制文件上传大小,垃圾分类系统里的现场照片通常在3MB以内,10MB足够。mybatis.mapper-locations指定XML文件位置,如果路径写错,启动时只会报“Invalid bound statement”,不看到这一层很容易去翻Java代码。

生产环境不要直接把密码写进yaml,用环境变量覆盖是更安全的做法:

SPRING_DATASOURCE_PASSWORD=你的密码 mvn spring-boot:run

Spring Boot启动时会读取这个环境变量并覆盖yaml中的默认值,这样配置文件可以提交到仓库,而密码只保留在部署机器上。

3.4 使用Maven打包并启动应用

数据库导入成功后,就可以编译启动。最小步骤是:

mvn clean package -DskipTests java -jar target/garbage-system-0.0.1-SNAPSHOT.jar --server.port=8080

参数说明:clean先删除旧target目录,package把项目打成可执行jar包,-DskipTests跳过测试减少环境干扰。如果项目里使用了Lombok,要确保JDK版本与Lombok版本兼容,否则编译会报“java: package lombok does not exist”,这时需要在pom.xml里把lombok.version升级到支持当前JDK的版本。启动日志出现“Started XxxApplication in xx seconds”后,用浏览器访问http://localhost:8080。

在服务器上部署时,通常把日志重定向到文件并放到后台运行:

nohup java -jar target/garbage-system-0.0.1-SNAPSHOT.jar > app.log 2>&1 &

nohup让java进程不随SSH会话断开而退出;> app.log把控制台输出写入文件;2>&1把错误输出也合并到同一个文件。等两分钟后,查看app.log,如果看到“Tomcat started on port(s): 8080”,系统已启动完毕。如果端口被占用,改用--server.port=8081或者修改配置文件。检查端口监听状态可以用:

ss -lntp | grep 8080

这一步能快速确认端口是否真的被Java进程监听。Windows环境下即使启动成功也没有页面,大概率是防火墙拦截了8080端口,在控制面板入站规则里放行即可。

4. 核心业务实现:垃圾分类识别、积分扣减与接口验证

数据库和启动跑通后,真正要改代码时才需要重点看业务逻辑。这个系统里的垃圾分类识别和积分扣减是两端最容易出问题的地方。我在写类似系统时,会先定义枚举和接口,再实现Service,少写if else,避免功能越加越乱。

4.1 用枚举替代if else完成垃圾类别识别

“报纸是什么垃圾?塑料瓶是什么垃圾?”这类需求如果在Controller里用if判断,后面加一个分类就要改一次代码。更常见且好维护的做法是把类别定义成枚举,配合关键词集合做匹配。

public enum WasteCategory { RECYCLABLE(1, "可回收物", Arrays.asList("报纸", "塑料瓶", "玻璃瓶", "易拉罐")), HAZARDOUS(2, "有害垃圾", Arrays.asList("电池", "温度计", "油漆桶")), KITCHEN(3, "厨余垃圾", Arrays.asList("剩饭", "菜叶", "果皮")), OTHER(4, "其他垃圾", Arrays.asList("卫生纸", "陶瓷碎片")); private final Integer code; private final String name; private final List<String> keywords; WasteCategory(Integer code, String name, List<String> keywords) { this.code = code; this.name = name; this.keywords = keywords; } public Integer getCode() { return code; } public String getName() { return name; } public static Integer matchByName(String keyword) { if (keyword == null || keyword.isBlank()) { return OTHER.getCode(); } for (WasteCategory category : WasteCategory.values()) { for (String item : category.keywords) { if (keyword.contains(item) || item.contains(keyword)) { return category.getCode(); } } } return OTHER.getCode(); } }

逻辑说明:枚举里的keywords只保留了演示用的少量垃圾名词,实际项目建议把关键词放进数据库字典表,方便后台运营在线维护。matchByName方法先用空值判断兜底,再遍历每个类别的关键词,用双向contains判断,是为了兼容用户输入“一个塑料瓶”和“塑料瓶”都能命中。注意:isBlank是JDK 11才有的方法,如果项目编译目标是JDK 8,应改用keyword.trim().isEmpty(),否则javac会直接编译失败。这里的降级返回OTHER,保证前端收到的是一个合法类别code。

在Service里调用枚举,并同时插入一条投放记录:

@Service public class WasteRecordService { @Resource private WasteRecordMapper wasteRecordMapper; @Transactional(rollbackFor = Exception.class) public Integer submitWasteRecord(Long userId, Long binId, String keyword, BigDecimal weightKg) { Integer categoryCode = WasteCategory.matchByName(keyword); WasteRecord record = new WasteRecord(); record.setUserId(userId); record.setBinId(binId); record.setCategoryId(categoryCode); record.setWeightKg(weightKg); record.setStatus(0); wasteRecordMapper.insert(record); return categoryCode; } }

@Transactional(rollbackFor = Exception.class)在这里是必须的,insert过程中如果数据库连接断开或主键冲突,整个方法会回滚,不会给用户留下一条残废记录。只写@Transactional可能回滚不掉CheckedException,这也是Java面试题里经常追问的知识点。wasteRecordMapper.insert使用MyBatis生成的主键回填,insert后record.getId()就是新的主键值,后面记录积分流水时需要用到。

4.2 积分扣减的乐观锁写法与积分流水记录

回收预约订单通常需要扣减积分或用积分兑换礼品。如果直接SELECT余额然后在Java里扣减,再UPDATE回去,在并发请求下会出现超扣。常见做法是把余额判断放进UPDATE语句的WHERE条件中,用数据库行锁保证原子性。

Mapper方法:

@Update("UPDATE garbage_user SET balance_points = balance_points - #{points} " + "WHERE id = #{userId} AND balance_points >= #{points}") int deductPoints(@Param("userId") Long userId, @Param("points") Integer points);

这条SQL的执行逻辑是:只有用户剩余积分不小于扣减数时才会更新,否则受影响行数为0。扣减成功后,再插入一条积分流水:

@Service public class PointsService { @Resource private UserMapper userMapper; @Resource private PointsLogMapper pointsLogMapper; @Transactional(rollbackFor = Exception.class) public boolean deductIfEnough(Long userId, Integer points, Long orderId) { int rows = userMapper.deductPoints(userId, points); if (rows == 0) { return false; } PointsLog log = new PointsLog(); log.setUserId(userId); log.setRecordId(orderId); log.setChangePoints(-points); log.setPointsType(2); log.setRemark("回收预约积分抵扣"); pointsLogMapper.insert(log); return true; } }

参数说明:deductPoints返回的rows是数据库更新的行数,不是积分余额。rows == 0时直接return false,表示本次扣减无效,调用方可以在Controller里返回“积分不足”。在同一个事务里,先UPDATE后INSERT,能保证余额与流水的最终一致性。如果先INSERT流水再UPDATE余额,一旦余额不足,流水虽然可以删除,但在高并发下容易留下痕迹。注意不要在扣减前再执行一次SELECT余额做判断,因为两次请求之间数据可能已经变化,还是以UPDATE的影响行数为准。

4.3 分页查询与接口验证:用Swagger或Postman快速跑通

源码里如果只有零散的HTTP接口,项目很难交付。建议统一接口风格,把查询参数包装成对象:

@RestController @RequestMapping("/api/waste") public class WasteRecordController { @Resource private WasteRecordService wasteRecordService; @GetMapping("/list") public PageResult<WasteRecord> list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size, Long userId) { return wasteRecordService.pageQuery(page, size, userId); } }

分页使用PageHelper时有一句话要记住:PageHelper.startPage必须紧跟在要分页的查询语句前,不能间隔其他数据库操作。错误示范是startPage后先执行了用户查询,再执行投放记录查询,分页会把两次查询都拦截,导致返回List的size不对。

public PageResult<WasteRecord> pageQuery(Integer page, Integer size, Long userId) { PageHelper.startPage(page, size); List<WasteRecord> records = wasteRecordMapper.selectByUserId(userId); PageInfo<WasteRecord> pageInfo = new PageInfo<>(records); return PageResult.of(pageInfo); }

PageInfo的total来自MyBatis的COUNT查询,和List.size()是两回事。在返回给前端时,total一定要用PageInfo.getTotal(),否则前端无法正常渲染总页数。

系统启动后,使用Postman或直接浏览器验证这几个接口:

接口方法请求参数预期返回
/api/waste/listGETpage=1&size=10&userId=1投放记录分页
/api/waste/submitPOSTbinId=1&keyword=塑料瓶&weightKg=0.8返回垃圾分类code=1
/api/points/deductPOSTuserId=1&points=10&orderId=1001true或false
/api/points/logGETuserId=1&page=1&size=10积分流水列表

如果submit接口返回的code是1,说明“塑料瓶”命中了可回收物枚举;如果返回4,则检查枚举里是否正确设置了keywords,以及请求参数是否带有不可见字符。验证时可以在application.yml里把日志级别调成DEBUG,看到MyBatis打印的SQL参数,就能定位是数据库问题还是业务逻辑问题。

5. 交付用来演示的细节:乱码检查、zip伪加密与最终打包

跑通只是第一步,让系统“拿给别人也能正常运行”需要再做几件事。这部分的技巧不是代码功能,而是工程习惯。我把它们按检查顺序放在最后,每条都能在五分钟内验证。

5.1 用一条curl命令验证接口编码和健康状态

启动后用curl发起请求,如果返回的中文变成\uXXXX的转义序列,说明Jackson序列化配置没有强制UTF-8。在application.yml中增加:

spring: http: encoding: force: true

再验证一次:

curl -s "http://localhost:8080/api/waste/list?page=1&size=10" | head -c 200

看到中文正常显示,就说明编码链路通了。如果数据库里的中文都正常,但接口返回乱码,通常是JDBC URL缺少characterEncoding=utf8mb4,或者Tomcat默认字符集不是UTF-8。

5.2 识别zip伪加密和压缩包异常

很多人收到源码zip后,双击竟然要求输入密码,而README没有写密码,这很可能是“zip伪加密”现象。ZIP格式在文件头的通用位标记里有一位表示加密,伪加密是这一位置被修改为1,实际数据并没有真正加密。在Linux下查看zip详情:

zipinfo -v 文件名.zip | grep -i "encrypt"

如果输出显示“file encryption: none”,但解压时仍提示输入密码,说明这是伪加密,可以用7-Zip打开并选中文件,如果右侧显示“Encrypted”为灰色,即可确认。常见做法是使用zip工具修复目录或重新压缩。需要说明的是,这里讨论的是压缩包格式异常,不是破解密码;遇到真正加密的zip,正确做法是联系交付方获取密码。类似问题也常出现在数据库同步软件生成的包中,来源不明的数据库文件建议先隔离环境再导入。

5.3 调整HikariCP连接池参数

源码里的默认连接池参数可能不适合演示机器。在并发演示时,如果频繁报“Connection is not available, request timed out”,需要调整连接池配置:

spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000

maximum-pool-size控制最大连接数,本地演示一般20足够;connection-timeout是获取连接的超时时间,单位毫秒,30000表示30秒内拿不到连接就报错;idle-timeout是空闲连接存活时间,超过后被回收。调试时如果启动很慢,建议把minimum-idle调小到1,避免空闲连接占用MySQL进程。

5.4 制作规范的zip交付包

最后一步是重新打包,把编译产物和本机日志排除在外:

zip -r final_submission.zip . -x "target/*" -x ".git/*" -x "*.log" -x "*.db"

参数说明:-x后面依次排除target目录、git元数据、日志文件和数据库文件。这样生成的新压缩包里只保留源码、SQL脚本和配置文件。打包完成后,把它解压到另一个干净目录,删除本地target目录,再执行mvn spring-boot:run验证一遍。如果这次能正常起来,说明交付包不依赖环境残留文件。

更稳妥的做法是在zip里放入README.md,注明JDK版本、MySQL版本、数据库账号和默认管理员密码。这样做能避免拿到zip的人反复猜测配置。最后把生成的zip重命名成“Java城市垃圾分类回收管理系统源码+数据库(毕业设计).zip”时,要注意压缩包内不要包含绝对路径,例如“C:\Users...”这类信息,否则在另一台机器解压会看到一大堆空目录。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/22 22:17:59

LangChain智能体开发:从ReAct原理到生产级Agent落地

1. 为什么“智能体开发”不是写个函数调用就完事&#xff1f;——从一个被反复删改的 demo 说起我第一次用 LangChain 写出能“自主思考”的 Agent 时&#xff0c;兴奋地发到技术群&#xff0c;结果被一位做工业智能体的老哥直接点破&#xff1a;“你这叫 Chain&#xff0c;不叫…

作者头像 李华
网站建设 2026/9/22 22:15:11

汇川DDR伺服驱动系统调试实战:参数整定与定位精度提升指南

简介&#xff1a;汇川DDR伺服驱动系统用户手册&#xff08;简易版&#xff09;是一份面向自动化设备调试与维护工程师的技术资料&#xff0c;系统讲解ISMT系列DDR电机与DDR伺服驱动器的安装、通讯、调试及安全注意事项&#xff0c;适用于TP设备、半导体制造、贴片机、激光设备及…

作者头像 李华
网站建设 2026/9/22 22:09:01

SD.Next API 批量出图:3 条命令跑完 100 张

SD.Next API 批量出图&#xff1a;3 条命令跑完 100 张 【免费下载链接】automatic SD.Next: All-in-one WebUI for AI generative image and video creation, captioning and processing 项目地址: https://gitcode.com/GitHub_Trending/au/automatic 板块一 定位与场…

作者头像 李华