news 2026/9/23 12:41:22

JavaWeb二手交易系统源码解析:从Spring Boot到Druid实战改造

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaWeb二手交易系统源码解析:从Spring Boot到Druid实战改造

简介:面向 JavaWeb 期末大作业与课程设计场景的二手闲置物品交易系统完整源码,覆盖用户登录、商品发布/浏览、订单交易等常见业务模块,适合高校学生参考完整工程结构或直接二次开发。压缩包共 352 个文件,约 45.54MB,核心代码包括 39 个 Java 源文件和同名 class 编译文件,104 个 XML 配置/映射文件;前端包含 22 个 HTML、28 个 JS、26 个 CSS 页面样式与交互脚本,另有图片、字体、properties 配置和 Maven 运行脚本等辅助资源,目录清晰,便于定位前后台代码与数据库配置。从应用启动类到控制器、Service 实现类、工具类均有完整链路,数据库连接池等配置内容也可直接借鉴,对期末答辩、课程设计报告编写及 JavaWeb 实战练习都有参考价值。已有 4460 人学习下载,适合需要快速交付期末作业、理解分层开发思路或系统学习 JavaWeb 项目的开发者。

1. 期末周最值的一件事:把二手闲置物品交易系统这份 JavaWeb 源码跑起来再改

如果你这周就要交 javaweb 期末大作业,又不想从零手搓一个 Spring Boot 项目,那这份二手闲置物品交易系统源码就是你的救命稻草。它不是那种只有页面没有逻辑的静态模板,而是带着完整 Java 后端链路可以直接跑的真实项目。里面包含商品管理、用户登录、Druid 连接池、统一返回值处理这类常见期末答辩考点,核心里面还有几乎所有课程设计都要用到的增删改查闭环。适合三类人:一是时间紧想快速交作业的,二是想把别人项目改成自己风格但缺乏参考的,三是想通过读懂一个真实项目来搞懂 Spring Boot + MyBatis 协作方式的。我拆过不少这类源码,这篇把从导入到改代码的完整路径和常见翻车点都写出来。

2. 拆包看架构:从十个 Class 文件名反推技术栈与项目分层

2.1 文件名里藏着技术选型:Spring Boot、MyBatis、Druid 怎么一眼看出来

拿到 zip 后先别急着解压运行,把里面的 class 文件列出来看一遍,项目的技术画像就出来了。这份源码里的关键类名我列成了一张表,每行都指向一个明确的技术决策:

类名职责推断对应技术点
Application.classSpring Boot 启动入口说明是 Spring Boot 工程而非传统 SSM 的 XML 配置方式
GoodController.class / UserController.class商品、用户的 Web 控制层典型 MVC 分层,Controller 只做参数接收和结果返回
GoodsServiceImpl.class / UserServiceImpl.class商品、用户的业务实现层接口 + 实现类的标准 Service 设计
Goods.class / User.class实体映射类对应数据库表结构,字段大概率与表列一一对应
DruidConfig.class数据源配置类使用 Druid 连接池,并且做了自定义配置而不是默认配置
AjaxResult.class统一 JSON 返回体前端通过 Ajax 拿数据,后端封装 code、msg、data 三要素
DateUtil.class日期工具类处理商品发布时间、用户注册时间等格式化逻辑

从这张表你能得到三个关键结论。第一,这是一个前后端不分离的 Spring Boot 单体项目,界面用模板引擎渲染,AjaxResult 说明部分交互走 JSON 接口。第二,数据层用的是 MyBatis,因为 ServiceImpl 这种命名习惯是 MyBatis 项目中非常常见的分层写法。第三,DruidConfig 单独成类,说明不是简单依赖默认数据源,而是手动注册了 Druid 的监控和过滤功能,这也是答辩时老师容易追问的细节。

这里要提醒一句:拿到这种压缩包第一件事不是跑代码,而是先把类清单看一遍。很多同学在 IDEA 里直接双击运行 Application 类,结果因为缺依赖或配置不对反复报错,原因就是你根本不了解这个项目里有什么东西。

2.2 分层设计还原:Controller 到 Service 再到数据库的完整调用链

