简介这是一套基于SpringBoot的Java全栈体育用品商城实战项目面向Java初学者与Web开发入门者提供从用户端到后台管理的完整电商系统实现方案。项目采用JSPHTMLjQuery构建前端页面SpringBoot整合MyBatis与MySQL实现后端逻辑支持管理员与普通用户双角色操作并集成协同过滤推荐算法与百度地图API下单功能具备良好扩展性可快速适配其他垂直品类商城。资源包共698个文件含58个JSP页面核心业务视图、46个Java类Service/Controller/Entity层、51个JS脚本交互逻辑、25个PNG/GIF图片界面素材及1个SQL建表脚本含初始化数据整体压缩包仅4.9MB结构清晰、模块解耦度高。已有156人学习下载读者可直接导入IDEA或Eclipse运行调试掌握MVC分层开发、前后端交互、数据库设计及常见第三方API集成等关键技能。1. 这不是又一个“学生作业式商城”而是一套可落地的 Java Web 开发闭环实践路径你搜“Java体育用品商城”大概率会看到一堆带截图、没源码、连登录都卡在 JSP 表单提交的 demo 项目。但真实企业级 Java Web 应用里SpringBoot 不是摆设JSP 不是历史包袱MySQL 不是只建三张表的玩具——它得能处理商品分类树形展开、库存并发扣减、订单状态机流转、用户浏览行为埋点还得让前端工程师能改 HTML/CSS 不报错、运维能通过 Maven profile 切换测试/生产数据库、DBA 能从 SQL 日志里快速定位慢查询。本项目标题里的javaSpringBootjsphtmlmavenmysql不是技术堆砌清单而是当前中小型企业 Java 后端团队仍在高频使用的稳定型技术栈组合SpringBoot 提供快速启动与自动装配JSP 承担轻量级服务端渲染尤其适合内部管理后台或对 SEO 无强需求的 B2B 场景HTML 是页面骨架Maven 管理依赖与构建生命周期MySQL 存储核心业务数据。本文不讲“如何新建 SpringBoot 工程”而是聚焦于如何让这六种技术在体育用品商城这个具体业务场景中真正协同工作——从 JSP 页面如何安全接收 SpringBoot Controller 返回的 JSON 数据到 Maven 的pom.xml中 MyBatis 与 JSP 标签库的版本兼容性陷阱从 MySQL 的utf8mb4字符集对运动鞋型号“NIKE Air Max 270 ✨”的支持到web.xml中 JSP 编译参数对中文注释乱码的修复。适合正在维护老系统、参与传统行业数字化升级、或准备 Java 面试题中“JSP 与 SpringBoot 混合开发”考点的开发者。2. SpringBoot 与 JSP 共存的底层逻辑为什么不能直接用RestController返回 HTML2.1 JSP 在 SpringBoot 中的定位不是“淘汰品”而是“可控渲染层”SpringBoot 官方文档明确指出内嵌 Tomcat 默认不支持 JSP。这不是 Bug而是设计取舍——SpringBoot 推崇前后端分离JSP 属于传统服务端模板引擎。但在体育用品商城这类内部运营系统中JSP 仍有不可替代价值运营人员需实时修改商品详情页的促销文案如“夏季清仓篮球袜满 99 减 30”若强制走 Vue/React 前端框架每次修改都要重新构建部署而 JSP 文件放在src/main/webapp/WEB-INF/jsp/下Tomcat 热加载后即可生效配合web.xml中jsp-config设置可实现“改完保存F5 刷新即见效果”。关键在于理解 SpringBoot 的 DispatcherServlet 如何接管 JSP 请求它不直接解析.jsp文件而是将请求转发给容器内置的 JSP 引擎如 Jasper。因此必须显式配置InternalResourceViewResolver并确保prefix指向WEB-INF/jsp/安全起见JSP 文件绝不能放在webapp根目录下防止 URL 直接访问。2.2 实现 SpringBoot Controller 向 JSP 传递数据的最小可行配置2.2.1pom.xml中必须引入的依赖组合!-- SpringBoot Web 启动器 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- JSP 支持核心Tomcat JSP API -- dependency groupIdorg.apache.tomcat.embed/groupId artifactIdtomcat-embed-jasper/artifactId scopeprovided/scope /dependency !-- JSTL 标签库用于 JSP 中循环展示商品列表 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId /dependency !-- Servlet API编译 JSP 所需 -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId scopeprovided/scope /dependency提示tomcat-embed-jasper的scopeprovided是关键。它告诉 Maven该依赖由运行时容器如外部 Tomcat提供打包时不打入jar否则内嵌 Tomcat 会因类冲突启动失败。若部署到独立 Tomcat此依赖可移除。2.2.2application.properties中的视图解析器配置# 关闭默认的 Thymeleaf 模板引擎避免冲突 spring.thymeleaf.enabledfalse # 配置 JSP 视图解析器 spring.mvc.view.prefix/WEB-INF/jsp/ spring.mvc.view.suffix.jsp # 启用 JSP 编译调试开发期必需 server.jsp-servlet.init-parameters.developmenttrue2.2.3 Controller 返回 Model 数据的典型写法Controller RequestMapping(/product) public class ProductController { Autowired private ProductService productService; // 返回商品列表页数据 视图名 GetMapping(/list) public String listProducts(Model model) { // 查询体育用品分类球类、健身器材、户外装备等 ListCategory categories productService.getCategories(); // 查询热门商品按销量排序前 10 ListProduct hotProducts productService.getHotProducts(10); // 将数据放入 ModelJSP 通过 ${categories} 访问 model.addAttribute(categories, categories); model.addAttribute(hotProducts, hotProducts); return product/list; // 对应 /WEB-INF/jsp/product/list.jsp } }逻辑说明return product/list中的字符串是逻辑视图名InternalResourceViewResolver会自动拼接为/WEB-INF/jsp/product/list.jsp。Model是 Spring 封装的 MapaddAttribute()方法本质是modelMap.put(key, value)JSP 中通过 EL 表达式${key}获取。注意不要用ResponseBody注解此方法否则 Spring 会将其序列化为 JSON 并返回给浏览器而非跳转到 JSP 页面。2.3 JSP 页面中安全使用 JavaBean 与集合的语法规范2.3.1list.jsp中展示商品列表的标准写法% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html langzh-cn head meta charsetUTF-8 title体育用品商城 - 商品列表/title /head body h1全部商品/h1 !-- 使用 JSTL 的 forEach 遍历 hotProducts -- c:forEach items${hotProducts} varproduct varStatusstatus div classproduct-item h3${product.name}/h3 p价格¥${product.price}/p p品牌c:out value${product.brand}//p !-- c:out 可防止 XSS自动转义特殊字符 -- a href/product/detail?id${product.id}查看详情/a /div !-- 每 3 个商品加一个分隔线 -- c:if test${status.count % 3 0} hr/ /c:if /c:forEach /body /html参数说明% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %声明 JSTL 核心标签库c:前缀用于forEach、if等控制逻辑。c:out value${product.brand}/比直接${product.brand}更安全自动过滤script等危险 HTML 标签防止用户输入恶意内容污染页面。varStatusstatus提供循环状态对象status.count返回当前迭代序号从 1 开始用于实现“每 3 行分隔”。3. Maven 构建与 MySQL 集成从pom.xml依赖管理到application.yml数据源配置3.1pom.xml中 MySQL 驱动与持久层框架的版本协同策略体育用品商城涉及商品、订单、用户三张核心表需支持事务与连接池。Maven 依赖选择必须考虑SpringBoot 版本兼容性。以 SpringBoot 2.7.x当前企业主流 LTS 版本为例组件推荐版本选择理由mysql:mysql-connector-java8.0.33支持 MySQL 8.0 的caching_sha2_password认证插件避免连接拒绝mybatis-spring-boot-starter2.2.0与 SpringBoot 2.7.x 完全兼容自动配置 DataSourcedruid-spring-boot-starter1.2.18替代 HikariCP提供更丰富的监控指标如 SQL 执行时间、慢 SQL 报警!-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- MyBatis 整合 -- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.0/version /dependency !-- Druid 连接池 -- dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.18/version /dependency注意mysql-connector-java的scoperuntime表示仅在运行时需要编译期无需。若使用 MySQL 5.7驱动版本应降为5.1.49否则连接时抛出Communications link failure。3.2application.yml中 MySQL 数据源的生产级配置项spring: datasource: url: jdbc:mysql://localhost:3306/sports_store?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrueuseSSLfalse username: root password: your_secure_password driver-class-name: com.mysql.cj.jdbc.Driver # Druid 连接池参数 druid: initial-size: 5 min-idle: 5 max-active: 20 # 连接泄漏检测体育用品商城高并发下单场景必备 remove-abandoned-on-borrow: true remove-abandoned-timeout: 60 # SQL 监控开关 stat-view-servlet: enabled: true url-pattern: /druid/* web-stat-filter: enabled: true exclusions: *.js,*.css,/druid/* # MyBatis 配置 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true # 数据库字段 user_name → Java 属性 userName log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印 SQL关键参数解释characterEncodingutf8mb4确保存储 emoji如运动图标 ⚽️和生僻汉字如“骉”、“犇”不乱码这是体育用品品牌名如“彪马”、“李宁”的刚需。remove-abandoned-on-borrow: true当连接被借出超过 60 秒未归还Druid 自动回收防止库存扣减事务未提交导致连接耗尽。log-impl: ...StdOutImpl开发期开启可直观看到 MyBatis 生成的 SQL例如SELECT * FROM product WHERE category_id ?便于排查“为什么篮球分类下没显示足球”这类问题。3.3 创建体育用品商城核心表结构的 MySQL DDL 脚本-- 商品表含运动品类特有字段 CREATE TABLE product ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, name varchar(100) NOT NULL COMMENT 商品名称如耐克男子跑步鞋, category_id bigint NOT NULL COMMENT 分类ID关联category表, price decimal(10,2) NOT NULL COMMENT 售价, stock int NOT NULL DEFAULT 0 COMMENT 库存数量, brand varchar(50) DEFAULT NULL COMMENT 品牌如Nike, sport_type enum(RUNNING,BASKETBALL,FOOTBALL,TENNIS,GYM) NOT NULL COMMENT 运动类型枚举, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品信息表; -- 分类表支持多级如一级球类→二级篮球→三级篮球鞋 CREATE TABLE category ( id bigint NOT NULL AUTO_INCREMENT, name varchar(50) NOT NULL, parent_id bigint DEFAULT 0 COMMENT 父分类ID0表示一级分类, level tinyint NOT NULL DEFAULT 1 COMMENT 分类层级, PRIMARY KEY (id), KEY idx_parent (parent_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;实战技巧执行 DDL 前先在 MySQL 中运行SET NAMES utf8mb4;确保客户端连接使用正确字符集。若出现Incorrect string value错误说明表或列未设置CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci。4. HTML 与 JSP 协同如何让静态页面具备动态数据能力4.1!doctype htmlhtml langzh-cn结构下嵌入 JSP 动态内容的规范流程体育用品商城首页需展示轮播图、热销榜、新品预告三个区块。纯 HTML 无法动态加载数据必须与 JSP 结合。标准做法是HTML 作为骨架JSP 标签注入动态内容。4.1.1index.jsp中复用 HTML 结构并注入数据% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html langzh-cn head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title体育用品商城 - 首页/title link relstylesheet href/static/css/bootstrap.min.css /head body !-- 1. 轮播图从 Controller 传入的 bannerList -- div idcarouselExampleIndicators classcarousel slide>Component public class PriceUtils { /** * 将 BigDecimal 价格转为带¥符号的字符串 * param price 价格数值 * return 格式化后的字符串如 ¥199 */ public String formatPrice(BigDecimal price) { if (price null) return ¥0; return ¥ price.setScale(0, RoundingMode.HALF_UP).toBigInteger(); } }4.2.2 在 JSP 中通过spring:eval标签调用工具方法% taglib prefixspring urihttp://www.springframework.org/tags % !-- 在 JSP 头部声明 spring 标签库 -- c:forEach items${hotProducts} varp div classcard-body h5 classcard-title${p.name}/h5 !-- 调用 PriceUtils.formatPrice -- p classcard-text spring:eval expressionpriceUtils.formatPrice(p.price) / /p /div /c:forEach参数说明priceUtils是 Spring 的 Bean 名称默认为类名首字母小写p.price是 JSP 中的变量。spring:eval在服务端执行 Java 方法结果插入 HTML 流。禁止在 JSP 中写new BigDecimal()或数据库查询逻辑所有业务计算应在 Service 层完成。5. 排查 JSP 修改不生效与 MySQL 连接超时的典型故障链5.1 “JSP 改了不生效”的三层排查法从缓存到编译再到部署当修改list.jsp后刷新页面仍是旧内容按以下顺序检查层级检查点命令/操作预期结果浏览器层是否禁用缓存Chrome 开发者工具 → Network → 勾选 Disable cache刷新后list.jsp请求响应头含Cache-Control: no-cacheTomcat 层JSP 是否重新编译查看target/tomcat/work/Catalina/localhost/ROOT/org/apache/jsp/WEB_002dINF/jsp/product/list_jsp.java文件修改时间该文件时间应与list.jsp最后保存时间一致Maven 层是否启用热部署pom.xml中spring-boot-devtools依赖是否存在存在则mvn spring-boot:run启动时修改 JSP 会触发自动重编译关键命令若list_jsp.java未更新手动删除target/tomcat/work/目录重启应用。devtools依赖如下dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-devtools/artifactId optionaltrue/optional /dependency5.2 MySQL 连接超时的根因分析与wait_timeout参数调整体育用品商城在凌晨低峰期可能触发 MySQLwait_timeout默认 28800 秒 8 小时导致次日首次请求报CommunicationsException: Connection reset。5.2.1 验证当前 MySQL 的wait_timeout值-- 登录 MySQL 后执行 SHOW VARIABLES LIKE wait_timeout; -- 查看当前连接的空闲时长 SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE COMMAND Sleep AND TIME 3600;5.2.2 在application.yml中配置连接池保活策略spring: datasource: druid: # 每 30 分钟执行一次心跳检测 time-between-connect-error-millis: 1800000 # 连接空闲 5 分钟后校验有效性 min-evictable-idle-time-millis: 300000 # 校验 SQLMySQL 8.0 推荐 useServerPrepStmtsfalse 时用 SELECT 1 validation-query: SELECT 1 test-while-idle: true test-on-borrow: false test-on-return: false参数逻辑min-evictable-idle-time-millis300000表示连接空闲 5 分钟后Druid 会执行validation-querySELECT 1检测其是否有效。若 MySQL 的wait_timeout设为 36001 小时则此参数必须小于 3600否则连接在被校验前已被 MySQL 主动断开。5.3 用curl快速验证 SpringBoot JSP MySQL 端到端连通性# 1. 检查应用是否启动成功HTTP 200 curl -I http://localhost:8080/ # 2. 检查 JSP 页面能否渲染返回 HTML 内容 curl -s http://localhost:8080/product/list | head -20 # 3. 检查数据库查询是否正常返回 JSON证明 MyBatis 工作 curl -s http://localhost:8080/api/products/hot | jq .[0].name # 4. 检查 MySQL 连接池状态Druid 监控页 curl -s http://localhost:8080/druid/index.html | grep -i active技巧说明curl -s静默模式避免进度条干扰jq .[0].name解析 JSON 提取第一个商品名称验证数据链路完整。若第 3 步失败说明 MyBatis 或 MySQL 配置有误若第 2 步返回空白检查InternalResourceViewResolver的prefix路径是否正确。本文还有配套的精品资源点击获取
