JSP+Servlet+MySQL花店系统:Java Web入门实战全指南

发布时间:2026/10/1 4:01:55
JSP+Servlet+MySQL花店系统:Java Web入门实战全指南 简介本资源是一套完整的基于JSP技术的毕业设计项目实战材料面向计算机专业本科生及Java Web初学者解决课程设计、毕设选题与系统开发实践中的全流程需求。压缩包共125个文件涵盖35个JSP页面实现前后端交互、21个Java类含ManageServlet、IndexServlet等核心控制器及ProductDao、UserDao等数据访问组件、20个编译后class文件、7个JPG与6个PNG界面截图、3个MP4演示录像含系统操作全流程、1个SQL数据库脚本及答辩PPT、项目报告等文档整体容量达438.35MB。已有236人学习下载内容结构完整、模块划分清晰覆盖用户管理、商品分类、购物车、订单处理、公告发布等典型电商功能配套源码可直接部署运行PPT与报告可用于答辩准备录像直观展示系统逻辑与交互效果是Java Web入门到综合应用的优质参考范例。1. 为什么一个“基于JSP的网上花店销售系统”至今仍是Java Web初学者绕不开的实战锚点不是因为它多前沿——Servlet 3.0、Spring Boot早成标配而是它像一把刻度清晰的标尺用最朴素的技术栈JSP Servlet JDBC MySQL把电商核心链路——用户注册登录、商品浏览分类、购物车增删改、订单生成支付、后台管理 CRUD——全部压进一个可触摸、可调试、可打断点的单体结构里。你不需要懂微服务拆分也不必纠结OAuth2.0鉴权流程但必须亲手写% %嵌套逻辑、手调web.xml映射、手动拼接SQL防注入、在Tomcat日志里逐行追NullPointerException。这个项目不是毕业设计的“凑数选题”它是Java Web工程师的第一块肌肉记忆板当IDEA里右键新建一个JSP页面你下意识会先写% page contentTypetext/html;charsetUTF-8 languagejava %而不是去查文档——这种条件反射只能靠真实跑通一个带登录校验、带数据库事务、带页面跳转参数传递的完整闭环来锻造。适合刚学完Servlet生命周期、能写简单DAO但没串过业务流的人也适合想快速验证自己是否真懂“请求-响应-转发-重定向”底层差异的熟手。别被.zip后缀迷惑——它不是成品软件包而是一份可解压、可编译、可Debug、可改需求的活体教学沙盒。2. 从零启动用IDEA搭建可运行的JSP环境并导入项目2.1 环境准备JDK、Tomcat、IDEA三件套的版本锁死策略这个项目对环境极其敏感。实测发现JDK 17 Tomcat 10.1.x 会直接报javax.servlet.*类找不到——因为Tomcat 10起全面切换到Jakarta EE 9命名空间jakarta.servlet.*而本项目所有JSP和Servlet仍使用旧版javax.*包。血泪经验必须降级到JDK 8u202 Tomcat 9.0.85组合。JDK 8是最后一个支持javax.*且长期稳定更新的版本Tomcat 9.0.85是最后一个默认启用org.apache.jasper.compiler.TldLocationsCache且兼容老式TLD扫描的9.x小版本。安装时注意Tomcat解压目录路径不能含中文、空格、特殊符号如D:\My Projects\Tomcat会触发JSP编译器路径解析失败IDEA中配置Tomcat时在“Deployment”页签下Application context必须留空或设为/否则所有request.getContextPath()返回值异常导致CSS/JS路径404。# 验证Tomcat基础运行非项目 $ cd /path/to/tomcat/bin $ ./startup.sh # Linux/macOS # 或双击 startup.batWindows # 访问 http://localhost:8080 —— 应看到Tomcat欢迎页提示若启动后浏览器空白或报404立即检查catalina.out日志末尾是否有SEVERE: Failed to initialize connector [Connector[HTTP/1.1-8080]]——这通常意味着端口被占用修改conf/server.xml中Connector port8080为8081即可。2.2 IDEA导入项目WAR包解压后的标准目录结构识别项目压缩包解压后典型结构如下flower-shop/ ├── src/ # Java源码Servlet、DAO、Bean │ ├── main/ │ │ ├── java/ │ │ │ └── com/flower/ # 包名含UserServlet.java等 │ │ └── webapp/ # Web资源根目录关键 │ │ ├── WEB-INF/ │ │ │ ├── web.xml # 核心配置文件必须存在 │ │ │ └── lib/ # JAR依赖mysql-connector-java-5.1.47.jar在此 │ │ ├── index.jsp │ │ ├── login.jsp │ │ └── admin/ │ └── test/ # 单元测试本项目通常为空 ├── database/ # SQL脚本flower_shop.sql ├── doc/ # 项目报告PDF、答辩PPT └── video/ # 演示录像MP4在IDEA中操作File → Open → 选择 flower-shop/ 目录不是zip文件弹窗提示“Import project from external model”时勾选“Web Application”并确保“Web root”自动识别为src/main/webapp若未识别手动点击文件夹图标指向该路径在“Project SDK”下拉框中强制选择已安装的JDK 1.8不要用IDEA默认推荐的JDK 17点击“Finish”后IDEA会自动生成.idea配置但需手动补两处- 右键项目 →Add Framework Support...→ 勾选Java EE Web Module→Web Resource Directory设为src/main/webapp-File → Project Structure → Artifacts → → Web Application: Archive → Output directory设为out/artifacts/flower_shop_war_exploded2.3 数据库初始化MySQL 5.7兼容性与字符集硬约束项目SQL脚本database/flower_shop.sql明确要求MySQL 5.7非8.0。原因在于表定义中CREATE TABLE user (...) ENGINEInnoDB DEFAULT CHARSETutf8;—— MySQL 8.0默认utf8mb4且utf8是别名实际指向utf8mb3但本项目JSP页面meta charsetutf-8与JDBC连接URL未指定useUnicodetruecharacterEncodingutf8会导致中文插入乱码user表中password字段类型为varchar(32)暗示使用MD5加密32位十六进制字符串而MySQL 8.0默认密码插件caching_sha2_password不兼容老式JDBC驱动执行步骤启动MySQL 5.7服务确认端口3306未被占用创建数据库CREATE DATABASE flower_shop CHARACTER SET utf8 COLLATE utf8_general_ci;执行SQL脚本mysql -u root -p flower_shop /path/to/flower_shop.sql验证数据SELECT username, password FROM user WHERE usernameadmin;应返回admin和对应MD5密文注意若执行SQL时报错ERROR 1067 (42000): Invalid default value for create_time需临时关闭严格模式SET GLOBAL sql_mode(SELECT REPLACE(sql_mode,STRICT_TRANS_TABLES,));再重试。此问题源于MySQL 5.7默认开启严格模式而脚本中create_time datetime NOT NULL DEFAULT 0000-00-00 00:00:00不被允许。3. 核心业务链路跑通从登录到下单的6个关键断点调试3.1 登录功能login.jsp→LoginServlet→UserDAO的请求流转验证这是整个系统的入口闸门也是最容易卡住的环节。典型断点位置login.jsp中表单form actionLoginServlet methodpost—— 确认action路径与web.xml中servlet-mapping一致LoginServlet.java第25行String username request.getParameter(username);—— 在此处打断点检查request.getParameterMap()是否包含username和password键值UserDAO.java中public User findUserByUsernameAndPassword(String username, String password)方法 —— 断点进入PreparedStatement ps conn.prepareStatement(sql);前打印sql变量确认为SELECT * FROM user WHERE username? AND password?关键参数说明web.xml中servlet-mapping的url-pattern必须与JSP表单action完全匹配包括大小写例如/LoginServlet不能写成/loginServletJDBC连接URL必须显式声明字符集jdbc:mysql://localhost:3306/flower_shop?useUnicodetruecharacterEncodingutf8serverTimezoneGMT%2B8UserDAO中密码比对使用user.getPassword().equals(md5Password)而非避免字符串池引用错误3.2 购物车添加Session作用域与List集合的线程安全陷阱购物车数据存储在HttpSession中典型代码// CartServlet.java HttpSession session request.getSession(); ListCartItem cart (ListCartItem) session.getAttribute(cart); if (cart null) { cart new ArrayList(); session.setAttribute(cart, cart); } // ... 添加商品逻辑避坑点session.getAttribute(cart)返回null时必须new ArrayList()并setAttribute否则后续cart.add()会抛NullPointerExceptionCartItem类必须实现Serializable接口因Session可能序列化到磁盘否则Tomcat重启后购物车丢失多用户并发操作同一Session时ArrayList非线程安全——但本项目无高并发场景故可接受若需加固改用Collections.synchronizedList(new ArrayList())3.3 订单生成数据库事务的显式控制与回滚边界OrderServlet.java中订单创建涉及三张表操作order_info主订单、order_item订单项、user扣减余额。必须用JDBC事务保证原子性Connection conn null; try { conn JDBCUtil.getConnection(); conn.setAutoCommit(false); // 关键关闭自动提交 // 1. 插入order_info String sql1 INSERT INTO order_info (...) VALUES (...); PreparedStatement ps1 conn.prepareStatement(sql1, Statement.RETURN_GENERATED_KEYS); ps1.executeUpdate(); ResultSet rs ps1.getGeneratedKeys(); int orderId rs.next() ? rs.getInt(1) : 0; // 2. 插入order_item循环 String sql2 INSERT INTO order_item (...) VALUES (...); PreparedStatement ps2 conn.prepareStatement(sql2); for (CartItem item : cart) { ps2.setInt(1, orderId); ps2.setString(2, item.getFlowerName()); ps2.executeUpdate(); } // 3. 更新user余额伪代码 String sql3 UPDATE user SET balance balance - ? WHERE id ?; PreparedStatement ps3 conn.prepareStatement(sql3); ps3.setDouble(1, totalAmount); ps3.setInt(2, userId); ps3.executeUpdate(); conn.commit(); // 全部成功才提交 } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } request.setAttribute(msg, 订单创建失败 e.getMessage()); request.getRequestDispatcher(error.jsp).forward(request, response); }提示conn.setAutoCommit(false)必须在获取Connection后立即执行且conn.commit()和conn.rollback()必须包裹在try-catch中——否则事务不生效出现“订单生成但商品未扣减”的脏数据。4. 避坑指南新手必踩的5个JSP项目落地雷区4.1 现象JSP页面中文显示为“???”URL中中文参数乱码原因JSP页面未声明% page contentTypetext/html;charsetUTF-8 %导致浏览器按ISO-8859-1解析Tomcatconf/server.xml中Connector未配置URIEncodingUTF-8GET请求参数编码失败JDBC URL缺少characterEncodingutf8数据库读写字符集不一致解决所有JSP顶部添加% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8%修改server.xmlConnector port8080 protocolHTTP/1.1 URIEncodingUTF-8 ... /JDBC URL追加?useUnicodetruecharacterEncodingutf8serverTimezoneGMT%2B84.2 现象web.xml配置的Servlet映射无效访问/LoginServlet返回404原因web.xml根节点web-app未声明正确schema如缺少version3.0或xmlns错误web.xml放在src/main/webapp/WEB-INF/下但IDEA未识别为部署描述符右键web.xml→Mark as → Deployment DescriptorServlet类未放在src/main/java/下或包名与web.xml中servlet-class不匹配解决确认web.xml开头为?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd version3.1右键web.xml→Mark as → Deployment Descriptor检查LoginServlet.java包声明package com.flower.servlet;与web.xml中servlet-classcom.flower.servlet.LoginServlet/servlet-class完全一致4.3 现象MySQL插入中文报错Incorrect string value: \xE6\x9F\x90\xE6\x9F\x90原因数据库、表、字段三级字符集未统一为utf8mb4utf8在MySQL中仅支持3字节UTF-8无法存emoji和部分生僻字JDBC驱动版本过低如5.1.47不支持utf8mb4或连接URL未指定useUnicodetruecharacterEncodingutf8mb4解决修改数据库字符集ALTER DATABASE flower_shop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;修改表字符集ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;升级JDBC驱动至8.0.28连接URL改为jdbc:mysql://localhost:3306/flower_shop?useUnicodetruecharacterEncodingutf8mb4serverTimezoneGMT%2B84.4 现象Tomcat启动后JSP编译失败日志报org.apache.jasper.JasperException: Unable to compile class for JSP原因web.xml中jsp-config未配置taglib但JSP中使用了自定义标签本项目通常无src/main/webapp/WEB-INF/lib/下JAR包冲突如同时存在servlet-api.jar和tomcat-servlet-api.jarIDEA未将src/main/webapp设为Web资源根目录导致JSP编译器找不到web.xml解决删除WEB-INF/lib/下所有servlet-api*.jarTomcat自带重复引入导致类加载冲突右键项目 →Open Module Settings→Project Settings → Modules → Sources→ 将src/main/webapp标记为Resources清理Tomcat工作目录删除tomcat/work/Catalina/localhost/_/下所有文件4.5 现象登录成功后跳转到index.jsp但页面显示空白或报java.lang.ClassNotFoundException: com.flower.bean.User原因User.java类未放在src/main/java/com/flower/bean/下或包声明错误web.xml中welcome-file-list未配置index.jsp导致Tomcat默认找index.htmlindex.jsp中jsp:useBean iduser classcom.flower.bean.User scopesession/的class路径与实际类路径不一致解决确认User.java首行package com.flower.bean;web.xml中添加welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-listindex.jsp中jsp:useBean的class属性必须与User.java的package声明完全匹配区分大小写5. 进阶验证用Postman模拟全流程接口调用与压力基线测试5.1 构建可复用的Postman Collection覆盖6大核心接口本项目虽为传统JSP但所有业务均通过HTTP请求触发完全可用Postman验证。关键接口清单接口路径HTTP方法参数示例预期状态码验证要点/LoginServletPOSTusernameadminpassword21232f297a57a5a743894a0e4a801fc3302重定向检查Set-Cookie: JSESSIONID是否返回且后续请求携带/CartServlet?actionaddid1quantity2GETURL参数302查看Session中cart属性是否新增CartItem对象/OrderServletPOSTaddress北京phone13800138000200检查order_info表是否新增记录order_item是否关联正确/AdminServlet?actionlistUsersGET无200返回HTML表格含trtdadmin/tdtd管理员/td/tr/LogoutServletGET无302检查JSESSIONIDCookie是否失效再次访问需重新登录Postman操作新建Collection → 命名为FlowerShop-API每个接口新建RequestMethod设为对应HTTP方法在Authorization标签页选择Cookies→Manage Cookies→ 手动添加JSESSIONID首次登录后从响应头复制对/LoginServlet设置Tests脚本自动提取Session ID// Post-request script const cookies pm.cookies.toObject(); pm.environment.set(JSESSIONID, cookies[JSESSIONID]);后续请求在Headers中添加Cookie: JSESSIONID{{JSESSIONID}}5.2 用Apache Bench做轻量级压力测试定位性能瓶颈JSP项目性能瓶颈通常在数据库连接和JSP编译。用ab命令验证# 测试登录接口预热后 $ ab -n 100 -c 10 http://localhost:8080/LoginServlet # 关键指标关注 # Time per request: 125.345 [ms] (mean) —— 单请求平均耗时 # Percentage of the requests served within a certain time (ms) # 50% 112 # 90% 189 # 99% 245 # Failed requests: 0 —— 必须为0否则存在连接池耗尽或SQL错误若Failed requests 0按以下顺序排查检查WEB-INF/lib/mysql-connector-java-5.1.47.jar是否为唯一MySQL驱动重复驱动导致类加载冲突查看tomcat/logs/catalina.out末尾是否有java.sql.SQLException: Cannot create PoolableConnectionFactory—— 表明数据库连接池满需在context.xml中增加maxActive50运行jstack tomcat-pid搜索BLOCKED线程确认是否因UserDAO中Connection未关闭导致连接泄漏5.3 数据库连接池改造从直连JDBC到DBCP2的平滑升级原项目使用JDBCUtil.getConnection()直连高并发下易耗尽连接。升级为DBCP2只需3步pom.xml添加依赖若用Mavendependency groupIdorg.apache.commons/groupId artifactIdcommons-dbcp2/artifactId version2.9.0/version /dependency创建DBCP2Util.java替代JDBCUtilpublic class DBCP2Util { private static BasicDataSource dataSource; static { dataSource new BasicDataSource(); dataSource.setUrl(jdbc:mysql://localhost:3306/flower_shop?useUnicodetruecharacterEncodingutf8); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setInitialSize(5); // 初始连接数 dataSource.setMaxTotal(20); // 最大连接数 dataSource.setMaxIdle(10); // 最大空闲连接 dataSource.setMinIdle(5); // 最小空闲连接 dataSource.setTestOnBorrow(true); // 借出前检测连接有效性 dataSource.setValidationQuery(SELECT 1); // 连接检测SQL } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }将所有JDBCUtil.getConnection()替换为DBCP2Util.getConnection()并确保Connection.close()调用仍有效DBCP2中close是归还连接非销毁我的习惯是每次改完DAO层立刻用Postman发10次相同请求观察ab测试中Failed requests是否从非0变为0。如果还是失败我直接打开catalina.out搜索SQLException90%的问题都在那里等着——不是代码写错了而是数据库连不上、表不存在、字段名拼错了。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询