二手闲置物品交易系统这种规模的项目,代码结构一般遵循标准三层架构。Controller 接收前端请求,调用 Service 接口,ServiceImpl 里写业务逻辑,再通过 MyBatis 的 Mapper 操作数据库。这个项目的类名里没有出现 Mapper 相关类,但你不用慌,这是很多课程设计源码的常规操作——把 Mapper 接口和 XML 文件放在 resources 目录下,class 目录里只会保留编译产物。

看这种项目的代码,建议按照一条业务链路去跟:以发布商品为例,前端表单提交到 GoodsController 的 addGoods 接口,Controller 接收参数后封装成 Goods 对象,调用 GoodsService 的 addGoods 方法,最终落到 GoodsServiceImpl 里完成数据库写入。我拆这类项目时一般会先画出这条链路,再看每个节点的入参和返回,比把每个类从头到尾读一遍效率高得多。

// 反推 GoodsController 核心代码结构 @Controller @RequestMapping("/goods") public class GoodsController { // Spring 的构造器注入,替代 @Autowired 可以提升可测试性 private final GoodsService goodsService; public GoodsController(GoodsService goodsService) { this.goodsService = goodsService; } // 发布商品接口,前端以表单形式提交 @PostMapping("/add") @ResponseBody public AjaxResult add(Goods goods) { boolean success = goodsService.addGoods(goods); return success ? AjaxResult.success() : AjaxResult.error("发布失败"); } // 商品列表接口,支持分页参数 @GetMapping("/list") @ResponseBody public AjaxResult list(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer limit) { return AjaxResult.success(goodsService.getGoodsList(page, limit)); } }

参数说明:page 和 limit 这种分页参数在课程设计里很常用,defaultValue 保证前端不传时不会空指针;@ResponseBody 是关键,它让方法返回 AjaxResult 时被 Jackson 序列化成 JSON 字符串而不是跳转页面。我习惯在 Controller 里尽量用构造器注入,这样单元测试的时候不用启动整个 Spring 容器。

反推逻辑说明:goodsService.addGoods() 内部要做的核心事情就两件——把 Goods 实体里没值的字段补默认值(比如发布时间用 DateUtil 生成当前时间),然后调用 Mapper 写入数据库。很多同学做完新增功能后列表页看不到数据,多半是漏了发布时间赋值,数据库字段非空而实体里是 null,直接抛异常。

2.3 核心表设计:用户表和商品表在二手场景下的字段取舍

看实体类就能大概拼出数据库表结构。用户表通常包含 id、username、password、nickname、phone、avatar、create_time 这些字段;商品表核心是 id、title、description、price、original_price、seller_id、status、create_time。两个表通过 seller_id 建立一对多关系,这就是典型的二手交易模型,一个用户能发布多个商品,一个商品只属于一个用户。

价格字段是这类系统的重点。我见过不少同学在设计时用了 double 或 float,但实际项目里价格用 decimal 更稳妥,否则在计算和展示时容易丢精度。你不需要改这个,但答辩时被问到你得知道。status 字段也要注意,它控制商品状态:0 表示在售,1 表示已下架,2 表示已卖出。这个字段在列表页过滤和详情页按钮展示上起着关键作用。

-- 常见二手商品表结构(字段名与实体类对应) CREATE TABLE goods ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', title VARCHAR(100) NOT NULL COMMENT '商品标题', description TEXT COMMENT '商品描述', price DECIMAL(10, 2) NOT NULL COMMENT '售价', original_price DECIMAL(10, 2) COMMENT '原价', seller_id INT NOT NULL COMMENT '发布者ID', status TINYINT DEFAULT 0 COMMENT '0在售 1下架 2已卖出', create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间', KEY idx_seller (seller_id) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

逻辑说明:TINYINT 做状态位比用 VARCHAR 存字符串性能更好,而且代码里可以用数字判断;create_time 直接给默认值 CURENT_TIMESTAMP 能省掉后端手动赋值,但如果你发现 DateUtil 被使用频繁,大概率这个项目没开默认值而是用了工具类。utf8mb4 是必须的,utf8 在遇到 emoji 表情或生僻字时会报编码错误,这是经典坑。索引只建了 idx_seller,因为查询场景就是按用户查他发布的商品。

3. 三十分钟跑起来:IDEA 导入、数据库脚本与 Druid 配置排查

3.1 环境版本匹配:JDK 8、MySQL 5.7、IDEA 的搭配逻辑

