又是一年毕设季。很多同学后台私信我:课设选题想做一个能拿得出手、答辩有亮点、后端技术又不至于太复杂的项目,到底做什么好?说实话,JavaWeb 方向的校园二手交易平台是综合性价比很高的选择——功能贴近真实业务、技术栈覆盖 JSP/Servlet/MySQL/JDBC 这些课程核心考点、代码量适中,既能体现工程能力,又不会像 SpringCloud 微服务那样压得人喘不过气。
本文将围绕这个项目做一次完整拆解。不管你是拿它做课程设计,还是准备毕业设计,都可以参考这套从数据库设计、分层代码实现到 IDEA 运行部署的完整流程。我会给出核心模块的源码片段、建表 SQL、运行步骤,以及课设答辩中容易踩的坑。
适合的读者:
- 正在做 JavaWeb 课设、毕设选题的同学。
- 学完 JSP/Servlet 但缺少完整项目串联的初学者。
- 想在 IDEA 中从零跑通一个 JavaWeb 项目的开发者。
1. 项目背景与核心概念
1.1 校园二手交易平台是什么
校园二手交易平台的业务定位很清晰:面向高校在校生,解决教材、数码产品、生活用品等闲置物品的流转问题。学生在平台上发布自己不需要的二手商品,其他同学浏览、咨询、下单购买,实现站内交易闭环。
从课程设计角度,这类项目之所以受欢迎,原因是它的业务模型非常“标准”——包含用户、商品、订单三个核心实体,围绕这三个实体可以自然延伸出发布、下架、购买、订单管理、个人信息维护等功能。业务复杂度适中,不会像电商平台那样涉及支付、库存、物流,但又能完整串起 JavaWeb 的核心知识点。
1.2 项目功能模块拆分
一个基础但完整的校园二手交易平台,通常包含以下功能模块:
| 模块 | 功能点 | 说明 |
|---|---|---|
| 用户模块 | 注册、登录、退出、个人信息修改 | 需要处理重复用户名、密码加密 |
| 商品模块 | 商品发布、商品列表、商品详情、商品下架 | 支持按分类筛选和关键词搜索 |
| 订单模块 | 购买商品、订单列表、订单详情 | 简化交易流程,不做购物车也能闭环 |
| 会话管理 | 登录拦截、Session 存取 | 确保未登录用户不能购买和发布 |
如果希望项目更有亮点,可以增加图片上传、分页查询、分类统计这些进阶功能。但要注意,课设项目的核心是“跑得通、讲得清”,不建议一开始就堆太多功能。
1.3 为什么选择 JavaWeb 实现
JavaWeb 是很多高校 Java 课程体系的中段内容,它不依赖过于复杂的框架,能让人清楚地看到一次 HTTP 请求从浏览器到 Servlet 再到数据库的完整过程。相比直接上手 Spring Boot,用 JSP + Servlet + JDBC 做出来的项目更便于在答辩时讲解底层原理,也更容易对应课本上的知识点。
当然,如果你的课程要求必须使用 SSM 或 Spring Boot,也可以在理解本文业务设计的基础上替换技术实现。业务表结构和分层思想是通用的。
2. 环境准备与版本说明
在开始写代码之前,先把开发环境梳理清楚。这里给出的版本是常见教学环境,你可以根据自己的实际情况调整,核心是保证思路一致。
| 工具 | 推荐版本 | 说明 |
|---|---|---|
| JDK | JDK 8 或 JDK 11 | 向下兼容性好,Tomcat 支持稳定 |
| IDEA | IntelliJ IDEA 2023 或更高 | 社区版即可完成课设 |
| Tomcat | Tomcat 8.5 或 Tomcat 9 | 对应 Servlet 3.1 / 4.0 |
| MySQL | MySQL 5.7 或 MySQL 8.0 | 注意驱动版本的差异 |
| Maven | Maven 3.6+ | 用来管理依赖,也可以用传统 lib 方式 |
| 数据库连接驱动 | mysql-connector-java 5.1.49 或 8.0.x | 不同版本驱动类名不同 |
这里特别说明一下,如果你使用的是 MySQL 8.0,JDBC 驱动的类名是com.mysql.cj.jdbc.Driver,同时在 JDBC URL 中需要加上serverTimezone=Asia/Shanghai参数,否则会报时区错误。
2.1 推荐项目目录结构
使用 Maven 构建时,推荐按以下结构组织项目。如果你不习惯 Maven,也可以在 WEB-INF/lib 下手动放入 mysql-connector-java.jar、jstl.jar,效果是等价的。
campus-secondhand/ ├── pom.xml └── src/main/ ├── java/com/campus/ │ ├── dao/ // 数据访问层 │ ├── entity/ // 实体类 │ ├── service/ // 业务逻辑层 │ ├── servlet/ // 控制器层 │ └── util/ // 工具类 ├── resources/db.properties └── webapp/ ├── WEB-INF/ │ ├── web.xml │ └── jsp/ // JSP 页面 ├── css/ ├── js/ └── index.jsp3. 数据库设计与实现
数据库设计是课设项目最容易得分也最容易扣分的部分。一个严格的评审老师通常会先看表结构是否合理、字段是否冗余、主外键关系是否清晰。
3.1 核心数据表结构
本项目设计了 4 张核心表:用户表、商品分类表、商品表、订单表。
3.1.1 用户表t_user
CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(100) NOT NULL COMMENT '密码(MD5加密)', `nickname` varchar(50) DEFAULT NULL COMMENT '昵称', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `qq` varchar(20) DEFAULT NULL COMMENT 'QQ号', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';这里要注意两个细节:
username设置唯一索引,防止重复注册。password字段长度设置为 100,而不是常见的 32 位。这是为将来升级成加盐加密留出空间。如果只用 MD5,32 位确实够,但从工程习惯上讲,多留一些长度没有坏处。
3.1.2 商品分类表t_category
CREATE TABLE `t_category` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '分类ID', `name` varchar(50) NOT NULL COMMENT '分类名称', `sort` int(4) DEFAULT '0' COMMENT '排序号', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='商品分类表';3.1.3 商品表t_goods
CREATE TABLE `t_goods` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '商品ID', `title` varchar(100) NOT NULL COMMENT '商品标题', `description` text COMMENT '商品描述', `price` decimal(10,2) DEFAULT '0.00' COMMENT '价格', `cover_image` varchar(255) DEFAULT NULL COMMENT '商品图片路径', `category_id` int(11) DEFAULT NULL COMMENT '分类ID', `seller_id` int(11) NOT NULL COMMENT '发布者ID', `status` int(1) DEFAULT '0' COMMENT '状态: 0在售 1已售 2下架', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间', PRIMARY KEY (`id`), KEY `idx_category` (`category_id`), KEY `idx_seller` (`seller_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='商品表';status字段是商品状态的核心标记,通过 0/1/2 区分在售、已售和下架,可以避免物理删除数据造成外键关联问题。
3.1.4 订单表t_order
CREATE TABLE `t_order` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单ID', `order_no` varchar(32) NOT NULL COMMENT '订单编号', `goods_id` int(11) NOT NULL COMMENT '商品ID', `buyer_id` int(11) NOT NULL COMMENT '买家ID', `seller_id` int(11) NOT NULL COMMENT '卖家ID', `price` decimal(10,2) NOT NULL COMMENT '成交价格', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='订单表';订单表保存了买家 ID 和卖家 ID,这样同一个订单详情页面可以根据登录用户身份显示“我买到的”或“我卖出的”。order_no使用业务编号而不是数据库自增 ID,更接近真实项目习惯。
3.2 初始化分类数据
为了让项目跑起来之后有数据可看,需要在t_category中插入几条分类数据:
INSERT INTO `t_category` (`name`, `sort`) VALUES ('教材书籍', 1); INSERT INTO `t_category` (`name`, `sort`) VALUES ('数码电器', 2); INSERT INTO `t_category` (`name`, `sort`) VALUES ('生活用品', 3); INSERT INTO `t_category` (`name`, `sort`) VALUES ('运动器材', 4); INSERT INTO `t_category` (`name`, `sort`) VALUES ('其他', 5);4. 项目搭建与核心代码实现
4.1 创建 Maven Web 项目
在 IDEA 中创建项目的步骤如下:
- 打开 IDEA,选择
New Project。 - 左侧选择
Maven,勾选Create from archetype,选择maven-archetype-webapp。 - 填写
GroupId为com.campus,ArtifactId为campus-secondhand。 - 点击
Finish后等待 Maven 下载依赖。
然后在pom.xml中补充依赖:
<dependencies> <!-- Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- JSP --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- MySQL 驱动,8.0.33 对应 MySQL 8.x --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> </dependencies>注意:javax.servlet-api和javax.servlet.jsp-api的 scope 是provided,因为 Tomcat 本身已经包含这些类库。如果设置为默认的compile,在打包部署时可能引发包冲突。
4.2 JDBC 工具类实现
数据访问层我们采用原生 JDBC,配合一个简单的工具类管理连接和资源释放。这样做不是为了炫技,而是为了让你在答辩时能把DriverManager、Connection、PreparedStatement、ResultSet这些概念讲清楚。
// 文件路径:src/main/java/com/campus/util/DBUtil.java package com.campus.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBUtil { private static final String URL = "jdbc:mysql://localhost:3306/campus_secondhand?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8"; private static final String USERNAME = "root"; private static final String PASSWORD = "123456"; static { try { // MySQL 5.x 使用 com.mysql.jdbc.Driver // MySQL 8.x 使用 com.mysql.cj.jdbc.Driver Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } public static void close(ResultSet rs, Statement stmt, Connection conn) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }这里有个建议:开发课设时可以直接把数据库账号密码写在工具类里,但要在答辩时主动说明——正式项目应当将配置外置到db.properties或环境变量中,这是安全意识的体现。
4.3 用户注册与登录实现
用户模块是整个项目的基础,也是逻辑比较完整的入门模块。以注册为例,需要经历的步骤是:
- 前端表单收集用户名和密码。
- Servlet 接收请求参数。
- 调用 Service 层,先检查用户名是否已存在。
- 密码做 MD5 加密后再保存到数据库。
- 跳转到登录页面。
4.3.1 用户实体类
// 文件路径:src/main/java/com/campus/entity/User.java package com.campus.entity; import java.util.Date; public class User { private Integer id; private String username; private String password; private String nickname; private String phone; private String qq; private Date createTime; // getter 和 setter 省略,使用快捷键生成 }4.3.2 注册 Servlet
// 文件路径:src/main/java/com/campus/servlet/RegisterServlet.java package com.campus.servlet; import com.campus.entity.User; import com.campus.service.UserService; import com.campus.service.impl.UserServiceImpl; import com.campus.util.MD5Util; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/register") public class RegisterServlet extends HttpServlet { private UserService userService = new UserServiceImpl(); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); String nickname = req.getParameter("nickname"); if (username == null || username.trim().isEmpty() || password == null || password.trim().isEmpty()) { req.setAttribute("msg", "用户名和密码不能为空"); req.getRequestDispatcher("/register.jsp").forward(req, resp); return; } User user = new User(); user.setUsername(username); user.setPassword(MD5Util.md5(password)); user.setNickname(nickname); boolean result = userService.register(user); if (result) { resp.sendRedirect(req.getContextPath() + "/login.jsp"); } else { req.setAttribute("msg", "用户名已存在,请更换"); req.getRequestDispatcher("/register.jsp").forward(req, resp); } } }4.3.3 MD5 工具类
// 文件路径:src/main/java/com/campus/util/MD5Util.java package com.campus.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Util { public static String md5(String input) { if (input == null || input.isEmpty()) { return ""; } try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(input.getBytes()); StringBuilder sb = new StringBuilder(); for (byte b : digest) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("MD5 加密失败", e); } } }这里要提醒一下:MD5 本身不够安全,实际项目中应当使用BCrypt或加盐哈希。但作为课设项目,MD5 可以用于演示加密思想,答辩时能说出它的缺陷和改进方案,反而是加分项。
4.4 商品发布功能实现
商品发布是本项目的业务核心。用户在发布页面填写商品标题、描述、价格、分类,并选择一张图片作为封面。图片上传的处理逻辑在 Servlet 中使用@MultipartConfig注解实现文件上传。
// 文件路径:src/main/java/com/campus/servlet/PublishGoodsServlet.java package com.campus.servlet; import com.campus.entity.Goods; import com.campus.entity.User; import com.campus.service.GoodsService; import com.campus.service.impl.GoodsServiceImpl; import com.campus.util.UploadUtil; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; import java.io.IOException; import java.math.BigDecimal; @WebServlet("/publishGoods") @MultipartConfig(maxFileSize = 1024 * 1024 * 5) public class PublishGoodsServlet extends HttpServlet { private GoodsService goodsService = new GoodsServiceImpl(); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); User loginUser = (User) req.getSession().getAttribute("loginUser"); if (loginUser == null) { resp.sendRedirect(req.getContextPath() + "/login.jsp"); return; } String title = req.getParameter("title"); String description = req.getParameter("description"); String priceStr = req.getParameter("price"); String categoryIdStr = req.getParameter("categoryId"); // 图片上传 Part coverPart = req.getPart("coverImage"); String coverPath = UploadUtil.saveImage(coverPart, req); Goods goods = new Goods(); goods.setTitle(title); goods.setDescription(description); goods.setPrice(new BigDecimal(priceStr)); goods.setCategoryId(Integer.parseInt(categoryIdStr)); goods.setSellerId(loginUser.getId()); goods.setCoverImage(coverPath); goods.setStatus(0); goodsService.publishGoods(goods); resp.sendRedirect(req.getContextPath() + "/goodsList"); } }4.5 商品列表分页查询
商品列表页是一个系统里访问量最高的页面。为了方便演示分页实现,可以在GoodsDao中增加如下方法:
// 文件路径:src/main/java/com/campus/dao/GoodsDao.java(关键片段) public List<Goods> findPage(int offset, int limit, Integer categoryId, String keyword) { List<Goods> list = new ArrayList<>(); StringBuilder sql = new StringBuilder( "SELECT * FROM t_goods WHERE status = 0 "); List<Object> params = new ArrayList<>(); if (categoryId != null) { sql.append(" AND category_id = ? "); params.add(categoryId); } if (keyword != null && !keyword.trim().isEmpty()) { sql.append(" AND title LIKE ? "); params.add("%" + keyword + "%"); } sql.append(" ORDER BY create_time DESC LIMIT ?, ?"); params.add(offset); params.add(limit); // 执行查询并封装结果 // ... return list; }分页的核心思路是LIMIT offset, limit,offset通过(当前页码 - 1) * 每页条数计算。JSP 端通过 JSTL 标签循环展示商品卡片,这里不再赘述。
4.6 购买流程实现
购买流程的设计重点是事务控制。因为购买商品需要同时完成两件事:
- 创建订单记录。
- 将商品状态从“在售(0)”改为“已售(1)”。
如果不使用事务,一旦第二步失败,就会出现“订单已创建但商品还在售”的数据不一致问题。
// 文件路径:src/main/java/com/campus/service/impl/OrderServiceImpl.java(关键片段) @Override public boolean createOrder(Order order) { Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); // 1. 校验商品状态,防止重复购买 String checkSql = "SELECT status FROM t_goods WHERE id = ? FOR UPDATE"; // 执行查询,如果 status != 0 则抛出异常回滚 // 2. 插入订单 String insertOrder = "INSERT INTO t_order(order_no, goods_id, buyer_id, seller_id, price) VALUES(?,?,?,?,?)"; // 执行插入 // 3. 更新商品状态 String updateGoods = "UPDATE t_goods SET status = 1 WHERE id = ?"; // 执行更新 conn.commit(); return true; } catch (Exception e) { if (conn != null) { try { conn.rollback(); } catch (Exception ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { if (conn != null) { try { conn.setAutoCommit(true); conn.close(); } catch (Exception e) { e.printStackTrace(); } } } }这里用到了SELECT ... FOR UPDATE对商品行加锁,目的是防止两个用户同时抢购同一件商品。这个细节非常值得在答辩时展开讲解,它展示了你对并发场景的思考。
5. IDEA 配置与项目运行
5.1 配置 Tomcat
在 IDEA 中运行 JavaWeb 项目,需要先把 Tomcat 集成进来:
- 点击 IDEA 顶部工具栏的
Add Configuration。 - 点击
+,选择Tomcat Server→Local。 - 在
Application server中点击Configure,选择本地 Tomcat 安装目录。 - 选择
Deployment页签,点击+添加Artifact,选择war exploded。 - 修改
Application context为/campus。 - 点击
Apply后启动。
注意:IDEA 的社区版不支持 Tomcat 集成,如果你使用的是社区版,需要安装Smart Tomcat插件,或者使用maven tomcat7-maven-plugin插件,也可以用免费版 IDEA 配合外部 Tomcat 启动。
5.2 初始化数据库
在 MySQL 中执行前面给出的建表 SQL,然后执行初始化分类数据 SQL。可以用命令行、Navicat 或 IDEA 自带的 Database 工具。
建议在测试阶段时,用INSERT语句手动添加 2 到 3 个测试用户和 5 到 6 件商品数据,方便调试列表页和详情页。
5.3 运行验证
启动项目后,访问以下功能验证项:
- 访问注册页面
http://localhost:8080/campus/register.jsp,注册一个新账号。 - 用新账号登录,进入后台发布商品。
- 访问首页商品列表,确认新发布的商品出现在列表中。
- 换个账号登录,进入商品详情页,点击购买,确认订单生成且商品状态变为“已售”。
- 退出登录后直接访问发布商品 URL,确认被拦截到登录页。
6. 常见问题与排查思路
JavaWeb 项目运行过程中,新手最容易遇到以下几类问题。这里整理成表格方便快速定位:
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| Tomcat 启动失败,提示端口占用 | 8080 端口被其他程序占用 | 修改 Tomcat 端口,或结束占用进程 |
| 访问项目返回 404 | Artifact 配置错误 | 检查 Deployment 中 Artifact 是否已添加 |
数据库连接报ClassNotFoundException | MySQL 驱动没有导入 | 确认 Maven 依赖存在,或 jar 已在 WEB-INF/lib |
| 数据库连接报时区错误 | JDBC URL 缺少时区参数 | 在 URL 后添加serverTimezone=Asia/Shanghai |
| 页面中文乱码 | 请求或响应编码不一致 | 请求设置req.setCharacterEncoding("UTF-8"),响应设置resp.setContentType("text/html;charset=UTF-8"),同时确保数据库连接 URL 带characterEncoding=utf8 |
| JSP 中 JSTL 标签不生效 | 缺少 jstl jar | Maven 添加jstl依赖,或手动放入 lib |
| 发布商品时图片上传失败 | @MultipartConfig未添加,或目录没有写权限 | 确认 Servlet 上有@MultipartConfig注解 |
6.1 一个典型的 404 排查流程
如果项目启动后访问任何页面都报 404,不要慌,按下面的顺序排查:
- 看 IDEA 控制台中 Tomcat 是否成功启动了
Deployment。如果显示Deployment is not available,说明 Artifact 没有构建成功,执行Build→Build Artifacts→Rebuild。 - 确认访问路径是否包含
Application context。如果你设置的 context 是/campus,那访问地址必须是http://localhost:8080/campus/xxx。 - 检查
web.xml中是否配置了欢迎页或 Servlet 映射。
大多数 404 都是路径问题,把 IDEA 控制台启动日志中INFO级别里Deployment of web application directory后面的路径和浏览器地址对比一下,很快就能定位。
7. 课设答辩加分点与最佳实践
很多同学项目做完了,但在答辩时不知道讲什么。这里结合我的经验,给你一份“答辩讲解主线”和“高分实践建议”。
7.1 如何讲解项目架构
答辩时不要一上来就打开代码逐行念。建议按照下面这条主线来讲解:
- 业务流程:先描述清楚用户从注册到下单的完整业务闭环。
- 技术架构:说明项目采用 JSP + Servlet + JDBC 的三层架构,分别是哪三层。
- 数据库设计:展示 4 张表的关系,解释为什么订单表要同时存
buyer_id和seller_id,为什么商品表要用status字段而不是直接删除。 - 核心功能实现:挑出购买功能的事务处理、分页查询的 SQL 写法、登录拦截器的判断逻辑,每个功能讲清楚“思路-代码-效果”。
- 遇到的问题:主动说你在开发中遇到过什么问题、怎么排查的,这往往是加分项。
7.2 编码规范建议
课设项目代码量虽然不大,但编码规范是否到位,老师一眼就能看出来。
- 包名统一使用
com.campus.xxx这种反域名方式。 - 类名使用大驼峰,方法名和变量名使用小驼峰。
- Dao、Service、Servlet 分层清晰,不要把所有逻辑都堆在 Servlet 里。
- SQL 关键字统一大写,字段名统一小写下划线风格,保持整齐。
- 常量不要硬编码在业务代码中,比如商品状态
0、1、2可以抽成GoodsStatus常量类。
7.3 生产环境注意事项
虽然这是一个课设项目,但在项目文档和答辩陈述中体现出工程意识,会明显拉开与其他同学的差距:
- 数据库密码不要写在代码中明文暴露在公开仓库,应当通过
db.properties配置并加入.gitignore。 - 所有数据库操作结束后必须在
finally中释放资源,否则在高并发场景下会出现连接泄漏。 - 上传文件时要做类型和大小的校验。本项目只允许图片格式,最大 5MB。如果没有校验,恶意用户可以上传 JSP 木马文件,导致服务器被攻击。
- 登录密码在数据库中以密文存储,不能存明文。即使你用 MD5 不够安全,也要比明文好得多。
- 正式部署时,不要使用 Tomcat 默认的管理端账号密码,应当修改或禁用管理端。
8. 项目扩展方向
如果你的课设要求更高,或者你想在这个项目基础上做出更亮眼的毕设,可以考虑以下几个扩展方向:
| 扩展方向 | 技术要点 | 复杂度 |
|---|---|---|
| 图片批量上传 | 使用Part循环处理,生成缩略图 | 中等 |
| 商品搜索增强 | 按标题、描述模糊查询,增加分类和价格区间组合筛选 | 低 |
| 收藏功能 | 增加t_favorite表,关联用户和商品 | 低 |
| 站内私信 | 增加t_message表,实现买卖双方沟通 | 中等 |
| 登录验证码 | 引入 Kaptcha 生成验证码图片 | 低 |
| 管理员后台 | 增加管理员角色,实现用户禁用、商品审核 | 较高 |
| 密码加盐加密 | 使用BCryptPasswordEncoder替换 MD5 | 低 |
推荐优先做“收藏功能”和“验证码”。这两个功能实现难度不大,但一个能丰富业务交互,一个能体现安全性考虑,答辩时都有话可讲。
9. 源码结构与课件使用说明
如果你拿到的课程资料包含源码和课件,建议按下面的步骤使用,而不是直接运行:
- 阅读课件中的需求分析和数据库设计部分,理解每个表的用途。
- 在本地手动执行建表 SQL,然后运行项目源码,对照源码理解每个功能的实现方式。
- 找一个核心功能(比如购买商品)打断点调试,观察变量在每一步的变化。
- 尝试独立实现一个扩展功能(比如收藏),把源码先放一边。
- 将项目重命名,改写部分页面样式和文案,作为自己的课设提交。
这一步很重要:每年都有很多学生因为“项目雷同”被判定为雷同作业或学术不端。只有在别人的源码基础上,通过自己的理解“写”出一遍,才是真正属于自己的东西。
10. 避坑指南与最终建议
在过去辅导过的课设项目中,最影响项目得分的往往不是功能多少,而是下面这些看似不起眼的问题。这里集中提醒一下:
- 不要使用过新的技术版本:比如 JDK 17 + Tomcat 10 + Servlet 5,很多网上的代码会不兼容,尤其是
javax.servlet包名变成jakarta.servlet后,旧代码会有大量报错。课设项目追求稳定,JDK 8 + Tomcat 9 组合足够。 - 严格区分功能优先级:先把注册、登录、发布、列表、详情、购买这条主线跑通,再去做页面美化和辅助功能。主线没跑通,其余都是零。
- 事先规划测试数据:准备一套“故事线”测试数据,比如一个学长账号发布三本书、一个新生账号买走其中一本。答辩时用这套数据演示,逻辑清晰、效果直观。
- 不要忽视项目文档:即使代码完成度高,如果缺少需求分析、数据库设计、核心功能说明等文档,评分也会打折扣。
如果你正在做这个选题,不用追求功能的大而全,把一条核心业务链做扎实,讲清楚每一个设计决策背后“为什么”,分数一定低不了。