ARTICLE DETAIL

资讯详情

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

JSP+Access网上购物系统课程设计:从部署到避坑指南

JSP+Access网上购物系统课程设计:从部署到避坑指南 简介基于JSP和Access的网上购物系统设计与实现资料面向计算机相关专业学生适合用于课程设计、毕业设计或项目实训也可作为Java Web初学者的参考案例。压缩包内集成项目全套源码与完整设计文档源码已经过测试校正可百分百成功运行能帮助使用者快速理解B/S架构下网上购物系统的完整业务流程包括用户注册登录、商品分类浏览、购物车添加与管理、订单生成与处理以及后台管理员对商品、订单、用户信息的管理等核心功能模块。资源包大小约1.9MB主要文件为JSP页面源码、Access数据库文件以及配套的设计说明文档压缩包结构简洁清晰便于按模块查阅和二次开发。目前已有290人学习下载资源质量经过验证实用性较强。文档部分覆盖了从需求分析、数据库设计到系统实现与测试的完整环节可有效支撑从环境搭建到功能调试的整个实践过程是完成类似电商项目设计时值得参考的完整方案。1. 网上购物系统课程设计JSP 配 Access 这套老组合还值不值得下载手头需要交一份网上购物系统的课程设计你打开搜索框大概率会看到大量 Spring Boot 配 MySQL 的仓库。但这套基于 JSP Access 的网上购物系统恰恰是另一个维度的选择不需要单独安装数据库服务不需要理解繁琐的框架分层解压之后配个 Tomcat 就能跑。它保留了最传统的 JSP Servlet JavaBean 结构反而能把“用户在页面点了什么、请求怎么到后台、后台怎么读写数据库”这条链路看得明明白白。适合做课程设计或毕业设计的大三、大四学生也适合想快速找回 Java Web 底子的从业者。源码和配套文档都齐下面从选型逻辑、数据表、部署到避坑逐个拆开讲。2. 为什么是 JSP 搭 Access选型逻辑与请求链路拆解2.1 Access 不是玩具单文件数据库能扛住课程设计的业务量很多人在打开这个项目的第一反应是Access 也算数据库这里要说句公道话。Access 是微软 Office 体系里的桌面数据库一个 .mdb 文件就能把所有表、查询、索引打包在一起。对于课程设计这个量级——商品几十到几百条、用户几百个、订单几千条——它完全撑得住而且省去了 MySQL 安装、改 root 密码、建库授权这一整套运维折腾。你把这个项目拷给老师数据库就藏在压缩包里老师打开就能复核不需要在验收机器上再配一个数据库服务。JSP 对应的是 Java Web 传统开发路线JSP 负责页面展示Servlet 负责控制流转JavaBean 或 DAO 类负责数据库访问。这一点从这个项目的 BS 架构就能看出来——浏览器通过 Tomcat 访问后台逻辑客户端零安装输入 localhost 地址就能进系统。这种选型的背后是高校 Java Web 课程体系的真实教学顺序先让学生用最原生的方式把请求响应链路跑通再引入框架。所以它不是性能最优解却是教学场景下最合适的组合。2.2 一个登录请求从点击到响应穿过几层代码以登录为例你在 login.jsp 里输入用户名密码表单提交后请求会依次穿过 JSP、Servlet、DAO、Access 四层。我见过不少初学者在页面和数据库之间来回改代码却不知道每一层具体干什么。下面这段 LoginServlet 是这类项目的标配逻辑// LoginServlet 处理 login.jsp 提交的用户名和密码 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 第一行必须放在 doPost 最前面否则中文参数会乱码 request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); UserDao dao new UserDao(); User user dao.findUserByLogin(username, password); if (user ! null) { // 登录成功把用户对象放进 session购物车之后才有归属 request.getSession().setAttribute(loginUser, user); response.sendRedirect(request.getContextPath() /index.jsp); } else { // 登录失败回跳登录页并携带一个错误消息 request.setAttribute(loginError, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } }这段代码的逻辑是先统一请求编码再取出表单参数然后调用 DAO 查询根据返回结果决定跳转方向。注意response.sendRedirect和request.getRequestDispatcher(...).forward的区别——一个是浏览器重新发请求地址栏会变另一个是服务端内部转发浏览器地址栏不变。课程设计答辩时老师常会问到这一点。真正访问 Access 数据库的代码在 DAO 层常见写法是封装一个 DBUtil 工具类给所有 DAO 提供连接和关闭方法// UserDao 中通过 JDBC 访问 Access 数据库的登录查询 public User findUserByLogin(String username, String password) { Connection conn null; PreparedStatement ps null; ResultSet rs null; try { conn DBUtil.getConnection(); String sql SELECT * FROM user WHERE username ? AND password ?; ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); rs ps.executeQuery(); if (rs.next()) { User user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); user.setRealName(rs.getString(realName)); return user; } } catch (Exception e) { e.printStackTrace(); } finally { // Access 单文件数据库对连接未关闭非常敏感这里必须严格关闭 DBUtil.close(conn, ps, rs); } return null; }这里有两个值得注意的参数细节。第一SQL 里用?占位配合PreparedStatement的setString赋值而不是用字符串拼接这是为了防止 SQL 注入很多老教程里直接拼接SELECT * FROM user WHERE username username 是会出安全问题的写法如果下载的源码里是这种方式建议改成上面这样。第二finally里的DBUtil.close(conn, ps, rs)不能省——Access 是一个共享文件数据库连接开着不关别的线程再访问就会被锁住后面第 5 章会专门讲这个翻车点。2.3 三层目录结构对照你手里的每个文件该放进哪一层打开压缩包你会看到源码部分大致是 src 目录和 WebRoot或 webapps目录。src 下通常分成 entity、dao、servlet、util 几个包WebRoot 下放 JSP、CSS、JS 和 WEB-INF。这两块正好对应 MVC 里的 Model、Controller、View。我一般拿到项目会先按下面这张表过一遍文件归属确认缺了什么再动手层典型目录典型文件职责表现层 ViewWebRootindex.jsp、login.jsp、cart.jsp页面展示收集用户输入控制层 Controllersrc 下的 servlet 包LoginServlet、ProductServlet、OrderServlet接收请求参数调用 Model决定跳转业务与数据层 Modelsrc 下的 dao、entity 包UserDao、ProductDao、OrderDao、User.javaSQL 执行、结果封装、业务判断工具类src 下的 util 包DBUtil.java统一管理数据库连接与关闭资源文件WebRoot/WEB-INFweb.xml、lib 下的 jar配置 Servlet 映射和依赖包有一点提醒一下如果你用 Eclipse 或 MyEclipse 导入项目WEB-INF/lib 下的 jar 会自动进入构建路径但如果你用 IDEA导入之后要手动把 lib 目录标记为库否则运行时会报ClassNotFoundException这个问题非常多见。文档部分一般会有需求分析、数据库设计、详细设计和操作说明按学校要求改封面、补测试截图就能直接交。3. 核心模块与数据表购物车、订单、库存是怎么串起来的3.1 核心表结构四张表足够支撑一个购物系统网上购物系统的核心数据压缩到最小集合是四张表用户表、商品表、订单表、订单明细表。有的项目还会加一个商品分类表。下面这张表是我按这类项目的通用设计整理的你下载的压缩包里如果表字段名略有不同对照理解即可表名关键字段Access 字段类型说明userid、username、password、realName、phone、address自动编号、文本保存前台用户和管理员账号productid、productName、price、quantity、description、pic自动编号、数字、文本商品信息quantity 是库存ordersid、orderNo、userId、totalMoney、state、createTime自动编号、文本、数字订单主表state 表示订单状态orderitemid、orderId、productId、price、quantity自动编号、数字订单明细记录每个商品快照这里要为新手解释一个容易混淆的设计为什么已经有了 orders 表还要单独建 orderitem 表因为一个订单会包含多件商品如果把商品直接塞进 orders 表比如加一个字段记录“3个商品、每个商品价格”那么下次要按商品维度统计销量就非常痛苦。订单和商品是多对多关系必须通过明细表来拆。这也是答辩时老师常问的“你数据库有做范式化设计吗”的答题点。需要注意 Access 的字段类型和 MySQL 不一样它没有int(11)这种写法数字类型就是“数字”整数用“长整型”。文本类型默认 255 字节如果要存比较长的商品描述要用“备注”类型。日期类型可以直接存#2025-01-01#这种格式。如果你在 Access 的查询设计器里写 SQL语法也要跟着 Access 走比如字符串用单引号日期用#而不是。3.2 从“加入购物车”到“下单成功”四步主流程拆解这个系统的主流程可以拆成四条链路浏览商品、加购、下单、订单管理。先说加购这类系统的购物车几乎都是放在 session 里的核心代码如下// 购物车动作把商品加入 session 购物车 public String addCart(HttpServletRequest request) { int productId Integer.parseInt(request.getParameter(productId)); int quantity Integer.parseInt(request.getParameter(quantity, 1)); // 购物车用 MapProductId, 数量 的形式存在 session 里 MapInteger, Integer cart (MapInteger, Integer) request.getSession().getAttribute(cart); if (cart null) { cart new HashMap(); request.getSession().setAttribute(cart, cart); } // 如果购物车里已有这件商品数量累加 Integer oldCount cart.get(productId); cart.put(productId, (oldCount null ? 0 : oldCount) quantity); return cart.jsp; }购物车为什么放 session 而不是存数据库理由有三条第一未登录用户也能先加购登录后再合并即可第二避免给 Access 增加大量无意义的写操作第三Access 是单文件数据库频繁写入会造成文件锁竞争session 购物车则完全没有这个问题。但缺点也很明显——用户关掉浏览器购物车就没了。这属于课程设计可接受的范围如果你想让购物车持久化后面第 6 章会讲怎么改造。下单流程比加购复杂一些常见的实现是点击“去结算”后生成订单号、插入订单主表、遍历购物车往明细表写入、扣减库存最后清空 session 购物车。扣减库存这里有一个关键写法很多人直接简单粗暴地先查库存再更新并发场景下容易出问题-- 安全的库存扣减把“库存 购买数量”作为更新条件比先查后改更稳妥 UPDATE product SET quantity quantity - ? WHERE id ? AND quantity ?这条 SQL 的意思是在同一个更新语句里完成判断和扣减只有当数据库中的库存仍然大于等于购买数量时才执行更新。如果更新影响行数为 0说明库存不足下单就应当中断。这是课程设计里少见的“并发意识”写进文档里答辩时非常加分。3.3 管理员模块商品管理与订单状态流转管理员部分一般是一个单独的后台页面登录时判断当前用户的权限字段普通用户不能访问后台目录。商品管理的常见操作是新增、编辑、删除删除商品前要检查它是否已经存在于订单明细里如果有就不能直接删否则会导致订单明细悬空。这个限制在代码里通常体现为一个查询判断。订单状态流转是后台的重头戏。常见状态值是0 待付款1 待发货2 已发货3 已完成有时还有 4 已取消。管理员在后台看到新订单后点击发货把 state 从 1 改成 2。前台用户看到的状态随之变化。这里要注意订单状态字段用数字表示比用文本更合理因为文本容易写错、占空间、也不方便状态流转判断。文档里如果有状态定义表直接照文档来即可如果没有我建议你按上面这套状态值补进数据库设计文档里。4. 部署全流程从解压到 Tomcat 跑起来的几个关键步骤4.1 环境选型JDK、Tomcat、数据库文件三件套部署这套老项目之前先把环境确定下来。最常见的组合是 JDK 1.7 或 1.8 Tomcat 7 或 8.5 Office Access 2007 及以上版本生成的 .mdb 文件。如果你是新装的机器建议优先选 JDK 8 Tomcat 8.5因为 JDK 8 是目前课程设计环境里最通用的配置。如果你手头只有 JDK 11 或更高版本后面遇到 JSP 编译问题时不要惊讶——老项目的 JSP 语法和 Servlet 版本是按 JDK 8 时代写的高版本 JDK 跑老 Tomcat 容易出现不兼容。这里有一个很关键的环境注意点老项目里通常自带一个 .mdb 文件不要用 Access 2016/2019 去打开后另存为 .accdb 格式。很多老代码的连接串写的是*.mdb一旦转成 .accdb原样连接就会失败。老老实实保留 .mdb 格式最多用新版本 Access 打开后直接关掉它会自动兼容旧格式。4.2 数据库连接配置JDBC-ODBC 桥和 uCanAccess 两种写法这套项目访问 Access 数据库有两条路线拿到源码后第一步要先看 DBUtil 或 db.properties 里用的是哪种。老项目通常用的是 JDBC-ODBC 桥连接串长这样// 旧式 JDBC-ODBC 桥连接 AccessJDK 8 及以上版本已移除 Class.forName(sun.jdbc.odbc.JdbcOdbcDriver); String url jdbc:odbc:Driver{Microsoft Access Driver (*.mdb)};DBQE:/shop.mdb; Connection conn DriverManager.getConnection(url);这条路线在 JDK 8 里已经不能用了因为sun.jdbc.odbc.JdbcOdbcDriver这个类在 JDK 8 中被移除。如果你下载的源码里是这种写法运行时会直接报ClassNotFoundException。我一般会在拿到这类项目的第一时间把连接方式改成 uCanAccess这是目前 Java 连接 Access 最稳定的开源驱动// uCanAccess 方式连接 Access需要把 ucanaccess 及依赖 jar 放进 WEB-INF/lib Class.forName(net.ucanaccess.jdbc.UcanaccessDriver); String url jdbc:ucanaccess://E:/shop.mdb; Connection conn DriverManager.getConnection(url);注意 uCanAccess 的 URL 路径里直接写 .mdb 文件的绝对路径路径分隔符用正斜杠或双反斜杠都可以。改完驱动类之后还要把 ucanaccess 主 jar 和它的几个依赖 jarjackcess、commons-lang3、commons-logging一起放进去很多初学者只拷了一个主 jar 就启动结果报No suitable driver其实不是驱动没加载而是依赖 jar 缺失。如果你用的是 Eclipse直接在 WEB-INF/lib 下粘贴 jar 即可如果是 IDEA记得右键 lib 目录选 Add as Library。4.3 放置到 Tomcat 并启动目录位置、端口与启动方式环境配好后把项目文件夹或 WAR 包放进 Tomcat 的 webapps 目录。如果是文件夹形式项目名就是访问路径的前缀。比如你把它命名为 shop启动后访问地址就是 http://localhost:8080/shop/。如果你希望能直接用根路径访问可以把项目文件夹改名为 ROOT或者删除 Tomcat 自带的 ROOT 文件夹后替换。启动 Tomcat 的命令在 Windows 和 Linux 下不一样# Windows 下启动 Tomcat进入 bin 目录后执行 cd D:\apache-tomcat-8.5.91\bin startup.bat # Linux / macOS 下启动 cd /opt/apache-tomcat-8.5.91/bin ./startup.sh启动后浏览器访问 http://localhost:8080如果能打开 Tomcat 默认页面说明服务已经起来了。如果启动窗口一闪而过基本可以判定是JAVA_HOME或CATALINA_HOME环境变量没有配置对Tomcat 的 start 脚本找不到 Java 命令。用echo %JAVA_HOME%Windows或echo $JAVA_HOMELinux确认一下环境变量。4.4 验证部署成功四步验收法项目启动后不要只看首页能打开就算成功。我一般会按下面四步完整验收一遍确保每一步都有证据第一能打开首页并且商品列表有数据说明 Tomcat 和 JSP 解析正常第二能注册一个新用户并登录成功说明 user 表读写正常第三能往购物车添加商品并能在购物车页面看到数量累计说明 session 正常第四能走完整个下单流程生成一个订单号并能在订单列表里看到它说明订单表和明细表写入正常。这四步全部通过这个项目才算真正跑通。如果某一步失败优先去 Tomcat 的 logs 目录看catalina.yyyy-MM-dd.log和localhost.yyyy-MM-dd.log数据库相关错误几乎都会打在localhost日志里。另外后台管理员的初始账号密码一般在配套文档里写明常见是 admin/admin如果文档里没有打开 Access 里 user 表的字段看看里面会有一条管理员记录。5. 避坑JSP Access 最常见的五个翻车现场5.1 Tomcat 启动一闪而过浏览器打不开 8080现象双击 startup.bat 后窗口瞬间消失localhost:8080 无法访问。原因绝大多数情况是JAVA_HOME没有配置或者配置路径里有空格、多余分号。Tomcat 的启动脚本会先去找 JAVA_HOME 来定位 java.exe找不到就静默退出。解决打开系统环境变量检查 JAVA_HOME 指向的是 JDK 安装根目录不是 bin 目录。例如C:\Program Files\Java\jdk1.8.0_211并在 Path 中加入%JAVA_HOME%\bin。配置好后在命令行执行java -version能输出版本信息再重跑 startup.bat。如果端口被占用命令行执行netstat -ano | findstr 8080用任务管理器结束对应 PID 的进程或修改 Tomcat 的conf/server.xml把端口改成 8081。5.2 首次访问 JSP 报 500javax.servlet 开头的错误堆栈现象浏览器打开首页报 500 错误日志里提示类找不到或 Servlet 编译失败。原因项目 WEB-INF/lib 下的 jar 没有被加载常见于 IDEA 导入项目后没有把 lib 目录添加到构建路径Add as Library或者 Eclipse 里 jar 虽然可见但构建路径里缺失。解决在 IDEA 中选中 WebRoot/WEB-INF/lib 目录右键选 Add as Library如果报的是 Servlet 相关的类找不到检查是不是没有引入 servlet-api.jar这个 jar 在 Tomcat 的 lib 目录里也存在不要从 Tomcat lib 里往项目里乱拷直接用项目自带的就行。这类问题还有一个老套路项目里同时有两份同名的 servlet-api.jar 冲突代码里保留一份。5.3 数据库连接报 ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver现象运行时抛出java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver或者No suitable driver found for jdbc:odbc...。原因JDK 8 移除了 JDBC-ODBC 桥驱动老代码里的Class.forName(sun.jdbc.odbc.JdbcOdbcDriver)在新 JDK 里根本不存在。解决按第 4.2 节的方式换成 uCanAccess。改连接串时记得同时换驱动类名和 URL 协议只改其中一个会继续报错。如果你坚持要用 JDBC-ODBC 桥唯一的办法是安装 JDK 7 并配置 JAVA_HOME 指过去——但我不推荐为这个装旧环境uCanAccess 这条路干净得多。5.4 更新数据时提示“记录锁定”或生成 .ldb 文件现象系统运行时Access 数据库文件夹里出现同名的.ldb文件某个用户操作时提示“无法更新当前正被另一个用户锁定”或直接报“数据库已被锁定”。原因Access 以文件方式共享数据当某个连接未关闭或事务未结束时Access 会创建 .ldb 文件记录锁信息。另一个请求同时写入时就会冲突。这在 DAO 代码里忘了关连接时尤其常见。解决第一步检查所有 DAO 的 finally 块确保 Connection、Statement、ResultSet 三个对象都关闭不要只关其中一个。第二步不要在循环里反复打开连接——每开一次连接就是一次文件锁申请循环 100 次就有 100 次锁竞争。第三步如果系统对读写并发要求稍高可以在 DBUtil 里做一个单例连接整个应用共享一个连接但这样又会让同一文件长期处于被占用状态所以一般只建议用连接关闭策略而不是真的做连接池。这个平衡要灵活判断。5.5 数据库路径写死导致换台电脑就连不上现象把项目拷到另一台电脑或发给老师后运行时数据库连接失败但代码路径里明明有那个文件。原因源码里的连接串写的是绝对路径比如jdbc:ucanaccess://E:/shop.mdb。换了机器后文件在 D 盘或者目录层级变了路径自然就失效。解决把数据库文件从 src 或项目根目录移到一个固定相对位置在 DBUtil 里动态拼接路径。常见做法是约定把 .mdb 文件放在项目 WebRoot 下的 db 目录然后用当前项目路径动态定位// DBUtil 中动态定位 .mdb 文件绝对路径避免换机后找不到库 String dbPath getClass().getResource(/).getPath() .replace(/WEB-INF/classes, /db/shop.mdb); // Windows 下路径前面会多个 /去掉它 dbPath dbPath.replaceFirst(^/, ); String url jdbc:ucanaccess:// dbPath;这段逻辑的思路是Web 应用运行时getResource(/)拿到的是 classes 目录路径通过它向上回退一层定位到 WebRoot再拼接 db 目录下的数据库文件。这样项目无论放到哪个目录、哪台电脑数据库路径都是跟着项目走的。这个改造虽然只有几行代码但能省掉后面换环境时的全部路径烦恼我拿到任何 JSP Access 项目都会优先做这一步。6. 进阶改造把课程设计做出答辩深度的三件事6.1 给数据库访问加一层日志排障不用瞎猜原版代码的 DAO 里几乎只有e.printStackTrace()出错时信息打在哪里都找不到。我一般会给 DBUtil 加一个最简单的日志输出每次执行的 SQL 语句和参数值统一打印到控制台。这样一旦页面报错你能立刻看到是哪条 SQL、哪几个参数出了问题而不是从头到尾翻堆栈。代码量不大但排障效率高出一大截。6.2 从 Access 迁移到 MySQL 的一条平稳路线如果答辩老师要求你“不用 Access改成 MySQL”不要慌。先在 Access 里把表结构和数据看一遍然后在 MySQL 手工建出同样结构的库和表。数据迁移不要用可视化工具我一般写一个一次性 Java 程序用 uCanAccess 连接 Access 读数据再通过 JDBC 往 MySQL 插入每批提交 100 条。这样迁移过程完全可控中途出错也能定位到具体批次。迁移完成后把 DBUtil 换成 MySQL 的驱动和连接串其他 DAO 代码只要 SQL 语法没有用到 Access 专属写法基本不用大改。6.3 答辩被问“系统不足”时的安全回答每次答辩老师必问“你这个系统有什么可以改进的地方”。直接说“没有”是送命题。我建议你从项目里真实存在、且已经被你验证过的点去回答购物车存在 session 里重启后丢失单文件数据库不适合高并发没有引入框架代码重复较高等。每一个回答后面都要紧跟一句“如果重新做我会怎么改”比如“购物车可以加一张持久化表用户登录后自动合并 session 购物车”。这样既显得你诚实又显得你有后续设计能力。另外给你一个后端隐藏技巧把购物车 Map 用 JSON 序列化后存进 Cookie有效期设置成 30 天这样用户关浏览器再打开购物车还在。实现思路很简单——加购时把 Map 转成 JSON 写进 Cookie打开首页时读取 Cookie 反序列化成 Map。这个细节绝大多数课程设计都没有但老师演示时很容易注意到。不过要注意 Cookie 体积限制购物车里积累太多商品会超出 4KB可以在商品数量超过 10 条时提示用户去结算算是一个安全边界。这套项目我拆过不止一次每次拿到新机器都要把环境变量、JDK 版本、数据库连接串重新过一遍。从那以后我每个 JSP Access 项目拿到手都强制先跑一遍“确认连接方式、动态化路径、验证完整下单流程”再动其他代码这套流程帮我避开了大量重复翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表