这类 javaweb 项目最稳的运行环境是 JDK 8 + MySQL 5.7 + IDEA 2020 以后任意版本。不要一上来就用 JDK 17 或 MySQL 8,后面可能会碰一鼻子灰。JDK 版本过高会导致 Tomcat 内嵌容器和 Spring Boot 老版本不兼容,最常见报错是 java.lang.NoSuchMethodError 或模块化系统拒绝访问;MySQL 8 则要额外注意驱动名要改成 com.mysql.cj.jdbc.Driver 和时区配置。

我在 IDEA 里导入这种 zip 的流程是:File → New → Project from Existing Sources,然后选中解压后的文件夹,Maven 会自动识别 pom.xml。如果项目没有 pom.xml 而是 lib 目录,那就说明是传统 WEB-INF/lib 方式引入依赖,需要手动添加 Tomcat 运行环境。这份源码里有 Application.class,十有八九是 Maven 管理的 Spring Boot 工程,直接按 Maven 项目导入就行。

导入后第一件事是等 Maven 下载依赖。这里给个血泪经验:千万别傻等,先检查本地仓库和镜像。打开设置里的 Maven 配置,看 user settings 文件指向的本地仓库路径是否存在,如果之前配过阿里云镜像,下载速度会快不少。等依赖下完再写代码,否则一敲代码全是红色报错,心态会崩。

<!-- pom.xml 中关键依赖版本组合参考 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> </parent> <dependencies> <!-- Web 层支持,内嵌 Tomcat --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Thymeleaf 模板引擎,渲染 HTML 页面 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- MyBatis 与 Spring Boot 整合 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!-- Druid 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> <!-- MySQL 驱动,注意 MySQL 8 需要换驱动类名 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies>

逻辑说明:Spring Boot 2.3.x 是当前课程设计项目中最常见的版本,因为和 JDK 8 天生配合好,不像 Spring Boot 3 强制要求 JDK 17。Thymeleaf 负责把后端数据渲染到 HTML,和 AjaxResult 同时存在意味着项目里既有页面跳转也有局部刷新。MyBatis 依赖里要小心版本冲突,如果同时引入了 mybatis-spring-boot-starter 和纯 mybatis 包,启动时会报 mapper 找不到。

3.2 数据库准备:建库脚本执行和 Druid 连接池的参数详解

大多数课程设计源码会在压缩包里附带 sql 文件,一般是 db_secondhand.sql 或者 init.sql 这类命名。如果没带脚本,你可以通过实体类反向建表,但字段类型拿不准会踩坑。我建议先把 zip 里的文件全部解压出来,找 sql 文件优先用脚本;实在找不到再手工建表。

执行脚本要注意字符集问题。我用 Navicat 或命令行执行时,会先手动创建数据库并指定 utf8mb4,再执行脚本里的建表语句。如果直接双击运行 sql 文件,可能会因为脚本里没有 CREATE DATABASE 语句而报 1046 没有选中数据库的错误。执行成功后检查一下表数量,通常只有 user 和 goods 两张表,如果有第三张表,可能是作者自己扩展的功能。

# application.yml 中 Druid 数据源配置 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/secondhand?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 username: root password: "123456" type: com.alibaba.druid.pool.DruidDataSource druid: initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000 stat-view-servlet: enabled: true url-pattern: /druid/* login-username: admin login-password: admin123 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.secondhand.entity

参数说明:driver-class-name 写 com.mysql.cj.jdbc.Driver 是针对 MySQL 8 的写法,如果这个项目用的驱动是 5.x,要改回 com.mysql.jdbc.Driver。url 里 serverTimezone=Asia/Shanghai 是必须的,不写的话 MySQL 8 会报 CST 时区错误。characterEncoding=utf8 解决中文乱码问题,这也是 javaweb 项目完整案例 mysql 里最常被问到的配置项。

Druid 的 initial-size 和 max-active 分别代表初始连接数和最大连接数,课程设计规模 5 和 20 足够。max-wait 是获取连接的超时时间,超过 60 秒会抛异常。这里有个细节:login-username 和 login-password 配置的是 Druid 监控页面的登录账号,默认是 admin/admin123,你如果不想让别人看到你的项目监控数据就改掉。启动成功后访问 http://localhost:8080/druid 可以看连接池实时状态,这是给答辩加分的好素材。

