ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Java+JSP校园二手交易平台实战:从环境搭建到部署上线

Java+JSP校园二手交易平台实战:从环境搭建到部署上线 简介这份资源是面向计算机相关专业学生与项目实战学习者的校园二手物品交易平台完整设计与实现包采用Java语言与JSP技术构建基于MVC设计模式划分模型、视图与控制器三层结构适合用作毕业设计、期末大作业或课程设计参考。压缩包共1305个文件约22.74MB其中128个java源文件与119个jsp页面构成系统主体364个js、146个css及大量png、gif、jpg等静态资源支撑前端交互与界面展示另含2个sql脚本、2个doc文档及properties配置等覆盖用户注册登录、商品发布浏览、交易沟通、订单管理、在线支付与评价反馈等完整业务环节。项目源码经本地编译调试可运行数据库表关系与业务逻辑设计完整并附开发文档与数据文档便于快速理解系统架构与实现思路。目前已有39人学习适合需要完整赛题方案与实战练习材料的学习者参考使用。1. 校园二手交易平台用 JavaJSP 做到底在解决什么问题每年毕业季宿舍楼下堆着的旧书、台灯、自行车和新生群里刷屏的“求购洗衣机”本质上是一个信息匹配问题。基于 Java 的校园二手物品交易平台要做的就是把这个匹配过程从微信群搬到浏览器里卖家发布商品、买家搜索浏览、双方在线沟通、线下交割。它不解决支付和物流核心价值在于把零散的供需信息结构化让“谁有闲置、谁要买”变得可检索。这个选题在 JavaWeb 课程设计和毕设里出现频率极高原因很实际技术栈成熟JSPServletMySQL、业务逻辑清晰增删改查加权限、工作量可控。适合两类人——一是刚学完 Java 基础、需要完整项目练手的在校生二是要交课程设计但不想从零造轮子的开发者。JSP 在这里的角色是服务端页面渲染配合 Model2 思想把 JavaBean、Servlet、JSP 三层分开避免把所有逻辑塞进一个页面里。下面从环境搭建到核心功能实现把这条路走通。2. 环境搭建与 Model2 分层别把 JSP 写成脚本大杂烩2.1 JDK、Tomcat、MySQL 的版本搭配与安装顺序环境配置是第一个拦路虎版本不匹配导致的报错能吃掉半天时间。我一般按这个顺序来先装 JDK再配 Tomcat最后装 MySQL。JDK 选 8 或 11 都行但要注意 Tomcat 版本对 JDK 的要求——Tomcat 9 支持 JDK 8Tomcat 10 开始把 javax.* 包名改成了 jakarta.*如果你用的 JSP 教程还是老写法Tomcat 10 会直接报 ClassNotFoundException。稳妥起见课程设计用 JDK 8 Tomcat 8.5/9 MySQL 5.7/8.0 这套组合资料最多踩坑最少。安装完 JDK 后配置环境变量JAVA_HOME指向 JDK 根目录Path里加%JAVA_HOME%\bin。验证命令java -version javac -version两条命令输出的版本号要一致。如果javac提示“不是内部或外部命令”说明 Path 没配好或者你装的是 JRE 而不是 JDK。Tomcat 解压后不需要装配置CATALINA_HOME指向解压目录即可启动用bin\startup.bat浏览器访问localhost:8080看到猫页面就算通了。MySQL 安装时记住 root 密码字符集选 utf8mb4排序规则选 utf8mb4_general_ci。建库语句CREATE DATABASE campus_trade DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;注意JDBC 连接 MySQL 8.0 时驱动类名是com.mysql.cj.jdbc.DriverURL 要加serverTimezoneAsia/Shanghai否则会报时区错误。MySQL 5.7 用com.mysql.jdbc.Driver即可。2.2 Model2 三层结构Servlet 收请求、JavaBean 传数据、JSP 只负责显示JSP Model2 的核心就一句话JSP 页面里不写业务逻辑只做展示。请求先到 ServletServlet 调用 Service/DAO 处理数据把结果存进 request 或 session然后 forward 到 JSP。这样改需求时只动 Servlet 或 DAO不用在一堆 HTML 里找 Java 代码。目录结构按这个来分src/ com.campus.entity/ // JavaBeanUser、Goods、Order com.campus.dao/ // 数据库操作UserDao、GoodsDao com.campus.servlet/ // 控制器LoginServlet、GoodsListServlet com.campus.util/ // 工具类DBUtil WebContent/ WEB-INF/web.xml // Servlet 映射 css/ js/ images/ login.jsp index.jsp goods_detail.jsp一个典型的 Servlet 写法WebServlet(/goods/list) public class GoodsListServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. 获取查询参数 String keyword req.getParameter(keyword); // 2. 调用 DAO 查询 GoodsDao dao new GoodsDao(); ListGoods list dao.search(keyword); // 3. 结果存入 request req.setAttribute(goodsList, list); // 4. 转发到 JSP 展示 req.getRequestDispatcher(/goods_list.jsp).forward(req, resp); } }逻辑说明WebServlet注解替代了 web.xml 里的servlet-mappingServlet 3.0 以后都这么写。forward是服务器内部跳转浏览器地址栏不变request 里的数据能带到 JSP。如果用sendRedirectrequest 数据会丢得改用 session 或 URL 参数。参数说明keyword来自搜索框的 name 属性DAO 里用PreparedStatement拼LIKE %?%防注入。req.setAttribute的 key 在 JSP 里用 EL 表达式${goodsList}取。JSP 页面里只写c:forEach items${goodsList} varg div classitem h3${g.title}/h3 p价格${g.price}/p a hrefgoods/detail?id${g.id}查看详情/a /div /c:forEach用 JSTL 的c:forEach替代 Java 脚本片段页面干净前端改样式不用碰 Java 代码。需要引入jstl.jar和standard.jar或者用 Maven 加依赖。3. 数据库设计与核心表用户、商品、订单三张表怎么定字段3.1 用户表与商品表的字段取舍表设计直接决定后面代码好不好写。用户表user至少要有id主键自增、username唯一索引、password存 MD5 或 BCrypt 哈希别存明文、nickname、phone、school、create_time。校园场景下school字段有用可以按学校筛选商品但如果你只做一个学校的这个字段可以省。商品表goods是核心id、title、description、price、image_url、category_id、seller_id外键关联 user.id、status0 在售 / 1 已售 / 2 下架、create_time。image_url存相对路径比如/upload/20250101_abc.jpg文件本身放在 WebContent 下的 upload 目录。status用 tinyint 而不是 varchar查询效率高代码里用常量类映射。分类表category单独建id、name、sort_order。常见分类有教材书籍、电子数码、生活用品、运动户外、代步工具。分类数据量小可以在启动时加载到 application 作用域避免每次查库。3.2 订单表与交易状态流转订单表orders记录交易意向id、goods_id、buyer_id、seller_id、price、status0 待确认 / 1 已确认 / 2 已完成 / 3 已取消、create_time、finish_time。校园二手交易通常线下付款所以订单表不涉及支付流水只记录“谁想买、卖家同不同意、最后成没成”。状态流转逻辑写在 Service 层public boolean confirmOrder(int orderId, int sellerId) { Order order orderDao.findById(orderId); // 只有卖家本人能确认且订单处于待确认状态 if (order.getSellerId() ! sellerId || order.getStatus() ! 0) { return false; } order.setStatus(1); return orderDao.updateStatus(order); }逻辑说明先查订单校验操作人身份和当前状态再更新。这种“先查后改”在并发下有问题——两个请求同时查到 status0都去更新会重复确认。解决办法是用UPDATE orders SET status1 WHERE id? AND status0根据返回的影响行数判断是否成功。参数说明sellerId从 session 里取当前登录用户不能从请求参数取否则别人可以伪造。status的数值含义在常量类OrderStatus里定义避免代码里到处写魔法数字。建表 SQL 示例CREATE TABLE goods ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, description TEXT, price DECIMAL(10,2) NOT NULL, image_url VARCHAR(255), category_id INT, seller_id INT NOT NULL, status TINYINT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_seller (seller_id), INDEX idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;注意外键约束在课程设计里可以加但生产环境高并发下外键会影响插入性能很多团队选择在应用层保证一致性。这里加INDEX而不是FOREIGN KEY查询快删除用户时手动处理关联商品。4. 商品发布与图片上传文件存哪、怎么防重复、路径怎么拼4.1 上传目录的配置与文件名生成策略图片上传是二手平台绕不开的功能。JSP 表单要设enctypemultipart/form-dataServlet 用MultipartConfig注解接收。文件不能直接存到 WebContent 下因为重新部署 war 包时会被覆盖。常见做法是存到服务器文件系统的固定目录比如/data/campus_trade/upload/然后在 Tomcat 里配一个虚拟路径映射或者用 Servlet 读文件流输出。我一般会在web.xml或 Tomcat 的server.xml里配Context docBase/data/campus_trade/upload path/upload /这样 JSP 里${pageContext.request.contextPath}/upload/xxx.jpg就能访问到。开发阶段图省事直接存WebContent/upload也行但要知道这个坑。文件名生成用 UUID 加原扩展名WebServlet(/goods/publish) MultipartConfig(maxFileSize 5 * 1024 * 1024) public class GoodsPublishServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Part filePart req.getPart(image); String originalName filePart.getSubmittedFileName(); // 提取扩展名 String ext originalName.substring(originalName.lastIndexOf(.)); // UUID 防重名 String newName UUID.randomUUID().toString().replace(-, ) ext; // 上传目录 String uploadDir getServletContext().getRealPath(/upload); File dir new File(uploadDir); if (!dir.exists()) dir.mkdirs(); filePart.write(uploadDir File.separator newName); // 存相对路径到数据库 String imageUrl upload/ newName; // ... 继续保存商品信息 } }逻辑说明getSubmittedFileName()拿到用户本地文件名只取扩展名避免中文名和特殊字符问题。UUID 保证同一秒上传多张图也不会覆盖。getRealPath在 war 包解压后指向实际目录但重新部署会丢所以生产环境要用外部目录。参数说明maxFileSize限制单文件 5MBmaxRequestSize限制整个请求大小。超过会抛IllegalStateException要在页面提示“图片不能超过 5M”。扩展名要白名单校验只允许 jpg、jpeg、png、gif防止上传 jsp 文件被解析。4.2 商品列表的分页查询与分类筛选商品多了必须分页。MySQL 用LIMIT offset, sizeoffset 是起始行号。Servlet 里算int page Integer.parseInt(req.getParameter(page) null ? 1 : req.getParameter(page)); int size 12; int offset (page - 1) * size; ListGoods list goodsDao.findByPage(offset, size, categoryId, keyword); int total goodsDao.count(categoryId, keyword); int totalPages (total size - 1) / size; req.setAttribute(currentPage, page); req.setAttribute(totalPages, totalPages);DAO 里拼 SQL 要注意分类和关键词可能为空用 StringBuilder 动态拼但参数必须用PreparedStatement的?占位。比如StringBuilder sql new StringBuilder(SELECT * FROM goods WHERE status0); ListObject params new ArrayList(); if (categoryId 0) { sql.append( AND category_id?); params.add(categoryId); } if (keyword ! null !keyword.trim().isEmpty()) { sql.append( AND title LIKE ?); params.add(% keyword.trim() %); } sql.append( ORDER BY create_time DESC LIMIT ?,?); params.add(offset); params.add(size);逻辑说明status0只查在售商品已售和下架的不显示。ORDER BY create_time DESC让最新发布的排前面。LIMIT的两个参数也走占位符避免拼接。参数说明page从 URL 取要做边界校验小于 1 按 1 算大于总页数按最后一页算。size每页 12 条三列布局刚好四行。totalPages传给 JSP 渲染分页条。JSP 分页条用 JSTLc:forEach begin1 end${totalPages} vari a hrefgoods/list?page${i}categoryId${param.categoryId} class${i currentPage ? active : }${i}/a /c:forEach注意param.categoryId在翻页时保留筛选条件否则点第二页会丢掉分类。关键词同理要拼在 URL 里并做 URLEncoder 编码。5. 避坑与排查登录态、中文乱码、JSP 编译报错5.1 登录态丢失与 session 超时现象用户登录后点几个页面就提示未登录或者重启 Tomcat 后所有用户掉线。原因session 默认存在内存里Tomcat 重启就清空。另外 session 默认超时 30 分钟超时后session.getAttribute(user)返回 null。解决登录成功后把 user 对象存 session每个需要登录的 Servlet 先检查User user (User) req.getSession().getAttribute(user); if (user null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; }如果不想重启掉线可以配 Tomcat 的 session 持久化在context.xml里加Manager pathnameSESSIONS.ser /。但课程设计没必要知道这个机制就行。5.2 中文乱码的三处来源现象表单提交的中文存到数据库变成问号或者页面显示乱码。原因三处编码要统一——JSP 页面% page contentTypetext/html;charsetUTF-8 %、request 解码req.setCharacterEncoding(UTF-8)、数据库连接 URL 加useUnicodetruecharacterEncodingutf8。Tomcat 8 以后 GET 请求默认 UTF-8但 POST 必须手动设。解决在 Servlet 的doPost第一行写req.setCharacterEncoding(UTF-8)或者写一个 Filter 统一处理public class EncodingFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { req.setCharacterEncoding(UTF-8); resp.setContentType(text/html;charsetUTF-8); chain.doFilter(req, resp); } }5.3 JSP 编译报错javax 与 jakarta 包名冲突现象Tomcat 10 下访问 JSP 报java.lang.NoClassDefFoundError: javax/servlet/jsp/PageContext。原因Tomcat 10 把 Java EE 的javax.*全部改成了jakarta.*老教程里的 JSP 标签库和 Servlet API 都是 javax 包。解决要么换 Tomcat 9要么把所有 import 改成 jakarta并换用支持 jakarta 的 JSTL 版本。课程设计建议直接用 Tomcat 9省去改包名的麻烦。5.4 图片上传后访问 404现象文件明明写到了 upload 目录但浏览器访问图片地址是 404。原因getRealPath(/upload)在开发时指向WebContent/upload但 IDE 部署时可能只复制编译后的 class 和 jsp空目录不会被复制。或者上传目录在 war 包外没有配虚拟路径。解决在 upload 目录里放一个空的.gitkeep文件或者代码里dir.mkdirs()确保目录存在。如果是外部目录检查 Tomcat 的server.xml里Context配置的docBase路径是否正确改完重启 Tomcat。5.5 数据库连接未关闭导致连接池耗尽现象系统跑一段时间后报Too many connections或者页面越来越慢。原因DAO 里Connection、PreparedStatement、ResultSet没在 finally 里关闭每次请求泄漏一个连接。解决用 try-with-resources 自动关闭try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { // 设置参数、执行查询 } catch (SQLException e) { e.printStackTrace(); }ResultSet也放在 try 的括号里。如果项目大了引入 Druid 或 HikariCP 连接池在druid.properties里配maxActive20监控连接使用情况。6. 从能跑到好用搜索优化与部署上线的几个实操技巧6.1 用 LIKE 做搜索的边界与替代方案LIKE %关键词%在数据量小的时候没问题但商品表超过几万行后全表扫描会明显变慢。校园平台通常几千条数据LIKE 够用。如果要做得好一点可以给title加全文索引ALTER TABLE goods ADD FULLTEXT INDEX ft_title (title) WITH PARSER ngram;然后查询用MATCH(title) AGAINST(关键词 IN BOOLEAN MODE)。ngram 解析器支持中文分词MySQL 5.7 以上可用。但全文索引对短词和停用词有限制实际效果要测。我一般先上 LIKE真慢了再换。另一个技巧是搜索历史记录。用户搜过的词存到 cookie 或 session下次点搜索框自动提示。实现简单体验提升明显// 搜索后把关键词存 localStorage localStorage.setItem(lastSearch, keyword); // 页面加载时回填 document.getElementById(keyword).value localStorage.getItem(lastSearch) || ;6.2 部署到服务器war 包、数据库导出与 Tomcat 配置本地跑通后部署到云服务器让同学访问才算完整。步骤IDE 里导出 war 包或者 Maven 执行mvn package。服务器装 JDK 和 Tomcat把 war 丢进webapps目录启动后自动解压。数据库用mysqldump -u root -p campus_trade campus_trade.sql导出服务器上mysql -u root -p campus_trade campus_trade.sql导入。改数据库连接配置把localhost改成服务器内网 IP密码改成服务器 MySQL 密码。开放安全组 8080 端口浏览器访问服务器IP:8080/项目名。注意服务器上的 MySQL 默认只允许 localhost 连接要执行GRANT ALL ON campus_trade.* TO user% IDENTIFIED BY password;并FLUSH PRIVILEGES;。Tomcat 的server.xml里Connector的URIEncoding设为UTF-8避免 GET 请求中文乱码。6.3 一个验证清单上线前逐项检查部署完别急着发链接按这个清单过一遍检查项预期结果失败时看哪里首页商品列表显示最新 12 条在售商品GoodsListServlet 的 SQL 和分页参数搜索“教材”返回标题含教材的商品LIKE 拼接和关键词编码发布商品带图数据库有记录图片能显示upload 目录权限和虚拟路径未登录点发布跳转登录页session 检查和拦截逻辑卖家确认订单订单状态变为已确认UPDATE 的影响行数和权限校验手机浏览器访问页面自适应不溢出viewport meta 和 CSS 媒体查询这个清单是我每次部署完必跑的能挡住八成低级问题。尤其是图片上传和 session 检查翻车次数最多。6.4 最后说一个习惯我做完每个课程设计都会把数据库连接信息、Tomcat 版本、JDK 版本写在一个README.md里连同建表 SQL 和部署步骤。过两个月回头看或者换台电脑重新搭能省掉重新摸索的时间。校园二手平台这个项目技术不复杂但细节多——编码、路径、session、分页每个点都可能卡住。把踩过的坑记下来下次就是经验。希望帮到你。本文还有配套的精品资源点击获取
返回列表