JSP网上购物系统开发实战:JavaBean、Servlet与JSP整合要点 简介面向Java Web初学者的学校实训项目整合JavaBean、Servlet与JSP三大核心技术完整实现网上购物系统可有效解决毕业生实训或课程设计中的项目落地问题。压缩包共179个文件包含50个Java源码与50个class文件、29个JSP页面、8个TLD标签库描述文件以及数据库脚本、jar依赖、PDF/PPT说明文档等整体仅7.52MB目录结构清晰便于按功能模块检索学习。已有1187人学习下载内容覆盖MVC设计模式、JDBC数据访问、Session购物车、异常处理与安全防护等关键知识点并配有页面截图与图片资源适合毕业实训、课设参考和JavaWeb入门者。通过此项目可掌握从DAO到Servlet控制层再到JSP视图层的完整开发流程理解电商系统业务逻辑与代码组织方式同时熟悉web.xml配置、标签库使用及数据库交互方法是一份高性价比的实战学习资料。1. 学校实训 JSP 项目网上购物系统的 JavaBeanServlet 组合很多人第一次拿到“网上购物系统”这个 JSP 实训项目时会以为重点是购物车和商品展示但真正决定成绩的是 JavaBean、Servlet、JSP 三者的分工。JavaBean 用来封装商品和用户的数据Servlet 接收浏览器请求并控制页面跳转JSP 负责把数据渲染成 HTML。这个结构听起来简单但大部分运行失败的项目问题都出在 Servlet 配置、session 使用和 JSP 里的类型转换上。下面直接以这个项目为对象把环境搭建、核心代码、购物车会话和答辩前的优化一次讲完。如果你正在做这个实训项目按照这里的方式把请求路径走一遍比死记代码更有用。2. 网上购物系统的运行环境搭建与 Eclipse 导入步骤2.1 拿到项目 zip 后先检查目录结构而不是直接启动拿到的压缩包数字节很小但里面往往同时包含完整 Eclipse 工程和一份数据库脚本。我一般不会急着解压到桌面而是先建一个纯英文目录比如D:\work\shop避免中文路径导致 Tomcat 解析文件失败。解压后先看有没有.project和.classpath文件这能直接区分它是 Eclipse 导出工程还是纯源码包。常见的网上购物系统目录结构类似这样shop/ ├── src/ │ ├── com/shop/bean/ # JavaBean 实体类 │ ├── com/shop/servlet/ # Servlet 控制器 │ └── com/shop/util/ # 数据库连接工具 ├── WebContent/ │ ├── jsp/ │ │ ├── login.jsp │ │ ├── register.jsp │ │ ├── index.jsp │ │ └── cart.jsp │ ├── WEB-INF/ │ │ ├── web.xml │ │ └── lib/ │ └── css/ js/ images/ └── .project这个结构里src下是 Java 源码WebContent是 Web 根目录。JSP 页面在运行时会由 Tomcat 编译成 servlet class但源 Java 文件必须在src下否则无法被容器找到。如果 zip 里没有.project文件就不能用 Eclipse 的“Existing Projects into Workspace”导入需要新建一个 Dynamic Web Project再把WebContent和src内容拷进去。2.2 确认 JDK、Tomcat 和 Servlet 版本兼容这个项目基于 JSP 2.3 和 Servlet 3.1 左右所以常见的搭配是 JDK 8 Tomcat 8.5。Tomcat 10 不建议直接使用因为它的包名已经换成jakarta.servlet旧代码里的import javax.servlet.http.HttpServlet会在运行时直接报ClassNotFoundException。在命令行里查看当前 JDK 版本java -version如果显示的不是 1.8 或 11需要到环境变量里调整JAVA_HOME。Eclipse 中还需要在项目属性里指定 Targeted Runtime否则javax.servlet.http.HttpServlet这个类找不到编译会报错。这里给出一个参考兼容表项目依赖推荐版本说明JDK1.8 或 11网上购物系统不涉及较新的语法8 足够Tomcat8.5 / 9.0避免 Tomcat 10 的 Jakarta 命名空间问题Servlet API3.1对应javax.servlet包JSP API2.3Tomcat 自带不需要额外引入MySQL Connector5.1.x 或 8.0.x注意驱动类名不同这里要特别提醒不要自己下载一个 servlet-api.jar 放到WEB-INF/lib下因为 Tomcat 已经内置了同名类目录重了会冲突轻则启动失败重则造成诡异的重写方法错误。2.3 用 Eclipse 导入项目并启动 Tomcat导入步骤其实很固定我一般按这个顺序操作打开 Eclipse选择 File → Import → General → Existing Projects into Workspace。Select root directory 指向D:\work\shop如果识别成功Projects 列表会出现项目名。如果导入后 Java 类报错右键项目 → Properties → Targeted Runtimes勾选 Tomcat。右键项目 → Run As → Run on Server选择 Tomcat 9完成启动。浏览器打开http://localhost:8080/shop/看到首页就说明环境配通了。如果启动时出现端口占用可以去 Tomcat 的server.xml中把 Connector port 改成 8081 或 8082。访问地址也要同步带端口。Tomcat 控制台出现一行Server startup in [xxx] milliseconds才代表部署成功不要只看页面没反应就反复重启。2.4 JSP 编译后的 class 文件与找不到主类排错实训中出现“错误: 找不到或无法加载主类 org.jeecg.JeecgSystemApplication”这类信息通常是因为用普通 Java 应用方式启动了一个 Spring Boot 类而当前项目不是 Spring Boot 工程。网上购物系统不存在 main 方法入口它必须依托 Tomcat 运行。JSP 编译后的 class 文件实际存放在 Tomcat 的work/Catalina/localhost/项目名/org/apache/jsp/目录下如果你改动 JSP 后没看到效果可以先删除整个work目录再重启 Tomcat强制重新编译。另一个常见错误是 Tomcat 报ClassNotFoundException: javax.servlet.http.HttpServlet这代表项目 Build Path 里缺少 Servlet 容器依赖。解决方式是在项目属性里勾选 Targeted Runtimes或者在 Java Build Path 的 Libraries 中点击 Add Library → Server Runtime → Tomcat而不是去网上下载 jar 包。环境配置到这里后面写 JavaBean 和 Servlet 时就不会被这些基础问题打断。3. JavaBean Servlet 如何驱动网上购物系统的数据流3.1 JavaBean 不只是 getter/setter还承担数据校验网上购物系统里最典型的 JavaBean 有 User、Product、CartItem 和 Cart。很多学生只写字段和 getter/setter但这样写唯一的作用是当容器传输数据的工具。实训评分时一个能体现工程能力的做法是在 JavaBean 中加入简单的业务校验比如价格不能为负、库存不能小于零。下面是一个 Product 的典型写法package com.shop.bean; public class Product { private int id; private String name; private double price; private String image; private String description; private int stock; public Product() {} public Product(int id, String name, double price) { this.id id; this.name name; this.price price; } public double getPrice() { return price; } public void setPrice(double price) { if (price 0) { throw new IllegalArgumentException(价格不能为负数); } this.price price; } // 其他 getter/setter 省略 }这段代码里最关键的是必须保留无参构造方法因为 JSP 的jsp:useBean标签通过反射创建对象时会调用无参构造。如果只写了带参构造页面运行时会抛InstantiationException。setPrice中加了一个简单的金额校验这不算复杂但能在答辩时展示你已经理解了 JavaBean 不只是数据仓库它还可以约束数据的合法性。3.2 Servlet 的 doGet/doPost 分工与登录流程网上购物系统中Servlet 是唯一负责接收请求的入口。以登录为例用户从login.jsp提交表单到 LoginServletLoginServlet 再调用数据库工具类找到 User 对象然后把结果放到 session 或 request 中。这个流程看着简单但 doGet 和 doPost 的分工很容易搞混。package com.shop.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import com.shop.bean.User; import com.shop.util.DBUtil; WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); User user DBUtil.findUser(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(loginUser, user); response.sendRedirect(request.getContextPath() /index.jsp); } else { request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(/jsp/login.jsp).forward(request, response); } } }登录失败用 forward 转发登录成功用 sendRedirect 重定向。这样做的原因是重定向会让浏览器地址栏发生跳转用户刷新页面时不会重复提交登录表单forward 则保留原来的请求地址登录失败后刷新页面会再次提交表单这是很多购物系统出现重复数据的原因之一。3.3 用 web.xml 或注解配置 Servlet 映射上面代码里使用了WebServlet(/login)这是 Servlet 3.0 之后提供的注解方式不需要在 web.xml 中维护映射关系。但很多学校实训项目还是保留旧式 web.xml 配置因为考试环境可能用老版教材。下面给出同一份映射的 web.xml 写法servlet servlet-nameloginServlet/servlet-name servlet-classcom.shop.servlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameloginServlet/servlet-name url-pattern/login/url-pattern /servlet-mapping这两种配置方式不能同时存在否则同一个 url-pattern 会被解析成两个 servlet启动时可能不会报错但实际请求时容易走到错误类。下面整理一张网上购物系统的常见 URL 映射表方便在调试时对照请求路径Servlet 类作用/loginLoginServlet用户登录/registerRegisterServlet用户注册/productProductServlet商品列表与详情/cartCartServlet添加购物车、修改数量/orderOrderServlet提交订单这张表就是整个系统的坐标。无论页面怎么跳转最后落脚点都是这些 Servlet 对应的方法所以调试时可以先把每个 URL 直接访问一遍看 Servlet 是否正常响应。3.4 数据从 Servlet 传到 JSP 的三种作用域Servlet 拿到数据后需要把数据交给 JSP 展示。网上购物系统里常用 request、session、application 三种作用域。商品列表适合放在 request 中因为每次刷新都会重新查询数据库登录用户信息必须放在 session 中因为多个页面都要读取购物车也建议放在 session 中因为它是用户在会话期间的持久状态。下面这段 JSP 代码展示了如何取出商品列表% page contentTypetext/html; charsetUTF-8 % % page importjava.util.List, com.shop.bean.Product % % ListProduct products (ListProduct) request.getAttribute(productList); for (Product p : products) { % div classproduct-item h3% p.getName() %/h3 p价格% p.getPrice() %/p a hrefcart?productId% p.getId() %加入购物车/a /div % } %这段代码有两个容易踩坑的点。第一个是强转之前必须判断request.getAttribute(productList)是否为 null否则 Servlet 直接把页面转发回来时这里会抛 NullPointerException。第二个是a标签里的路径最好加上${pageContext.request.contextPath}也就是写成项目根路径开头否则在带项目名的部署环境下会 404。4. JSP 页面渲染、Session 会话与购物车实现4.1 用 jsp:useBean 简化个人信息展示页网上购物系统的用户中心页通常要展示当前登录用户的昵称、邮箱、电话等信息。如果用 scriptlet 写太多 Java 代码页面会显得很笨重。常见的简化写法是用jsp:useBean拿到 session 中的用户对象再通过jsp:getProperty输出属性值jsp:useBean iduser scopesession classcom.shop.bean.User / h2欢迎jsp:getProperty nameuser propertynickname //h2 p邮箱jsp:getProperty nameuser propertyemail //p这里scopesession会先查找 session 里 key 为 user 的对象如果找不到才会自动 new 一个 User。因此在 Servlet 里session.setAttribute(user, user)的 key 必须和这里的 id 一致否则页面会输出 null 或者空对象。对“jsp个人信息展示页面”这个搜索意图来说这样写既简洁又不会出现 scriptlet 的强制类型转换问题。4.2 购物车的 JavaBean 设计与会话存储购物车实体类通常有两个CartItem 表示一行商品Cart 表示整个购物车。Cart 持有ListCartItem并提供 add、remove、update 方法。这里给一个简化版package com.shop.bean; import java.util.ArrayList; import java.util.List; public class Cart { private ListCartItem items new ArrayList(); public void add(CartItem item) { for (CartItem i : items) { if (i.getProductId() item.getProductId()) { i.setQuantity(i.getQuantity() item.getQuantity()); return; } } items.add(item); } public double getTotalPrice() { double total 0; for (CartItem item : items) { total item.getProduct().getPrice() * item.getQuantity(); } return total; } public ListCartItem getItems() { return items; } public int getItemCount() { int count 0; for (CartItem item : items) { count item.getQuantity(); } return count; } }这个类的关键是add方法里先判断商品是否已经存在如果存在就只增加数量而不是重复添加一行。这个逻辑在实训项目里很常见但要提醒的是getTotalPrice依赖item.getProduct().getPrice()如果 Product 对象没有被完整赋值会出现默认 0.0 的价格购物车总金额变成 0。在 Servlet 中添加购物车时要确保把完整的商品信息从数据库查出来再放入 CartItem。Cart 对象放在 session 中存取代码如下Cart cart (Cart) session.getAttribute(cart); if (cart null) { cart new Cart(); session.setAttribute(cart, cart); } cart.add(cartItem);这里不能把 cart 放到 request 中因为 request 的生命周期只覆盖一次请求用户跳到购物车页面后对象就被回收了。session 默认保持 30 分钟足够覆盖一次完整的浏览和下单过程。4.3 购物车列表页面的数量修改与 JSP 表单购物车页面的核心是允许用户修改数量下面是一个标准的 JSP 输出片段% page importcom.shop.bean.Cart, com.shop.bean.CartItem % % Cart cart (Cart) session.getAttribute(cart); if (cart null) { out.print(p购物车为空/p); return; } % table border1 trth商品名/thth单价/thth数量/thth小计/th/tr % for (CartItem item : cart.getItems()) { % tr td% item.getProduct().getName() %/td td% item.getProduct().getPrice() %/td td form actioncart methodpost input typehidden nameproductId value% item.getProductId() % / input typenumber namequantity value% item.getQuantity() % min1 / input typesubmit value更新 / /form /td td% item.getProduct().getPrice() * item.getQuantity() %/td /tr % } % /table p总金额% cart.getTotalPrice() %/p这个页面的坑在于actioncart如果页面位于/jsp/cart.jsp相对路径会解析成/jsp/cart从而 404。正确写法是% request.getContextPath() %/cart或者使用${pageContext.request.contextPath}/cart。在 CartServlet 的 doPost 中也要注意quantity若为空或负数需要回退成 1否则会在数量计算时产生负数库存。4.4 屏蔽 JSP 离开页面提示与防止重复提交演示项目时浏览器底部经常弹出“离开此页面后数据不会被保存”的提示非常影响观感。这个提示来自表单页面的beforeunload事件可以通过一行脚本关闭window.onbeforeunload null;但要注意这行代码并不能解决真正的重复提交问题。网上购物系统的下单按钮如果被连续点击会产生多个相同订单。实训阶段最稳妥的防重方案是使用一次性令牌JSP 表单加一个input typehidden nametoken value% session.getAttribute(orderToken) % /Servlet 收到请求后先比对 session 中的 token如果一致就执行下单并清空 token如果不一致就拒绝。这种方式比单纯屏蔽离开页面提示更值得写到答辩说明里。JSP 页面还可以用% include file/common/header.jsp %抽取公共导航栏。静态 include 在编译阶段把内容插入当前页面所以公共变量的作用域会扩展到主页面jsp:include则是运行时的动态包含适合更换频率更高的区域。网上购物系统的导航栏和页脚一般用静态 include 就够了既能减少重复代码也不会引入额外的请求延迟。5. 答辩前必做的 JSP 项目优化编码、JSTL 与错误排查5.1 用 Filter 统一处理编码和登录校验很多实训项目在提交表单后出现中文乱码原因只在一处 Servlet 里设置了编码其他请求没设置。与其在每个 Servlet 里写request.setCharacterEncoding(UTF-8)不如用一个 Filter 统一处理package com.shop.filter; import java.io.IOException; import javax.servlet.*; public class EncodingFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(UTF-8); response.setCharacterEncoding(UTF-8); chain.doFilter(request, response); } }Filter 减轻了 Servlet 的重复代码也能顺便处理登录校验。比如只拦截/cart、/order这些需要登录的路径。注意放行登录和注册接口否则会出现“重定向次数过多”的死循环。这个 Filter 是答辩时非常容易讲清楚的一个加分点因为几乎所有 JSP 项目都存在中文乱码问题。5.2 用 JSTL 替换 scriptlet减少页面里的 Java 代码网上购物系统的 JSP 页面如果满屏都是% %代码可读性会很差。最直接的优化是把循环和 if 判断换成 JSTL。在 JSP 头部引入标签库% taglib urihttp://java.sun.com/jsp/jstl/core prefixc %然后用c:forEach循环商品列表c:forEach varp items${productList} div classproduct-item h3${p.name}/h3 p价格${p.price}/p a href${pageContext.request.contextPath}/cart?productId${p.id}加入购物车/a /div /c:forEachJSTL 的items${productList}底层会通过反射调用 Product 的 getter所以 JavaBean 中必须有getName()、getPrice()、getId()。如果页面里还需要输出 JSON 数据给前端建议在 Java 类里用 JSONArray 构建好字符串再通过${jsonList}输出到 JSP避免在页面手写字符串拼接导致引号转义错误。5.3 答辩前快速验证的常见错误清单现象检查点中文乱码每个 Servlet 是否在读取参数前设置 UTF-8数据库 URL 是否带字符集参数404 找不到页面URL 是否包含项目名web.xml welcome-file 是否正确页面显示 nulljsp:useBean 的 id 是否与 session.setAttribute 的 key 一致订单重复创建是否有防重复提交令牌没有则加 hidden token修改 JSP 不生效删除 Tomcat work 目录后重启再刷新浏览器答辩前按这张表把所有页面都过一遍会节省大量现场调试时间。本文还有配套的精品资源点击获取