3.3 启动验证:从日志到页面三层确认项目健康

配置完成后启动 Application 类,观察控制台输出的日志。看到 Tomcat started on port(s): 8080 这行日志代表 Web 容器启动成功,看到 Druid 的初始化日志说明数据源没问题。这两个都没报错,才能在浏览器里测试接口。

第一层验证是打开首页。二手交易系统的默认路径一般是 / 或 /index,能看到页面正常渲染说明 Thymeleaf 模板和静态资源加载没问题。第二层验证是测试登录功能,用脚本里的初始账号试一次,能跳转到首页就说明登录链路通。第三层是验证 Druid 监控页,访问 /druid 看 SQL 执行记录,如果你刚才登录了一下,能看到 select 语句被执行,这就是整个链路完整的证据。

如果启动时报错端口被占用,在 idea 运行终端或命令行里用 netstat -ano | findstr 8080 找出占用进程,然后在任务管理器里结束它。如果报错信息里出现 Access denied for user root,说明密码不对,回到 yml 里检查 password 字段。最常见的错误是本地 MySQL 设置了密码但 yml 里还是空。

4. 二次开发实战:把通用模板改造成你自己的期末项目

4.1 页面改造入门:Thymeleaf 模板修改与列表页数据绑定

拿到项目跑通之后,你要做的最重要事情是让它变得像你的作品。大多数老师会抽查代码和页面,如果连页面标题还是原作者的名字,答辩印象分会很受影响。Thymeleaf 模板的修改入口很好找,在 resources/templates 目录下的 HTML 文件里。

