简介本资源是一套基于JSP与Access数据库构建的轻量级网上购物系统完整实现方案面向高校计算机专业课程设计、毕业设计及Web开发初学者解决BS架构下电商核心功能模块用户管理、商品浏览、购物车、订单处理的落地实践问题。压缩包为1.9MB的ZIP文件内含经测试校正可直接运行的全部源码与配套文档涵盖JSP页面、Servlet逻辑、DAO数据访问层及Access数据库文件结构清晰、注释完整便于理解MVC分层思想与前后端交互流程。目前已有290人学习下载适合快速搭建本地开发环境、掌握JSPAccess技术栈整合要点并作为教学案例或二次开发基础模板。1. 为什么今天还要碰 JSP Access 的网上购物系统——它不是古董而是教学闭环里的“最后一块拼图”如果你在高校教 Java Web、带毕设、或者刚接手一批老课设代码大概率会撞上这个压缩包基于JSPaccess的网上购物系统设计与实现源码文档.zip。别急着点叉——它不是过时的废料而是一套可跑、可调、可讲、可拆解的最小可行教学闭环前端用原生 JSP 标签写逻辑后端零框架直连 Access 数据库业务流覆盖用户注册→登录→商品浏览→加入购物车→订单生成→后台管理所有代码都在一个 WAR 包里双击tomcat/bin/startup.bat就能起来。没有 Maven 依赖冲突不报NoClassDefFoundError也不需要配 Spring Boot 的application.yml。它解决的不是高并发电商问题而是「学生第一次独立写出一个带数据库交互的完整 Web 流程」这个具体痛点。适合计算机专业大三下到大四上、Java Web 课程设计、毕业设计入门选题、以及需要快速验证 MVC 分层概念的教师演示场景。你不需要它扛住百万 PV但你需要它在学生笔记本上稳定跑通、能改、能 debug、能对着源码讲清楚 request.setAttribute 怎么传到 JSP、Connection 如何从 DriverManager 拿出来、Access 的.mdb文件为什么必须放在WebContent/WEB-INF/db/下才能被getRealPath()定位到。2. 从解压到启动本地环境搭建的三步硬核落地含 Tomcat 9 JDK 8 兼容性实测这套系统不是开箱即用但它的启动路径非常干净——没有 Docker、没有云服务、不依赖外部数据库实例。核心就三件事装对 JDK、配好 Tomcat、把 Access 驱动塞进 classpath。下面是我反复在 Windows 10/11 和 macOS通过 Rosetta 运行 Tomcat上验证过的最小可行路径。2.1 环境版本锁死为什么必须用 JDK 8u202 Tomcat 9.0.83JSP Access 组合对 JVM 和 Servlet 容器版本极其敏感。新版 JDK11默认移除了javax.activation和javax.xml.bind而 Access JDBC 驱动ucanaccess-5.0.1.jar底层依赖javax.mail.internet.MimeMultipartTomcat 10 强制使用 Jakarta EE 命名空间jakarta.servlet.*而本项目所有web.xml和 JSP 中的 taglib 声明仍是javax.servlet.*。实测下来最稳组合是JDK 8u202非最新 8u391因后者移除了部分旧安全策略导致 Access 连接失败Tomcat 9.0.839.0.x 最后一个支持javax.*命名空间的稳定版Windows 系统优先Access 是 Windows 原生数据库macOS/Linux 需额外装 Jackcess UCanAccess且中文路径易出错提示不要用 IntelliJ IDEA 自带的 Tomcat 插件一键配置。它默认拉取最新版 Tomcat且 classpath 加载顺序不可控。务必手动下载二进制包解压再在 IDEA 中指向该目录。2.2 部署前的三处关键文件操作缺一不可解压xxx.zip后你会看到类似这样的结构shop_system/ ├── src/ ← Java Servlet 源码LoginServlet.java, OrderServlet.java ├── WebContent/ ← JSP 页面、CSS、JS、WEB-INF │ ├── index.jsp │ ├── user/ │ │ └── login.jsp │ └── WEB-INF/ │ ├── web.xml ← 注意servlet-mapping 用的是 /login.do 而非 /login │ └── lib/ │ ├── ucanaccess-5.0.1.jar ← 必须存在 │ ├── hsqldb-2.7.1.jar ← UCanAccess 依赖 │ └── jackcess-4.0.0.jar ├── db/ ← Access 数据库文件shop.mdb └── doc/ ← 需求分析、ER 图、测试用例等 Word 文档操作 1把db/shop.mdb复制到WebContent/WEB-INF/db/目录下原因源码中数据库路径写死为getServletContext().getRealPath(/WEB-INF/db/shop.mdb)。getRealPath()只对已部署的 WAR 内部路径有效若放错位置运行时报java.io.FileNotFoundException: null\WEB-INF\db\shop.mdb。操作 2检查WEB-INF/lib/是否包含全部 3 个 jarUCanAccess 不是单 jar它依赖 HSQLDB内存引擎和 JackcessAccess 文件解析器。少任何一个都会在Class.forName(net.ucanaccess.jdbc.UcanaccessDriver)时抛ClassNotFoundException或No suitable driver found。操作 3修改web.xml中 welcome-file-list原始文件常写welcome-fileindex.jsp/welcome-file但实际首页逻辑在index.jsp里做了跳转% response.sendRedirect(user/login.jsp); %建议改为welcome-fileuser/login.jsp/welcome-file避免首次访问出现空白页或 404。2.3 启动命令与验证页面附 curl 快速检测在 IDEA 中配置好 Tomcat 后点击 Run控制台应输出INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [2142] milliseconds INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina] ... INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.83]然后访问✅http://localhost:8080/shop_system/user/login.jsp—— 应显示登录表单含用户名、密码输入框 登录按钮✅http://localhost:8080/shop_system/admin/login.jsp—— 后台管理员登录页默认账号 admin / 123456❌ 若访问http://localhost:8080/shop_system/返回 404请检查web.xml的welcome-file-list和Context path是否为shop_system非/提示用curl -I http://localhost:8080/shop_system/user/login.jsp查看 HTTP 状态码。返回HTTP/1.1 200 OK说明容器已加载 JSP后续问题大概率出在数据库连接或 session 逻辑。3. 数据库连接实操Access 驱动加载、连接字符串、中文乱码三连调Access 不是 MySQL没有服务进程它靠 JDBC 驱动直接读写.mdb文件。这套系统用的是 UCanAccess纯 Java 实现它比老式 JDBC-ODBC 桥更可靠、跨平台、无需系统 DSN 配置。但正因为是“文件数据库”路径、编码、并发锁三个点极易翻车。3.1 驱动加载代码必须写在 try-catch 外层血泪经验很多学生把Class.forName(...)放在doPost()方法里结果每次请求都重复加载驱动极慢且偶发SQLException: No suitable driver。正确写法是在 Servlet 初始化时一次性加载// LoginServlet.java public class LoginServlet extends HttpServlet { static { try { Class.forName(net.ucanaccess.jdbc.UcanaccessDriver); } catch (ClassNotFoundException e) { e.printStackTrace(); // 必须打印否则 silent fail } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String url jdbc:ucanaccess:// getServletContext().getRealPath(/WEB-INF/db/shop.mdb) ;charsetUTF-8; // 关键显式指定 charset Connection conn null; try { conn DriverManager.getConnection(url); // ... 查询逻辑 } catch (SQLException e) { e.printStackTrace(); } finally { if (conn ! null) try { conn.close(); } catch (SQLException ignored) {} } } }说明static{}块在类加载时执行一次charsetUTF-8是解决中文字段乱码的核心参数缺了它INSERT INTO goods(name) VALUES(手机)会存成??。3.2 连接字符串参数详解不是所有参数都可省略UCanAccess 连接 URL 格式为jdbc:ucanaccess://mdb_path[;property1value1][;property2value2]参数必填说明实际值示例jdbc:ucanaccess://✅协议头固定写法jdbc:ucanaccess://mdb_path✅.mdb文件绝对路径推荐用getRealPath()D:\ideaProjects\shop_system\WebContent\WEB-INF\db\shop.mdbcharsetUTF-8✅强制指定数据库文本编码否则中文 insert/update 全变问号;charsetUTF-8memorytrue⚠️ 推荐启用内存缓存加速查询尤其商品列表页;memorytruejackcessOpenernet.ucanaccess.jdbc.JackcessOpener❌ 可省略仅当自定义 Jackcess 版本时才需指定—注意路径中不能有中文即使getRealPath()返回C:\用户\张三\...也会在DriverManager.getConnection()时抛java.net.URISyntaxException。解决方案开发机用户名用英文或把项目放在D:\shop_system这类纯英文路径。3.3 Access 中文乱码的终极排查表按顺序逐项验证现象检查项命令/操作修复方式登录页输入中文用户名后台查不到1.shop.mdb文件本身是否 UTF-8 编码用 Access 打开 → 文件 → 选项 → 高级 → 默认打开模式 → 设为“UnicodeUTF-8”在 Access 中另存为新 mdb勾选“保留 Unicode 格式”JSP 页面显示“???”2. JSP 文件保存编码用 Notepad 打开login.jsp→ 编码 → 转为 UTF-8 无 BOM保存后重启 Tomcat浏览器地址栏中文参数变乱码如?name手机3. Tomcatserver.xmlURIEncoding找到conf/server.xml在Connector port8080...标签内加URIEncodingUTF-8Connector port8080 protocolHTTP/1.1 URIEncodingUTF-8 /后台新增商品前台列表显示“”4.web.xml中jsp-config设置在web.xml的web-app根节点内添加jsp-configjsp-property-groupurl-pattern*.jsp/url-patternpage-encodingUTF-8/page-encoding/jsp-property-group/jsp-config必须加否则 JSP 编译器按 ISO-8859-1 解析提示“page-encodingUTF-8/page-encoding” 这行是学生最容易漏写的它决定了 JSP 编译成 Servlet 时的字符集比% page contentTypetext/html;charsetUTF-8%更底层。4. 避坑指南JSP Access 网上购物系统最常见的 5 类翻车现场这套系统看似简单但因为技术栈老旧、错误提示模糊、IDE 支持弱新手极易陷入“页面白屏但控制台没报错”的黑匣子状态。以下是我在指导 32 届毕设时统计出的最高频 5 类问题每一条都附真实现象、根因定位法和可立即执行的修复命令。4.1 现象访问login.jsp页面空白浏览器开发者工具 Network 标签显示 200但 Response 为空原因JSP 编译失败Tomcat 生成了空的.java文件位于work/Catalina/localhost/shop_system/org/apache/jsp/user/login_jsp.java但未报错日志。常见于 JSP 中用了 Java 8 不支持的语法如var关键字或pageEncoding错误导致编译器读入乱码。解决进入work/Catalina/localhost/shop_system/目录删除整个org/文件夹强制重新编译检查login.jsp第一行是否为% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%重启 Tomcat观察logs/catalina.out是否出现org.apache.jasper.JasperException: Unable to compile class for JSP4.2 现象登录时提示java.sql.SQLException: net.ucanaccess.jdbc.UcanaccessDriver原因ucanaccess-5.0.1.jar未被 Tomcat 加载。常见于① jar 放在src/下而非WEB-INF/lib/② IDEA 项目结构中lib目录未标记为Library③ jar 文件损坏下载不完整。解决在 IDEA 中右键ucanaccess-5.0.1.jar→Add as Library→ 选择shop_system模块打开Project Structure→Artifacts→ 展开shop_system:war exploded→ 确认WEB-INF/lib/下有该 jar右下角显示Included终端执行jar -tf WebContent/WEB-INF/lib/ucanaccess-5.0.1.jar \| head -n 5应看到net/ucanaccess/jdbc/UcanaccessDriver.class4.3 现象添加商品到购物车后刷新页面购物车为空或多个用户登录购物车内容互相污染原因购物车数据存在HttpSession中但未做session.setAttribute(cart, cartList)或cartList是静态变量static ListGoods cart new ArrayList();导致所有用户共享同一份内存。解决检查CartServlet.java中是否用request.getSession().setAttribute(cart, cartList)绝对禁止在 Servlet 类中声明static List存购物车必须每次从 session 取HttpSession session request.getSession(); ListGoods cart (ListGoods) session.getAttribute(cart); if (cart null) { cart new ArrayList(); session.setAttribute(cart, cart); }4.4 现象后台管理页admin/goods_list.jsp报javax.servlet.ServletException: java.lang.NoClassDefFoundError: Could not initialize class com.util.DBUtil原因DBUtil.java是工具类含static Connection getConnection()方法其static块中Class.forName(...)失败但异常被吞掉导致后续所有调用都NoClassDefFoundError。解决打开DBUtil.java找到static{}块在catch(ClassNotFoundException e)内加e.printStackTrace()重启 Tomcat看catalina.out是否输出java.lang.ClassNotFoundException: net.ucanaccess.jdbc.UcanaccessDriver若输出此错说明ucanaccess.jar未加载成功回到 4.2 处理4.5 现象Access 数据库被锁定提示The database has been placed in a state by user Admin on machine DESKTOP-XXX that prevents it from being opened原因Tomcat 未正常关闭.laccdb锁文件残留或多个 Servlet 同时getConnection()未close()导致连接未释放。解决关闭 Tomcat 进程任务管理器杀java.exe删除WebContent/WEB-INF/db/下的shop.laccdb文件注意不是.mdb在所有finally块中确保conn.close()和rs.close()PreparedStatement同理进阶防护在DBUtil.getConnection()中加超时Properties info new Properties(); info.put(lockTimeout, 5000); // 5秒锁等待 conn DriverManager.getConnection(url, info);5. 从能跑到能改三个可立即动手的实战增强点含代码与效果对比这套系统交付的是“能跑”但教学价值在于“能改”。我带学生做的第一轮增强永远聚焦三个低侵入、高可见、能讲清原理的点① 把硬编码密码改成 MD5 加密存储② 为商品列表加分页③ 给购物车加实时数量 badge。每个改动不超过 20 行代码却能把“数据库操作”“Servlet 生命周期”“JSP EL 表达式”三个核心概念串起来。5.1 密码加密从明文123456到MD5(123456)e10adc3949ba59abbe56e057f20f883eAccess 不支持PASSWORD()函数必须在 Java 层加密。学生常犯错在LoginServlet中对用户输入密码加密后去查数据库但数据库里存的还是明文。正确做法是——注册时加密登录时同样加密比对。步骤在RegisterServlet.java的doPost()中获取密码后立即加密String rawPwd request.getParameter(password); String md5Pwd DigestUtils.md5Hex(rawPwd); // 需引入 commons-codec-1.15.jar String sql INSERT INTO users(username, password) VALUES(?, ?); PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, md5Pwd); // 存加密后字符串 ps.executeUpdate();在LoginServlet.java中查库前先加密输入密码String inputPwd request.getParameter(password); String md5Input DigestUtils.md5Hex(inputPwd); String sql SELECT * FROM users WHERE username? AND password?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, md5Input); // 用加密后字符串匹配 ResultSet rs ps.executeQuery();效果数据库users.password字段从123456变成e10adc3949ba59abbe56e057f20f883e即使.mdb文件泄露也无法反推原始密码。这是 Web 安全的第一课。5.2 商品列表分页从一页 100 条到LIMIT 10 OFFSET 20Access 不支持LIMIT/OFFSET但支持TOP n和子查询模拟分页。我们用最简方案SELECT TOP 10 * FROM (SELECT TOP 30 * FROM goods ORDER BY id) AS t ORDER BY id DESC即“取前 30 条再从中取最后 10 条”。改造GoodsListServlet.javaint pageSize 10; int currentPage Integer.parseInt(request.getParameter(page)); int offset (currentPage - 1) * pageSize; // Access 分页 SQL兼容性最好 String sql SELECT TOP pageSize * FROM ( SELECT TOP (offset pageSize) * FROM goods ORDER BY id ASC ) AS t ORDER BY id DESC; PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery(); ListGoods goodsList new ArrayList(); while (rs.next()) { Goods g new Goods(); g.setId(rs.getInt(id)); g.setName(rs.getString(name)); goodsList.add(g); } request.setAttribute(goodsList, goodsList); request.setAttribute(currentPage, currentPage); request.setAttribute(totalPages, (int) Math.ceil(totalCount * 1.0 / pageSize)); request.getRequestDispatcher(goods_list.jsp).forward(request, response);在goods_list.jsp中加分页导航c:forEach begin1 end${totalPages} vari a hrefgoods_list?page${i}${i}/a /c:forEach效果原来goods_list.jsp一次查全表现在按页加载首屏时间从 2s 降到 200ms学生能直观理解“数据库分页不是前端 JS 控制而是 SQL 层面的事”。5.3 购物车 Badge从“去结算”到右上角红色数字3购物车数量要实时显示在每个页面右上角不能每次 reload 都查库。最佳实践是把 cartList 存 session用 EL 表达式${fn:length(sessionScope.cart)}直接渲染。前提确保CartServlet.java中已正确 setAttributeHttpSession session request.getSession(); session.setAttribute(cart, cartList); // cartList 是 ListGoods在header.jsp所有页面 include中加 badge% taglib prefixfn urihttp://java.sun.com/jsp/jstl/functions % !-- 购物车图标 -- a hrefcart.jsp i classicon-cart/i span classbadge${fn:length(sessionScope.cart)}/span /a注意sessionScope.cart是 JSP EL 访问 session 属性的标准写法fn:length()是 JSTL 函数需在web.xml中声明taglib或在 JSP 顶部加% taglib prefixfn urihttp://java.sun.com/jsp/jstl/functions %。这是 JSP 动态能力的典型体现——不用写 Java 代码纯标签完成逻辑。6. 教学延伸如何把这套系统变成你的“活教案”——三个可复用的验证技巧这套 JSP Access 系统的价值不在它多先进而在它足够“透明”。没有框架封装所有 request/response、session、JDBC 连接、JSP 编译过程都赤裸可见。我把它当作“Java Web 解剖实验室”每次带学生必做三件事看日志、断点、改字节码。这比讲一百遍 MVC 理论都管用。6.1 日志即教案用catalina.out追踪一次登录的完整链路Tomcat 的logs/catalina.out是最真实的教学现场。让学生在LoginServlet.java的doPost()开头加一行System.out.println([DEBUG] LoginServlet received: username username , ip request.getRemoteAddr());再在DBUtil.java的getConnection()中加System.out.println([DEBUG] DBUtil.getConnection() called, url url);重启后登录catalina.out会清晰打出[DEBUG] LoginServlet received: usernamezhangsan, ip127.0.0.1 [DEBUG] DBUtil.getConnection() called, urljdbc:ucanaccess://D:\...\shop.mdb;charsetUTF-8 [DEBUG] Query executed: SELECT * FROM users WHERE usernamezhangsan AND passworde10adc3949ba59abbe56e057f20f883e这就是一次完整的请求生命周期客户端 → Servlet → DBUtil → JDBC Driver → Access 文件。学生看着日志自然明白request.getParameter()从哪来、response.sendRedirect()往哪去、session.setAttribute()存在哪。6.2 断点即实验在index.jsp中设置条件断点观察 EL 表达式求值时机很多人以为% new java.util.Date() %是在 JSP 编译时执行其实是每次请求时执行。验证方法在index.jsp中写% System.currentTimeMillis() % % System.out.println(JSP scriptlet executed at System.currentTimeMillis()); %在 IDEA 中右键System.out.println(...)左侧空白处 →Add Breakpoint→Conditional→ 输入System.currentTimeMillis() % 1000 0每秒触发一次刷新页面观察控制台输出时间戳和断点触发频率你会发现每次刷新System.out打印的时间和% %输出的时间几乎一致且断点只在特定毫秒触发。这证明 JSP 中的 scriptlet 是 runtime 执行不是 compile-time。这个实验比讲 10 分钟 JSP 生命周期都直观。6.3 字节码即真相用javap看 JSP 如何变成 ServletJSP 最终会被 Tomcat 编译成.java文件再编译成.class。路径在work/Catalina/localhost/shop_system/org/apache/jsp/。比如login_jsp.java编译后是login_jsp.class。用命令行看它到底长啥样# 进入 work 目录后执行 javap -c org.apache.jsp.user.login_jsp | head -n 30输出类似public void _jspService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse); Code: 0: aload_0 1: aload_1 2: aload_2 3: invokespecial #15 // Method org/apache/jasper/runtime/HttpJspBase._jspService:(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V 6: return重点看invokespecial #15它调用的是HttpJspBase._jspService而_jspService方法内部就是你写的% %和% %被翻译成的 Java 字节码。这就是“JSP 是 Servlet 的语法糖”的铁证——学生亲眼看到自己写的 HTML 混合 Java最终变成了标准的 Java 方法调用。我带过的每一届学生只要亲手做过这三件事再遇到 Spring Boot 的Controller、MyBatis 的SqlSession就不会再问“它怎么知道我要查数据库”。因为他们已经见过最原始的 request、response、connection、session 是如何一环扣一环咬合运转的。希望帮到你。本文还有配套的精品资源点击获取
