ARTICLE DETAIL

资讯详情

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

Java Web开发入门:基于Servlet+JSP+MySQL构建电商网站全流程解析

Java Web开发入门:基于Servlet+JSP+MySQL构建电商网站全流程解析 简介这是一套基于Java Web经典技术栈开发的购物网站系统面向计算机专业学生及Java初学者专为课程设计、期末大作业与项目实战练习打造。项目采用Servlet处理业务逻辑、JSP实现动态页面展示、MySQL存储商品与用户数据结构清晰、功能完整曾获98分高分评价具备良好的教学示范性与工程参考价值。压缩包共69个文件包含15个核心Java源码、13个JSP页面、16个编译后Class文件、11个GIF动画及6个JPG图片等资源辅以SQL建表脚本、CSS样式、JS交互逻辑及README说明文档总大小仅292KB轻量易部署。目前已有231人学习下载资源目录组织规范涵盖用户注册登录、商品浏览、购物车管理、订单提交等典型电商模块代码注释充分数据库脚本可一键导入开箱即用是掌握Java Web三层架构与MVC思想的理想实践范例。1. 从零到一一个经典Java Web购物网站的构建全景最近在整理硬盘翻出来一个十多年前刚入行时做的Java Web项目——一个基于ServletJSPMySQL的购物网站。现在看技术栈确实“复古”但它的价值恰恰在于此。对于很多刚接触Java Web开发的朋友来说Servlet和JSP是绕不开的起点它们直接对应着HTTP请求处理和动态页面渲染的核心原理。理解了这个“原始”的模型再去学习Spring MVC、Spring Boot这些现代框架你会感觉豁然开朗因为它们本质上是在这个模型上做的封装和优化。这个项目麻雀虽小五脏俱全。它包含了用户注册登录、商品浏览、购物车管理、订单生成与查看等电商核心功能。使用的技术就是最经典的Java EE三件套Servlet作为控制器Controller处理所有业务逻辑和请求转发JSP作为视图View负责数据的展示MySQL作为模型Model存储所有业务数据。虽然现在企业级开发很少直接裸写Servlet和JSP了但通过亲手搭建这样一个系统你能把Web开发的MVC思想、会话管理、数据库连接池、分层架构等核心概念吃得透透的。无论你是正在学习Java Web的学生还是想巩固基础、面试前回顾核心原理的开发者跟着这个思路走一遍收获绝对比单纯背“八股文”要大得多。2. 环境搭建与项目初始化避开那些“新手专属”的坑动手之前得先把“战场”布置好。很多人卡在第一步不是环境变量配不对就是依赖库下载不下来。咱们一步步来把常见的坑都提前标出来。2.1 JDK与IDE的选择稳定压倒一切首先你需要一个Java开发环境。别急着追求最新版对于学习型项目JDK 8或JDK 11这两个LTS长期支持版本是更稳妥的选择兼容性最好。去Oracle官网或Adoptium下载安装后配置JAVA_HOME环境变量指向你的JDK安装目录并把%JAVA_HOME%\bin添加到PATH中。在命令行输入java -version能正确显示版本信息这一步才算成功。注意配置环境变量后务必重新打开命令行窗口否则可能不生效。这是新手常犯的错误。集成开发环境IDE我强烈推荐IntelliJ IDEA Community Edition社区版它对Java Web开发的支持非常友好而且是免费的。别用太新的版本比如热词里提到的idea2026.2这可能是未来版本目前稳定版是2023.x或2024.x。新版本有时会对老旧技术如JSP的支持有变动可能遇到像“JSP页面中的函数点击引用无法跳转”这类IDE自身的问题用稳定版能减少不必要的麻烦。2.2 Web服务器与数据库Tomcat和MySQL的安装要点我们的项目需要运行在一个Servlet容器里Apache Tomcat是不二之选。去Apache官网下载Tomcat 8.5或9.x版本解压到一个没有中文和空格的路径下。记住CATALINA_HOME这个环境变量它应该指向你的Tomcat根目录虽然不配也能用但配了之后一些工具识别起来更方便。数据库方面自然是MySQL。建议下载MySQL 5.7或8.0的社区版。安装过程中牢记你为root用户设置的密码。安装完成后可以通过MySQL自带的命令行工具或者MySQL Workbench这个图形化工具来操作数据库。Workbench的“使用命令行新建数据表”功能很方便但初期为了理解SQL我建议多手写命令。2.3 创建动态Web项目与依赖管理在IDEA中不要创建普通的Java项目要创建“Java Enterprise”项目并勾选“Web Application”。这会自动生成标准的Web项目结构src目录放Java代码web目录或webapp下放WEB-INF、JSP页面和静态资源。接下来是关键一步引入依赖。我们至少需要MySQL Connector/JJava连接MySQL的驱动JAR包。JSTL标签库让JSP页面摆脱大量Java脚本更整洁。数据库连接池如HikariCP或Druid这是生产级项目的必备绝不能再用DriverManager获取连接了。传统的做法是把这些JAR包下载下来复制到项目的WEB-INF/lib目录下。但更现代、更推荐的做法是使用Maven或Gradle进行依赖管理。以Maven为例在项目根目录创建pom.xml文件在dependencies节点内添加上述库的坐标IDE会自动下载并管理依赖。这能彻底解决“ClassNotFound”这类因缺少JAR包引发的问题。!-- 在pom.xml中的示例依赖 -- dependencies !-- Servlet API -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- JSP API -- dependency groupIdjavax.servlet.jsp/groupId artifactIdjavax.servlet.jsp-api/artifactId version2.3.3/version scopeprovided/scope /dependency !-- JSTL -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- HikariCP 连接池 -- dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId version5.0.1/version /dependency /dependencies3. 数据库设计与核心表结构剖析数据库是系统的基石设计得好后期开发事半功倍。我们这个购物网站至少需要五张核心表用户表、商品表、商品分类表、订单表、订单明细表。我们来详细设计一下并解释每个字段的用意。3.1 表结构定义与关系建立用户表 (user)这张表存储用户的基本信息。id是主键通常用自增整数。username和password是登录凭证密码字段务必存储加密后的散列值如MD5、SHA-256更推荐bcrypt绝对不要存明文。email和phone用于联系和找回密码。create_time记录注册时间。CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL UNIQUE COMMENT 用户名唯一, password varchar(255) NOT NULL COMMENT 加密后的密码, email varchar(100) DEFAULT NULL, phone varchar(20) DEFAULT NULL, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;商品分类表 (category)用于对商品进行分类如“手机”、“电脑”、“服装”。这是一个简单的自关联表parent_id为0表示一级分类。CREATE TABLE category ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL COMMENT 分类名称, parent_id int(11) DEFAULT 0 COMMENT 父分类ID0为根分类, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品分类表;商品表 (product)这是系统的核心数据表。name和description描述商品。price用DECIMAL类型精确存储金额。stock库存是关键字段在高并发下单时需要谨慎处理。category_id外键关联到分类表。image_url存储商品主图的路径。CREATE TABLE product ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(200) NOT NULL, description text, price decimal(10,2) NOT NULL COMMENT 商品价格精确到分, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存数量, category_id int(11) DEFAULT NULL, image_url varchar(500) DEFAULT NULL COMMENT 商品图片路径, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category_id), CONSTRAINT fk_product_category FOREIGN KEY (category_id) REFERENCES category (id) ON DELETE SET NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;订单表 (order) 与订单明细表 (order_item)这里的设计体现了数据库范式的一个常见实践。订单表order注意order是SQL关键字有时需要用反引号或改名如orders记录订单的概要信息属于哪个用户user_id、总金额total_amount、状态status如0待支付、1已支付、2已发货、3已完成、收货地址等。 订单明细表order_item则记录订单中具体购买了哪些商品。一个订单对应多条明细。这里存储了商品快照信息product_name,product_price因为商品信息未来可能会变更但订单历史需要保持不变。CREATE TABLE order ( id varchar(32) NOT NULL COMMENT 订单号不使用自增ID常用时间戳随机数生成, user_id int(11) NOT NULL, total_amount decimal(10,2) NOT NULL, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 订单状态, address varchar(500) NOT NULL COMMENT 收货地址, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user (user_id), CONSTRAINT fk_order_user FOREIGN KEY (user_id) REFERENCES user (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表; CREATE TABLE order_item ( id int(11) NOT NULL AUTO_INCREMENT, order_id varchar(32) NOT NULL COMMENT 关联订单ID, product_id int(11) NOT NULL, product_name varchar(200) NOT NULL COMMENT 商品快照名称, product_price decimal(10,2) NOT NULL COMMENT 商品快照单价, quantity int(11) NOT NULL COMMENT 购买数量, PRIMARY KEY (id), KEY idx_order (order_id), CONSTRAINT fk_item_order FOREIGN KEY (order_id) REFERENCES order (id), CONSTRAINT fk_item_product FOREIGN KEY (product_id) REFERENCES product (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单明细表;3.2 数据库连接池的配置与使用为什么必须用连接池因为每次HTTP请求都创建和销毁一个数据库连接开销巨大性能极差。连接池预先创建好一批连接用的时候取用完了还实现了连接的复用。这里以HikariCP为例我们需要一个工具类来初始化它。在src下创建一个util包新建DatabaseUtil.java。这里采用单例模式确保全局只有一个数据源。package com.yourproject.util; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; public class DatabaseUtil { private static volatile HikariDataSource dataSource; private DatabaseUtil() {} // 私有构造 public static DataSource getDataSource() { if (dataSource null) { synchronized (DatabaseUtil.class) { if (dataSource null) { HikariConfig config new HikariConfig(); config.setJdbcUrl(jdbc:mysql://localhost:3306/your_database?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai); config.setUsername(your_username); config.setPassword(your_password); config.setMaximumPoolSize(10); // 最大连接数根据应用负载调整 config.setMinimumIdle(5); // 最小空闲连接 config.setConnectionTimeout(30000); // 获取连接超时时间 config.setIdleTimeout(600000); // 连接空闲超时时间 config.setMaxLifetime(1800000); // 连接最大生命周期 config.addDataSourceProperty(cachePrepStmts, true); config.addDataSourceProperty(prepStmtCacheSize, 250); config.addDataSourceProperty(prepStmtCacheSqlLimit, 2048); dataSource new HikariDataSource(config); } } } return dataSource; } public static Connection getConnection() throws SQLException { return getDataSource().getConnection(); } }实操心得连接池参数需要根据实际压力调整。maximumPoolSize不是越大越好设置过大反而可能导致数据库连接耗尽。serverTimezone参数对于高版本MySQL驱动非常重要不设置可能导致时间错误。4. 核心业务逻辑层Servlet的设计与实现Servlet扮演着控制器的角色它接收来自前端的请求如/login,/addToCart调用相应的业务逻辑Service层然后决定将请求转发Forward或重定向Redirect到哪个JSP页面进行展示。这是MVC中“C”的部分。4.1 用户登录与会话管理我们创建一个LoginServlet它继承自HttpServlet并重写doPost方法处理表单提交。核心流程从request对象中获取用户提交的用户名和密码。对密码进行相同的加密处理比如MD5。调用UserService的login方法传入用户名和加密后的密码去数据库查询。如果查询到用户则将用户对象至少是用户ID和用户名存入HttpSession中。HttpSession是服务器为每个用户创建的会话对象可以跨请求保存数据。登录成功重定向到首页response.sendRedirect(“index.jsp”)失败则转发回登录页并提示错误信息request.setAttribute(“error”, “用户名或密码错误”)request.getRequestDispatcher(“login.jsp”).forward(request, response)。package com.yourproject.web.servlet; import com.yourproject.model.User; import com.yourproject.service.UserService; import com.yourproject.service.impl.UserServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; import java.io.IOException; WebServlet(/login) // 使用注解配置Servlet映射路径替代web.xml配置 public class LoginServlet extends HttpServlet { private UserService userService new UserServiceImpl(); Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); // 必须设置防止中文乱码 response.setContentType(text/html;charsetUTF-8); String username request.getParameter(username); String password request.getParameter(password); // 实际项目中应对密码进行加密这里简化为明文对比仅为演示切勿用于生产 // String encryptedPwd MD5Util.encrypt(password); User user userService.login(username, password); if (user ! null) { // 登录成功将用户信息存入Session HttpSession session request.getSession(); session.setAttribute(currentUser, user); // 可选设置Session过期时间秒 // session.setMaxInactiveInterval(30 * 60); // 重定向到首页防止表单重复提交 response.sendRedirect(request.getContextPath() /index.jsp); } else { // 登录失败设置错误信息并转发回登录页 request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }避坑指南关于Servlet路径映射的404错误。热词中提到了servlet.service() for servlet [dispatcherservlet] in context with path [] threw exception这通常是Spring MVC项目中的错误。在我们纯Servlet项目中如果访问Servlet返回404请检查1.WebServlet注解的路径是否正确是否以/开头。2. 如果使用web.xml配置检查servlet和servlet-mapping配置是否正确。3. 项目是否成功部署到了Tomcat并启动了服务。4.2 商品展示与分页查询商品列表页通常需要分页。我们创建一个ProductListServlet它需要接收两个参数page当前页码和size每页条数可默认。核心流程获取请求参数page和size并处理默认值如page1 size10。调用ProductService的getProductsByPage方法传入页码和大小返回当前页的商品列表ListProduct。同时需要调用ProductService的countProducts方法获取商品总数用于计算总页数。将商品列表productList、当前页currentPage、总页数totalPage等数据放入request属性中。转发到product_list.jsp页面进行渲染。这里的关键是分页SQL的编写。以MySQL为例使用LIMIT语法LIMIT (page-1)*size, size。例如查询第2页每页10条SELECT * FROM product LIMIT 10, 10。// 在ProductService实现类中的分页查询方法 public ListProduct getProductsByPage(int pageNum, int pageSize) { String sql SELECT * FROM product LIMIT ?, ?; // 计算偏移量 int offset (pageNum - 1) * pageSize; try (Connection conn DatabaseUtil.getConnection(); PreparedStatement pstmt conn.prepareStatement(sql)) { pstmt.setInt(1, offset); pstmt.setInt(2, pageSize); ResultSet rs pstmt.executeQuery(); ListProduct list new ArrayList(); while (rs.next()) { Product product new Product(); product.setId(rs.getInt(id)); product.setName(rs.getString(name)); // ... 设置其他属性 list.add(product); } return list; } catch (SQLException e) { e.printStackTrace(); return Collections.emptyList(); } }4.3 购物车与订单生成的原子性操作购物车通常使用HttpSession来存储因为它是用户级别的临时数据。我们可以用一个MapInteger, CartItem存在Session里key是商品IDCartItem对象包含商品信息和购买数量。添加到购物车AddToCartServlet接收商品ID和数量从Session中获取购物车Map如果商品已存在则增加数量否则新建一个CartItem放入Map。生成订单这是整个系统最需要谨慎处理的地方涉及“库存扣减”和“订单创建”两个必须同时成功的操作必须保证事务的原子性。事务开始在Service层方法上我们需要手动管理数据库事务。获取Connection后设置conn.setAutoCommit(false)。检查并扣减库存遍历购物车中的每个商品执行UPDATE product SET stock stock - ? WHERE id ? AND stock ?。这个SQL语句利用了数据库的行锁和stock ?的条件判断在更新时同时检查库存是否充足防止超卖。如果更新影响的行数为0说明库存不足需要回滚事务并抛出异常。创建订单主表和明细表库存扣减成功后生成一个唯一的订单号可以用时间戳随机数插入order表和order_item表。提交或回滚所有步骤成功则conn.commit()任何一步失败则conn.rollback()并清理现场如恢复购物车这需要根据业务逻辑设计。清理购物车订单生成成功从Session中移除该用户的购物车数据。// OrderService中创建订单的方法简化版展示事务控制 public boolean createOrder(Order order, ListCartItem cartItems) { Connection conn null; try { conn DatabaseUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 // 1. 检查并扣减库存 for (CartItem item : cartItems) { String sql UPDATE product SET stock stock - ? WHERE id ? AND stock ?; try (PreparedStatement pstmt conn.prepareStatement(sql)) { pstmt.setInt(1, item.getQuantity()); pstmt.setInt(2, item.getProductId()); pstmt.setInt(3, item.getQuantity()); int affectedRows pstmt.executeUpdate(); if (affectedRows 0) { throw new SQLException(商品ID: item.getProductId() 库存不足或不存在下单失败); } } } // 2. 插入订单主表 String orderSql INSERT INTO order (id, user_id, total_amount, status, address) VALUES (?, ?, ?, ?, ?); try (PreparedStatement pstmt conn.prepareStatement(orderSql)) { pstmt.setString(1, order.getId()); pstmt.setInt(2, order.getUserId()); pstmt.setBigDecimal(3, order.getTotalAmount()); pstmt.setInt(4, order.getStatus()); pstmt.setString(5, order.getAddress()); pstmt.executeUpdate(); } // 3. 插入订单明细表 String itemSql INSERT INTO order_item (order_id, product_id, product_name, product_price, quantity) VALUES (?, ?, ?, ?, ?); try (PreparedStatement pstmt conn.prepareStatement(itemSql)) { for (CartItem item : cartItems) { pstmt.setString(1, order.getId()); pstmt.setInt(2, item.getProductId()); pstmt.setString(3, item.getProductName()); pstmt.setBigDecimal(4, item.getProductPrice()); pstmt.setInt(5, item.getQuantity()); pstmt.addBatch(); // 加入批处理 } pstmt.executeBatch(); // 执行批处理 } conn.commit(); // 提交事务 return true; } catch (SQLException e) { e.printStackTrace(); if (conn ! null) { try { conn.rollback(); // 回滚事务 } catch (SQLException ex) { ex.printStackTrace(); } } return false; } finally { if (conn ! null) { try { conn.setAutoCommit(true); // 恢复自动提交模式 conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }核心要点这里的事务控制是在Service层通过同一个Connection手动管理的。在高并发场景下仅靠数据库事务和行锁可能还不够还需要考虑“秒杀”等场景下的超卖问题可能会引入分布式锁或使用更高级的队列机制。但对于我们这个学习项目理解这个基本的事务模型至关重要。5. 视图层JSP页面的现代化写法与优化JSP页面负责展示数据。传统的JSP写法会混入大量Java代码Scriptlet如% ... %这导致页面难以维护。现代的做法是彻底摒弃Scriptlet采用JSTL标签库和EL表达式来实现逻辑控制和数据展示。5.1 使用JSTL与EL表达式净化页面首先确保你的项目引入了JSTL的JAR包见前面Maven依赖。在JSP页面顶部通过taglib指令引入核心标签库。% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % html head title商品列表/title /head body h1商品列表/h1 %-- 使用JSTL的c:if进行条件判断 --% c:if test${not empty errorMsg} div stylecolor: red;${errorMsg}/div /c:if %-- 使用JSTL的c:forEach遍历商品列表 --% table border1 tr thID/th th名称/th th价格/th th操作/th /tr c:forEach items${productList} varproduct tr td${product.id}/td td${product.name}/td td %-- 使用fmt:formatNumber格式化价格 --% fmt:formatNumber value${product.price} typecurrency currencySymbol¥/ /td td a hrefaddToCart?id${product.id}加入购物车/a /td /tr /c:forEach /table %-- 分页控件 --% div c:if test${currentPage 1} a hrefproductList?page${currentPage-1}上一页/a /c:if 第${currentPage}页/共${totalPage}页 c:if test${currentPage totalPage} a hrefproductList?page${currentPage1}下一页/a /c:if /div /body /html${productList}就是EL表达式它从PageContext,Request,Session,Application四个作用域中依次查找名为productList的属性。这比% request.getAttribute(“productList”) %简洁太多了。5.2 解决JSP开发中的常见痛点热词中提到了几个JSP相关的具体问题这里给出解决方案“idea设置jsp页面语法高亮”在IDEA中JSP文件默认应该有高亮。如果没有可以检查File - Settings - Editor - File Types确保*.jsp文件关联到了JSP或JSPX类型。也可以安装像“JSP and JSF”这类插件来增强支持。“jsp incremental annotation processing is disabled”这是一个警告信息通常出现在使用Lombok等注解处理器的项目中。对于纯JSP/Servlet项目可以忽略。如果想关闭可以在IDEA的Settings - Build, Execution, Deployment - Compiler - Annotation Processors中勾选“Enable annotation processing”。“jsp 導入html”你想在JSP中引入另一个HTML片段可以使用% include file”header.html” %静态包含编译时合并或者jsp:include page”header.html” /动态包含运行时包含。注意路径问题。“jsp个人信息展示页面”这就是一个典型的从Session中取数据展示的页面。在Servlet里将用户对象放入Sessionsession.setAttribute(“currentUser”, user)在JSP页面中直接用${currentUser.username}等EL表达式展示即可。记得在页面开头检查用户是否登录c:if test”${empty currentUser}”未登录则跳转到登录页。“jsp file [/hotline.jsp] not found”这是典型的404错误。检查a) 文件是否真的存在于webapp目录或其子目录下b) 访问的URL路径是否正确是否包含了项目上下文路径Context Pathc) 如果通过Servlet转发检查request.getRequestDispatcher的路径它是以项目根目录为起点的。6. 项目部署、调试与性能调优初探开发完成后我们需要将项目部署到Tomcat上运行并了解一些基本的调试和优化思路。6.1 项目打包与部署IDEA提供了非常方便的部署方式。你可以配置一个本地的Tomcat Server点击运行配置旁边的下拉菜单选择“Edit Configurations”。点击“”选择“Tomcat Server - Local”。在“Deployment”标签页点击“”选择“Artifact”添加你的项目生成的WAR包。应用并运行IDEA会自动启动Tomcat并部署项目。你也可以手动打包在项目根目录执行mvn clean packageMaven项目会在target目录下生成一个项目名.war文件。将这个WAR文件复制到Tomcat的webapps目录下启动Tomcat它会自动解压并部署。6.2 常见错误调试与内存管理空指针异常 (NullPointerException)这是Java中最常见的异常。在Servlet和JSP中多是因为从request、session中获取的参数或属性为null或者Service/DAO层的对象没有正确初始化。务必在每个可能为null的地方进行判断。数据库连接错误检查DatabaseUtil中的连接URL、用户名、密码是否正确。检查MySQL服务是否启动。检查网络是否通畅。查看Tomcat日志catalina.out或localhost.log中的详细错误信息。“java: outofmemoryerror: insufficient memory”这是内存溢出错误。对于Web项目可能是加载了过大的文件、内存泄漏如未关闭的Connection、Statement、ResultSet、或JVM堆内存设置过小。可以在Tomcat的启动脚本如catalina.sh或catalina.bat中调整JVM参数例如增加堆内存-Xms512m -Xmx1024m。务必确保在代码中所有打开的数据库资源Connection, Statement, ResultSet都在finally块中或使用try-with-resources语法关闭。“java: you aren‘t using a compiler supported by lombok”如果你使用了Lombok简化实体类如自动生成getter/setter需要在IDEA中安装Lombok插件并在Settings - Build, Execution, Deployment - Compiler - Annotation Processors中启用注解处理。6.3 基础性能优化建议虽然这是一个学习项目但了解一些优化方向对成长很有帮助前端优化合并和压缩CSS/JS文件使用图片懒加载减少HTTP请求数。Servlet优化对于Servlet可以考虑将其设置为单例默认就是但要注意线程安全避免在service方法内创建大量局部对象。数据库优化索引为经常用于查询条件WHERE、排序ORDER BY和连接JOIN的字段创建索引如product表的category_idorder表的user_id。SQL优化避免使用SELECT *只查询需要的字段。复杂查询使用EXPLAIN分析执行计划。连接池调优根据系统负载调整HikariCP的maximumPoolSize、connectionTimeout等参数。JSP优化对于不常变化的数据可以使用缓存。或者考虑将纯展示性的页面静态化。这个基于ServletJSPMySQL的购物车项目虽然技术栈不再时髦但它像一本活的教科书把Web开发最核心的请求-响应循环、数据流转、状态管理、事务控制都清晰地展现了出来。我建议你在实现基本功能后可以尝试自己添加一些新功能比如商品搜索、用户评价、后台管理界面或者尝试引入一个简单的框架如封装一个自己的迷你MVC框架这个过程会让你对后续学习Spring等框架有更深的理解。编程的路上把基础打牢后面才能走得更稳更快。本文还有配套的精品资源点击获取
返回列表