以首页为例,先找到 index.html,用 IDEA 打开后你会看到大量 th: 开头的标签。th:text 用于将后端传入的变量渲染成文本,th:each 用于遍历列表。如果你想把商品列表页的默认标题改掉,直接修改标签内容即可。如果你想把页面导航栏的 logo 文字改掉,全局搜索原来的项目名,批量替换成自己的名字。</p> <pre><code class="language-html"><!-- 商品列表页的 Thymeleaf 核心片段 --> <div class="goods-grid" th:each="goods : ${goodsList}"> <div class="goods-card"> <!-- 用 th:href 拼接商品详情页地址 --> <a th:href="@{/goods/detail/{id}(id=${goods.id})}"> <h3 th:text="${goods.title}">默认标题</h3> </a> <!-- 价格格式化,保留两位小数 --> <p class="price" th:text="'¥' + ${#numbers.formatDecimal(goods.price, 1, 2)}">¥0.00</p> <!-- 发布时间由 DateUtil 格式化后直接传入 --> <span class="time" th:text="${goods.createTime}">2024-01-01</span> <!-- 根据商品状态显示不同按钮 --> <button th:if="${goods.status == 0}" class="btn-buy">我想要</button> <button th:if="${goods.status == 1}" class="btn-sold" disabled>已下架</button> </div> </div> </code></pre> <p>逻辑说明:th:each 类似 for 循环,每遍历一个商品生成一个卡片;#{...} 是 Thymeleaf 的内置工具方法,numbers.formatDecimal 处理价格展示,避免出现 19.9 变成 19.900000000001 这种浮点尴尬;th:if 做状态判断。改造页面时我一般保留原有结构和 class,只修改文字和样式,这样不容易引入布局问题。</p> <p>这个项目的 DateUtil 类在时间格式化上起了大作用。默认情况下 Java 的 LocalDateTime 传到 Thymeleaf 会显示成 2024-06-01T15:30:00 这种带 T 的格式,非常丑。DateUtil 将其格式化为 yyyy-MM-dd HH:mm:ss 后,前端展示才符合中文习惯。我建议你能不动这个逻辑就尽量别动,改动不熟练反而影响列表页渲染。</p> <h3>4.2 新增一个举报/留言功能:完全照抄 Goods 这条链路</h3> <p>如果你觉得只是改页面不够,想加个功能体现工作量,那你不需要从零写,照着项目里 Goods 这条现有链路复制再改最快。加功能之前先想清楚模型:我要在现有结构之上扩展,比如在商品详情页加入收藏功能,就需要一张 favorite 表。</p> <p>照着 Goods 的链路加新功能只需要五个文件:实体类 Favorite.java、Mapper 接口 FavoriteMapper.java、Mapper XML 文件 FavoriteMapper.xml、业务类 FavoriteService 和 FavoriteServiceImpl、控制器 FavoriteController.java。这套命名规则在这个项目里已经很清楚了,照着写就行。每个文件的内容都可以拿 Goods 对应文件改动词名即可。</p> <pre><code class="language-java">// 新增的 FavoriteController,结构对齐 GoodsController @Controller @RequestMapping("/favorite") public class FavoriteController { private final FavoriteService favoriteService; public FavoriteController(FavoriteService favoriteService) { this.favoriteService = favoriteService; } // 收藏操作:前端传用户ID和商品ID @PostMapping("/add") @ResponseBody public AjaxResult add(@RequestParam Integer userId, @RequestParam Integer goodsId) { // 先判断是否已收藏,避免重复插入 if (favoriteService.isFavorited(userId, goodsId)) { return AjaxResult.error("已经收藏过了"); } boolean success = favoriteService.addFavorite(userId, goodsId); return success ? AjaxResult.success() : AjaxResult.error("收藏失败"); } // 取消收藏 @PostMapping("/cancel") @ResponseBody public AjaxResult cancel(@RequestParam Integer userId, @RequestParam Integer goodsId) { boolean success = favoriteService.cancelFavorite(userId, goodsId); return success ? AjaxResult.success() : AjaxResult.error("取消失败"); } } </code></pre> <p>逻辑说明:这段代码先查重再插入,防止重复收藏,这是答辩时值得讲的业务细节。@RequestParam 强制前端传参,如果没传会直接报 400,也比在方法里判空更直接。AjaxResult 的统一 code 设计让你在任意接口里返回成功或失败都不用操心 HTTP 状态码。</p> <p>照抄链条时最常翻车的是 Mapper XML 里的 namespace 没改。如果你复制了 GoodsMapper.xml,一定要把 namespace 改成 FavoriteMapper 的全限定名,否则启动时 MyBatis 会报绑定异常。还要注意 XML 里 resultType 要和实体类对应,不要复制时漏改了包名。</p> <h3>4.3 切换远程 MySQL 与修改服务器端口:Druid 配置的两个隐藏细节</h3> <p>有些同学本地没有装 MySQL,或者宿舍两台电脑需要共享同一个数据库,这就涉及把数据源指到远程服务器的问题。改 application.yml 里的 url 地址就行,把 localhost 换成远程 IP。这里有两个细节要注意,都是我这几年看别人翻车总结出来的。</p> <p>第一,远程 MySQL 默认不允许 root 用户从非本机登录,你会看到 Host 'xxx' is not allowed to connect to this MySQL server 报错。在远程服务器上执行 GRANT ALL PRIVILEGES ON <em>.</em> TO 'root'@'%' IDENTIFIED BY '密码' 并执行 FLUSH PRIVILEGES 才能放开限制。第二,云服务器的安全组和防火墙要放行 3306 端口,这一步和环境无关,纯网络层面的问题,排查起来容易忽略。</p> <p>修改端口就更简单了,在 application.yml 里加一行 server.port: 9090 即可。但要注意改了端口后,Druid 监控页的访问地址也要跟着变,还有前端页面里如果写死了 8080 端口请求接口,全部都要改,否则浏览器控制台全是跨域或 404 报错。这种硬编码问题在课程设计里很常见,我建议前端请求一律用相对路径,这样换端口的时候就只改一处。</p> <h2>5. 避坑指南:期末交作业最容易碰上的五个实际问题</h2> <h3>5.1 端口 8080 被占用导致启动失败</h3> <p>现象:启动 Application 类时控制台报 Port 8080 was already in use,Tomcat 起不来。</p> <p>原因:上一个项目没有正常停掉,或者电脑上其他软件占了 8080。最常见的是之前运行过同一个项目但窗口没关,再点一次启动就会冲突。</p> <p>解决:在 IDEA 终端执行 netstat -ano | findstr 8080,看到 LISTENING 状态的 PID,到任务管理器详情页结束对应进程,然后重新运行。如果你频繁切换项目,建议直接把端口改成 8090,规避大部分冲突。</p> <h3>5.2 打开 /druid 监控页面显示 404</h3> <p>现象:项目正常启动,但浏览器访问 http://localhost:8080/druid 返回 404 或者白屏。</p> <p>原因:DruidConfig 里只配置了数据源 Bean,没有注册 StatViewServlet。很多源码的 DruidConfig 类实际上根本没开监控页,就只是个数据源包装。</p> <p>解决:检查 DruidConfig 中是否包含 ServletRegistrationBean 类型的方法,没有的话手动补上,设置 url-pattern 为 /druid/*,并启用 login-username 和 login-password。spring boot 的 yml 里也要确认 stat-view-servlet 的 enabled 为 true,两处缺一不可。</p> <h3>5.3 AjaxResult 返回的数据前端拿到 null</h3> <p>现象:接口用 Postman 测试返回正常,但浏览器页面上数据展示不出来,看 network 面板发现 response 里 data 是 null。</p> <p>原因:前端期望的数据字段名和后端返回的 JSON key 不一致。比如后端返回 goodsList,前端写的是 list;或者是 Goods 实体里字段为 null,Jackson 默认不序列化 null 值,导致整个 data 只剩空壳。</p> <p>解决:在 AjaxResult 的 data 字段上加 @JsonInclude(Include.ALWAYS) 注解,或者让前端改取值字段名,两个方向都行。我自己的习惯是把 AjaxResult 设计成泛型类 AjaxResult<T>,这样返回数据时类型明确,前端取值也少出这种玄学问题。</p> <h3>5.4 商品价格出现 19.999999 这种奇葩结果</h3> <p>现象:数据库查询出来的价格展示在页面上变成 19.9999999999 或者 0.30000000000000004。</p> <p>原因:实体类里 price 字段用的 double,而 double 是二进制浮点,无法精确表达所有十进制小数。这是计算机原理层面的坑,跟你代码逻辑没有关系。</p> <p>解决:把所有涉及金额的字段从 double 改成 BigDecimal,数据库层面保持 decimal 不动。BigDecimal 构造时用字符串构造器 new BigDecimal("19.9"),不要用 new BigDecimal(19.9),后者依然会拿到不精确值。这个坑很容易在答辩时被老师提问,你答出原理会很加分。</p> <h3>5.5 中文乱码问题:页面显示问号或乱码</h3> <p>现象:登录后首页中文标题全部变成 ?? 或 ¤¤ 这类乱码。</p> <p>原因:有三层可能——数据库连接 url 缺 characterEncoding=utf8、IDE 的文件编码不是 UTF-8、数据库表本身是 latin1 字符集。一层没配好就会乱。</p> <p>解决:按顺序排查。首先确认连接 url 里写了 characterEncoding=utf8;然后在 IDEA 中打开 Settings → File Encodings,把所有编码改成 UTF-8;最后检查表结构的 charset,如果是 latin1 就执行 ALTER TABLE goods CONVERT TO CHARACTER SET utf8mb4。这三步走完,乱码问题基本根治。</p> <h2>6. 答辩前夜:三个能让你少被追问的细节处理和演示路径设计</h2> <p>二手交易系统这类项目,答辩时老师最爱问的无非几个点:表结构怎么设计的、登录校验怎么做的、为什么用这个技术栈。其中软删除这个概念值得你提前准备一下。商品表里如果有个 is_delete 或 status 字段表示下架,那这就是软删除的实现。传统 delete 是物理删除,数据没了没法恢复;软删除是逻辑上隐藏,数据还在。用户删除自己发布的商品时,系统其实执行的是 UPDATE 语句把 status 改成 1,而不是 DELETE。这个设计在课程设计里属于亮点,回答时主动说出来老师会很认可。</p> <p>日期处理同样是易考点。DateUtil 这个类的作用是把 LocalDateTime 转成特定格式的字符串,你在答辩时可以主动演示:列表页时间和详情页时间格式一致,是同一个工具类做的。这比每个 controller 里手动 SimpleDateFormat 优雅得多。老师问为什么用工具类而不是直接格式化,你可以答为了复用和统一管理,这正是工程化思维的体现。</p> <p>演示路径建议设计成一条完整业务闭环,总时长控制在三十秒内。先用测试账号登录,然后发布一个商品,填写标题、价格和描述;回到列表页确认新商品出现;点进详情页确认状态正常;最后用另一个账号浏览这条商品。整个流程下来,登录、发布、查询、状态流转全链路都覆盖到了,比东点一下西点一下强得多。</p> <p>演示前建议在浏览器打开开发者工具,把 Network 面板切到 XHR 过滤,这样每次点击操作后,后端返回哪些 JSON 数据都看得清清楚楚。答辩时依据 network 里的每个请求讲后端逻辑,比自己背代码要自然得多,而且显得你对项目链路非常熟悉。我还习惯在演示前关掉 Druid 监控页的登录,或者直接展示监控页面的 SQL 执行列表,让老师直观看到项目跑起来了,这会省去很多解释问题的口舌。</p> <p>最后再叮嘱一句:这台机器在答辩前务必完成一次从 MySQL 到 IDEA 的冷启动测试,拔掉电源重启后再跑一遍完整流程。我一直记得自己那次熬夜改完代码直接去答辩,结果演示时 MySQL 服务没启动,页面全崩,只能看着老师摇头。从那以后我每到交作业或答辩前,都强制自己按冷启动流程完整走一遍,别在最后一步掉链子。希望帮到你。</p> <p> <a href="https://download.csdn.net/download/weixin_55305220/85709915" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>

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

TIN本质:地形建模的底层几何逻辑与工程实践

1. 为什么TIN不是“另一个DEM算法”&#xff0c;而是地形表达的底层逻辑重构你可能在GIS课上听过TIN&#xff0c;也可能在测绘报告里见过“基于TIN插值生成DEM”的表述——但绝大多数人没意识到&#xff1a;TIN本身不是DEM的生成工具&#xff0c;它是DEM的原始形态&#xff1b;…

作者头像 李华
网站建设 2026/9/23 12:41:04

QAM频偏仿真MATLAB代码包解析:从星座图到误码率

简介&#xff1a;这是一份面向通信工程学习者与算法研究人员的QAM调制与频偏估计Matlab源码包。资源围绕4QAM、64QAM、256QAM三种星座图映射展开&#xff0c;包含信号生成、映射调制、判决解调及频偏估计等核心函数&#xff0c;可用于模拟频偏对星座点旋转的影响&#xff0c;并…

作者头像 李华
网站建设 2026/9/23 12:40:21

基于OpenCV与dlib的驾驶员疲劳检测系统:眨眼、哈欠与点头识别

简介&#xff1a;一套基于图像检测的Python驾驶员疲劳识别项目&#xff0c;面向计算机视觉初学者、本科课设或毕业设计人群&#xff0c;用于研究眨眼、打哈欠、瞌睡点头等疲劳行为的自动判定。系统给出了清晰判定阈值&#xff1a;连续三帧内眼睛长宽比达0.2视为眨眼&#xff0c…

作者头像 李华
网站建设 2026/9/23 12:39:55

AI Logo生成器Looka深度评测:从品牌VI到商业授权的完整指南

做品牌Logo这事&#xff0c;以前是“专业选手”的战场&#xff0c;要掏钱找设计公司&#xff0c;来回改稿磨上十天半个月。后来出来一堆在线Logo生成器&#xff0c;又总觉得模板感太重&#xff0c;换个字体颜色就完事&#xff0c;拿不出手。我自己前前后后试了七八款AI设计工具…

作者头像 李华
网站建设 2026/9/23 12:39:39

当代码成为情诗:拆解《world.execute(me);》的程序隐喻与情感循环

这几年有一首歌&#xff0c;我每隔一段时间就会翻出来循环一阵子&#xff0c;就是Mili的《world.execute(me);》。说实话&#xff0c;第一次看到这个歌名时&#xff0c;我以为是某段乱写的程序代码——execute(me)看着就像个函数调用&#xff0c;后面还带分号。后来才反应过来&…

作者头像 李华
网站建设 2026/9/23 12:36:23

5G光模块误码率优化:晶振相位噪声影响与选型设计指南

1. 从一个让人头疼的误码率问题说起搞过5G光模块硬件设计的人大概都有过这种经历&#xff1a;链路预算明明算得绰绰有余&#xff0c;眼图看着也还行&#xff0c;可一上系统跑流量&#xff0c;误码率就是压不下去&#xff0c;偶尔还冒出一两个莫名其妙的突发错误。你换光器件、调…

作者头像 李华