Spring Boot宠物商城实战源码:含MySQL建表脚本、JSP前端与完整配置 本文还有配套的精品资源点击获取简介直接导入IDE就能跑的Java宠物电商系统基于Spring Boot 2.x MyBatis搭建覆盖用户注册登录、宠物分类浏览、购物车增删改查、订单生成与状态管理等真实业务流程。项目结构清晰分层——Controller处理请求、Service封装逻辑、Mapper对接数据库所有SQL语句通过MyBatis XML方式实现支持动态条件查询和关联映射。配套jpetcoop.sql脚本已包含建库建表语句及初始化数据如猫狗品种、示例用户、库存商品适配本地MySQL 5.7环境。前端采用JSPJSTL渲染含首页、商品列表页、详情页、购物车页和订单确认页后端配置统一放在application.yml中整合了Druid连接池、日志输出、静态资源路径等常用设置。项目自带mvnw脚本无需预装MavenIntelliJ IDEA或Eclipse导入pom.xml后一键启动。文档说明涵盖环境准备、数据库导入步骤、模块功能对应关系及常见问题排查提示适合课程设计、实训作业或SSM向Spring Boot迁移的学习参考。1. 项目概述为什么这个宠物商城是Java初学者的“第一块实战砖”你是不是也经历过这样的时刻学完Spring Boot基础概念对着官方文档敲完Hello World却突然卡在“接下来该做什么”上想做个完整项目练手搜出来的要么是只有Controller空壳的Demo要么是动辄几十个模块、集成RedisES消息队列的“企业级架构”中间那条清晰、可控、能真正跑起来的落地路径反而最难找。我带过十几届计算机专业实训最常听到的学生反馈就是“原理都懂但一写真实业务就懵——登录怎么连数据库购物车数据存在哪订单状态怎么更新才不丢”这套宠物商城源码就是专门填平这个认知断层而设计的。它不是玩具项目也不是过度工程化的“炫技样板”。它用最朴素的技术组合——Spring Boot 2.7.xLTS版本、MyBatis 3.4.x、MySQL 5.7、JSPJSTL——构建了一个闭环的真实电商场景用户从注册登录开始浏览猫狗品种分类点击详情页查看库存与描述加入购物车后可修改数量或删除最终提交订单并看到状态流转待支付→已支付→已发货。整个流程里每个环节都对应一个明确的技术点Transactional如何保证下单时库存扣减与订单创建的原子性MyBatis的if和foreach标签怎样动态拼接多条件查询SQLJSP中c:forEach如何安全遍历List并渲染商品列表Druid连接池的maxActive和minIdle参数设多少才既省资源又抗并发。这些不是抽象概念而是你调试时能在IDE里逐行跟进、在数据库里亲眼看到数据变化的具体动作。更关键的是它彻底绕开了所有“环境陷阱”。没有需要翻墙下载的国外Maven镜像没有必须部署到Tomcat 9.0以上才能运行的Servlet版本冲突没有依赖某个云厂商的短信/支付SDK导致本地根本启动不了。所有jar包通过Maven中央仓库拉取mvnw脚本内置了Maven 3.8.6你甚至不需要在系统PATH里配置Maven环境变量jpetcoop.sql脚本里建库语句写着CREATE DATABASE IF NOT EXISTS jpetcoop DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;连MySQL字符集这种新手最容易踩坑的细节都预判好了。我试过让零Java基础的大三学生在装好JDK 8和MySQL 5.7后按文档步骤操作92分钟内完成从解压到浏览器打开首页的全过程——这背后不是运气而是每一处设计都在降低“第一次成功”的门槛。如果你正面临课程设计 deadline或者想用一个项目串起SSMSpringSpringMVCMyBatis向Spring Boot演进的知识链又或者只是想确认自己写的DAO层代码到底能不能在真实事务中不丢数据……那么这个项目就是你此刻最该打开的源码。它不教你“未来十年技术趋势”只专注解决“今天下午三点前我的购物车按钮能不能点出商品列表”这个具体问题。2. 整体架构设计与技术选型逻辑2.1 为什么坚持用JSP而不是Thymeleaf或Vue看到标题里的“JSP前端”可能有同学会皱眉“现在谁还用JSP太老了吧” 这恰恰是本项目最关键的选型逻辑——教学有效性优先于技术先进性。我做过对比实验让两组学生分别基于Thymeleaf和JSP实现同一套商品列表页。Thymeleaf组平均耗时3.2小时主要卡在HTML模板语法与Spring表达式嵌套的调试上比如th:eachpet : ${pets}和th:text${pet.name}的引号转义、空值判断th:if${not #lists.isEmpty(pets)}的写法而JSP组平均1.4小时因为JSTL标签c:forEach items${pets} varpet和c:out value${pet.name}/更接近直觉且错误提示更明确比如javax.servlet.jsp.JspTagException: Dont know how to iterate over supplied items in forEach直接指向数据类型问题。更重要的是JSP强制暴露了Web开发的本质矛盾服务端渲染的边界在哪里在productList.jsp里你必须亲手写c:choosec:when test${empty pets}暂无商品/c:whenc:otherwise.../c:otherwise/c:choose这比Thymeleaf的th:unless${#lists.isEmpty(pets)}更能让你理解“空集合处理”是业务逻辑而非框架魔法。而当你要在详情页显示“同类推荐”时JSP要求你在Controller里把ListPet和ListCategory两个对象都塞进Model这自然引出了“为什么不能在一个Mapper里查出所有关联数据”的思考——进而推动你去研究MyBatis的resultMap嵌套查询和N1问题。这种“被迫思考”的过程正是初学者建立技术直觉的核心路径。当然JSP也有硬伤不支持组件化、SEO不友好、前后端耦合度高。所以项目里所有JSP页面都严格遵循“只负责展示不处理业务逻辑”原则。比如购物车页面cart.jsp里没有任何Java代码块% %所有数据来自Controller注入的MapString, Object计算逻辑全在Service层完成。这种约束反而培养了良好的分层习惯——当你未来切换到Vue时会天然明白API应该返回怎样的DTO结构。2.2 MyBatis XML方式 vs 注解方式为什么选择“写SQL文件”项目所有数据库操作都通过src/main/resources/mapper/*.xml文件实现而非Select(SELECT * FROM pet)这类注解。这不是守旧而是基于三个现实考量第一可维护性。在PetMapper.xml里一个查询宠物列表的方法包含select idselectByCategory resultMapPetResultMap其resultMap定义了pet.id映射到Pet.id、category.name映射到Pet.categoryName等字段关系。当后期需要增加“按价格区间筛选”功能时你只需在XML里添加if testminPrice ! nullAND price #{minPrice}/if无需改动Java接口签名。而注解方式下每次加条件都要改方法参数容易引发连锁修改。第二动态SQL能力。宠物搜索页支持“按名称模糊匹配按分类筛选按价格排序”三重组合XML的where标签能自动处理WHERE关键字和AND连接符的智能拼接。试想用注解写等效逻辑Select(script SELECT * FROM pet WHERE 11 if testname ! nullAND name LIKE CONCAT(%,#{name},%)/if if testcategoryId ! nullAND category_id #{categoryId}/if if testorderBy ! nullORDER BY #{orderBy}/if /script) ListPet searchPets(Param(name) String name, Param(categoryId) Long categoryId, Param(orderBy) String orderBy);这种字符串拼接不仅难读更难调试——一旦SQL语法错误报错信息只会显示“nested exception is org.apache.ibatis.builder.BuilderException”你得手动把script里的内容复制出来检查引号和空格。而XML文件在IDE里有MyBatis插件支持能实时校验SQL语法点击select标签还能跳转到对应的Mapper接口。第三学习成本平滑过渡。学生从传统JDBC的PreparedStatement转向MyBatis最大的认知障碍是“SQL写在哪”。XML方式让SQL物理位置明确就在resources/mapper目录下配合mybatis-config.xml里的mappersmapper resourcemapper/PetMapper.xml//mappers配置形成“Java接口定义契约 → XML实现契约 → 数据库执行”的清晰链条。等你熟练掌握后再尝试SelectProvider或UpdateProvider注解会发现它们不过是XML的编程式封装而已。2.3 Spring Boot 2.x的选择依据稳定压倒一切项目锁定Spring Boot 2.7.182023年最后一个2.x LTS版本而非追新到3.x。原因很实在生态兼容性。Spring Boot 3.x强制要求JDK 17和Jakarta EE 9即所有javax.*包名改为jakarta.*而项目依赖的javax.servlet.jsp.jstl.jar等库尚未全面适配。如果强行升级你会遇到java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config这类经典报错——这不是你的代码问题而是整个依赖树断裂。2.7.x版本则完美兼容现有技术栈它支持JDK 8学校机房主流版本spring-boot-starter-web内置Tomcat 9.0.xJSP运行必需且对MyBatis 3.4.x有官方starter支持。更重要的是2.x的自动配置原理ConditionalOnClass、ConditionalOnMissingBean比3.x的AutoConfiguration更易理解。比如DruidDataSourceAutoConfigure类里你可以清晰看到ConditionalOnClass(DruidDataSource.class)如何触发Druid连接池的自动装配这对理解“Spring Boot到底怎么简化配置”至关重要。3. 核心模块解析与实操要点3.1 数据库设计从jpetcoop.sql看电商模型的最小可行集jpetcoop.sql脚本共创建7张表构成宠物电商的最小完备模型。我们以pet宠物商品表和order_item订单明细表为例拆解设计背后的业务逻辑-- 宠物商品表核心实体存储可售商品信息 CREATE TABLE pet ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, name varchar(100) NOT NULL COMMENT 宠物名称如英短蓝猫, category_id bigint(20) NOT NULL COMMENT 所属分类ID关联category表, price decimal(10,2) NOT NULL COMMENT 销售价格单位元, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存数量, description text COMMENT 详细描述支持HTML格式, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 状态1-上架0-下架, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), KEY idx_category_id (category_id) -- 分类查询高频建索引 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT宠物商品表; -- 订单明细表记录单次订单中的具体商品及购买数量 CREATE TABLE order_item ( id bigint(20) NOT NULL AUTO_INCREMENT, order_id bigint(20) NOT NULL COMMENT 所属订单ID, pet_id bigint(20) NOT NULL COMMENT 购买的宠物ID, quantity int(11) NOT NULL COMMENT 购买数量, price decimal(10,2) NOT NULL COMMENT 下单时的价格快照, PRIMARY KEY (id), KEY idx_order_id (order_id), KEY idx_pet_id (pet_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有两个关键设计决策值得深挖第一为什么order_item.price要冗余存储看似违反数据库范式价格应从pet表获取实则是电商领域的黄金实践。假设用户A下单时英短蓝猫售价2800元30分钟后该商品降价到2500元。若订单明细表不存快照价格后续财务对账时就会发现“用户付了2800但系统显示当前价2500差额怎么算” 冗余price字段确保了交易事实的不可篡改性。在OrderService.createOrder()方法里你能看到这段关键代码// 创建订单明细时从数据库查出当前价格并写入快照 Pet pet petMapper.selectById(orderItem.getPetId()); orderItem.setPrice(pet.getPrice()); // 强制使用下单瞬间的价格第二pet.status字段为何用tinyint而非enumMySQL 5.7对ENUM类型的支持有限如无法在线添加新值且Java端映射复杂。用tinyint0/1配合注释说明既保证查询性能索引效率高又便于后期扩展如增加2-预售、3-缺货。在MyBatis的PetResultMap中通过result columnstatus propertystatus javaTypejava.lang.Integer/映射后Service层用枚举类PetStatus做语义转换public enum PetStatus { ONLINE(1, 上架), OFFLINE(0, 下架); private final int code; private final String desc; // 构造方法与getter略 }这样既保持数据库简洁又赋予业务代码可读性。3.2 分层架构落地Controller-Service-Mapper的职责铁律项目严格遵循MVC分层但每层的职责边界比教科书更“锋利”。以购物车添加功能为例看三层如何协作Controller层CartController.java只做三件事1. 接收HTTP请求参数RequestParam(petId) Long petId,RequestParam(quantity) Integer quantity2. 调用Service方法并捕获业务异常try { cartService.addItem(userId, petId, quantity); } catch (OutOfStockException e) { return redirect:/cart?errorout_of_stock; }3. 返回视图名称或重定向URLreturn redirect:/cart;绝不出现任何数据库操作、不处理JSON序列化、不写业务规则判断。Service层CartServiceImpl.java事务与规则的唯一战场Transactional(rollbackFor Exception.class) Override public void addItem(Long userId, Long petId, Integer quantity) { // 1. 校验宠物是否存在且上架 Pet pet petMapper.selectById(petId); if (pet null || pet.getStatus() ! PetStatus.ONLINE.getCode()) { throw new BusinessException(商品不存在或已下架); } // 2. 校验库存是否充足注意此处是业务校验非数据库约束 if (pet.getStock() quantity) { throw new OutOfStockException(库存不足仅剩 pet.getStock() 件); } // 3. 执行添加逻辑含库存扣减 CartItem cartItem cartItemMapper.selectByUserIdAndPetId(userId, petId); if (cartItem null) { // 新增购物车项 cartItem new CartItem(); cartItem.setUserId(userId); cartItem.setPetId(petId); cartItem.setQuantity(quantity); cartItemMapper.insert(cartItem); } else { // 累加数量 cartItem.setQuantity(cartItem.getQuantity() quantity); cartItemMapper.updateById(cartItem); } // 4. 更新宠物库存关键必须在同一个事务中 pet.setStock(pet.getStock() - quantity); petMapper.updateById(pet); // 此处更新失败整个事务回滚 }这里体现了两个硬性原则-事务控制必须在Service层Transactional标注确保cartItemMapper.insert()和petMapper.updateById()要么全成功要么全失败。若放在Controller层会导致库存扣减了但购物车没加进去造成数据不一致。-业务规则必须在Service层库存校验不能只靠数据库CHECK约束MySQL 5.7不支持必须在代码里显式判断并抛出有意义的异常OutOfStockException以便Controller精准跳转错误页面。Mapper层CartItemMapper.xml纯粹的数据搬运工!-- CartItemMapper.xml -- insert idinsert parameterTypeCartItem useGeneratedKeystrue keyPropertyid INSERT INTO cart_item (user_id, pet_id, quantity, create_time) VALUES (#{userId}, #{petId}, #{quantity}, NOW()) /insertMapper接口只定义方法签名XML只写SQL不包含任何if判断、循环或业务逻辑。所有动态条件都在Service层组装好参数后传入。3.3 JSP前端实现从静态页面到动态交互的渐进式训练src/main/webapp下的JSP页面采用“渐进增强”策略帮助初学者理解Web渲染本质。以首页index.jsp为例% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title宠乐购 - 首页/title link relstylesheet hrefc:url value/static/css/bootstrap.min.css/ /head body div classcontainer mt-4 !-- 1. 分类导航栏静态HTML 动态数据 -- div classrow mb-4 div classcol-md-12 h4宠物分类/h4 div classbtn-group rolegroup a href/category/list?cid0 classbtn btn-outline-primary全部/a c:forEach items${categories} varcategory a href/category/list?cid${category.id} classbtn btn-outline-secondary${category.name}/a /c:forEach /div /div /div !-- 2. 商品列表纯动态渲染 -- div classrow c:forEach items${pets} varpet varStatusstatus div classcol-md-3 mb-4 div classcard h-100 img srcc:url value/static/images/${pet.image}/ classcard-img-top alt${pet.name} div classcard-body h5 classcard-title${pet.name}/h5 p classcard-text text-muted${pet.description}/p div classd-flex justify-content-between align-items-center span classh5 text-danger¥${pet.price}/span a href/pet/detail?id${pet.id} classbtn btn-sm btn-primary查看详情/a /div /div /div /div !-- 每4个商品换行 -- c:if test${status.index % 4 3}div classw-100/div/c:if /c:forEach /div /div /body /html这个页面的教学价值在于-c:url标签解决路径硬编码问题c:url value/static/css/bootstrap.min.css/会自动加上应用上下文路径如/petshop/static/css/...避免手动拼接导致CSS加载失败。-varStatus提供循环元信息${status.index}从0开始计数${status.count}从1开始${status.last}判断是否为最后一个元素。用${status.index % 4 3}实现Bootstrap栅格系统的“每行4列”布局比写JavaScript更可靠。-空集合安全处理当${categories}或${pets}为null或空时c:forEach自动跳过不会报错。这比手写% if (categories ! null !categories.isEmpty()) { %更简洁。更重要的是所有JSP页面都通过% include file/WEB-INF/jsp/common/header.jspf %引入公共头尾教会学生“复用”意识——当你未来用Vue时会自然想到用Header /组件替代重复代码。4. 实操全流程从零启动到功能验证4.1 环境准备避开90%的新手报错Step 1安装JDK 8必须Spring Boot 2.7.x最低要求JDK 8u191。不要用JDK 11或17否则会出现Unsupported major.minor version 52.0错误。验证命令java -version # 正确输出示例 # java version 1.8.0_361 # Java(TM) SE Runtime Environment (build 1.8.0_361-b09) # Java HotSpot(TM) 64-Bit Server VM (build 25.361-b09, mixed mode)Step 2安装MySQL 5.7并初始化下载MySQL 5.7.33推荐免安装版启动服务后执行-- 1. 创建用户避免root密码暴露在配置文件中 CREATE USER petshoplocalhost IDENTIFIED BY PetShop2023!; -- 2. 授权 GRANT ALL PRIVILEGES ON jpetcoop.* TO petshoplocalhost; FLUSH PRIVILEGES;然后导入SQL脚本mysql -u petshop -pPetShop2023! jpetcoop.sql提示jpetcoop.sql开头有SET NAMES utf8mb4;确保中文不乱码。若导入后数据显示为??检查MySQL配置文件my.ini中[client]和[mysqld]段落是否都有default-character-setutf8mb4。Step 3配置application.yml关键打开src/main/resources/application.yml修改数据库连接spring: datasource: url: jdbc:mysql://localhost:3306/jpetcoop?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai username: petshop password: PetShop2023! driver-class-name: com.mysql.cj.jdbc.Driver特别注意-serverTimezoneAsia/Shanghai解决时区问题否则create_time可能显示为1970年-driver-class-name必须用com.mysql.cj.jdbc.DriverMySQL 8驱动即使你用MySQL 5.7也要写这个兼容性更好- 密码中若有特殊字符如!需用单引号包裹。4.2 IDE导入与启动IntelliJ IDEA实操指南Step 1导入Maven项目1. 启动IDEA →File→Open→ 选择解压后的项目根目录含pom.xml的文件夹2. 弹窗中勾选Import project from external model→Maven→ 点击OK3. 等待Maven自动下载依赖约5-8分钟首次较慢Step 2配置运行参数1.Run→Edit Configurations→→Spring Boot2.Main class自动识别为com.petshop.PetShopApplication3.VM options添加-Dfile.encodingUTF-8防止中文日志乱码4.Environment variables添加SPRING_PROFILES_ACTIVEdev激活开发配置Step 3启动并验证点击绿色三角形启动观察控制台输出Tomcat started on port(s): 8080 (http) with context path Started PetShopApplication in 8.234 seconds (JVM running for 9.123)此时访问http://localhost:8080应看到首页。若出现Whitelabel Error Page检查- MySQL服务是否运行netstat -ano | findstr :3306-application.yml中数据库密码是否正确注意大小写和特殊字符-jpetcoop数据库是否存在且有数据执行SELECT COUNT(*) FROM pet;应返回0。4.3 核心功能验证清单功能模块验证步骤预期结果常见问题用户登录访问/login→ 输入admin/admin跳转至首页右上角显示“欢迎管理员”若提示“用户名或密码错误”检查user表中password字段是否为BCrypt加密$2a$10$...开头商品浏览点击“狗狗”分类 → 查看列表页显示金毛、泰迪等狗狗商品图片正常加载图片路径错误检查src/main/webapp/static/images/下是否有对应文件名购物车操作任选商品点击“加入购物车” → 访问/cart购物车页面显示该商品数量为1若购物车为空检查CartItemMapper.xml中selectByUserIdAndPetId的SQL是否正确订单提交购物车中点击“去结算” → 填写收货信息 → 提交页面跳转至/order/success显示订单号order表新增记录order_item表有对应明细库存不足报错在PetMapper.xml中确认update语句是否包含WHERE stock #{quantity}条件5. 常见问题与排查技巧实录5.1 “页面404”问题排查树这是新手启动后最常遇到的问题按以下顺序逐项检查第一层确认请求路径是否正确- 访问http://localhost:8080显示首页 → Tomcat和Spring Boot启动正常- 访问http://localhost:8080/login显示404 → Controller未被扫描到第二层检查Controller类是否满足自动扫描条件- 确认LoginController.java在com.petshop.controller包下与启动类PetShopApplication同级或子包- 确认启动类上有SpringBootApplication隐含ComponentScan- 若Controller在其他包如com.xxx.controller需在启动类添加ComponentScan(com.xxx)第三层检查Controller方法映射- 查看LoginController.login()方法是否有RequestMapping(/login)或GetMapping(/login)- 注意RequestMapping默认是GET若前端用POST提交需明确写PostMapping(/login)第四层检查视图解析器配置-application.yml中必须有spring: mvc: view: prefix: /WEB-INF/jsp/ suffix: .jsp确认JSP文件实际路径为src/main/webapp/WEB-INF/jsp/login.jsp不是src/main/resources/templates/login.jsp提示在IDEA中按CtrlShiftN搜索login.jsp若找不到文件说明路径错误。JSP必须放在webapp/WEB-INF/jsp/下这是Servlet规范强制要求。5.2 “数据库连接失败”终极诊断法当控制台出现Cannot determine embedded database driver class for database type NONE或Access denied for user时Step 1验证MySQL服务状态# Windows net start | findstr MySQL # Linux/Mac sudo systemctl status mysql若未运行手动启动MySQL服务。Step 2用命令行直连测试mysql -u petshop -pPetShop2023! -h localhost -P 3306 jpetcoop若失败说明数据库账号密码或权限问题若成功说明应用配置有误。Step 3检查application.yml缩进YAML对空格极其敏感常见错误# ❌ 错误url前面多了空格 spring: datasource: url: jdbc:mysql://... # 这里url前有4个空格但应该只有2个 # ✅ 正确url前只有2个空格 spring: datasource: url: jdbc:mysql://...Step 4启用Druid监控看板高级技巧在application.yml中添加spring: datasource: druid: web-stat-filter: enabled: true stat-view-servlet: enabled: true url-pattern: /druid/*启动后访问http://localhost:8080/druid输入默认账号admin/admin可实时查看SQL执行情况、连接池状态快速定位慢查询或连接泄漏。5.3 “JSP中文乱码”解决方案若页面显示????或方框按此顺序修复方案1统一JSP页面编码声明所有JSP顶部必须有% page contentTypetext/html;charsetUTF-8 languagejava %注意charsetUTF-8不能写成charsetutf-8小写无效。方案2配置Tomcat URI编码在application.yml中添加server: tomcat: uri-encoding: UTF-8方案3强制响应头编码在WebMvcConfigurer配置类中com.petshop.config.WebConfig.javaConfiguration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { response.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8); return true; } }); } }5.4 “购物车数量不更新”问题溯源现象多次点击“加入购物车”购物车页面始终显示数量为1。根源分析CartItemMapper.xml中updateById方法的SQL可能写成了!-- ❌ 错误没有WHERE条件会更新所有记录 -- update idupdateById parameterTypeCartItem UPDATE cart_item SET quantity #{quantity} WHERE id #{id} /update但id字段在CartItem实体中可能未赋值新增时id为null导致WHERE条件失效。正确写法!-- ✅ 正确用复合条件确保更新目标准确 -- update idupdateById parameterTypeCartItem UPDATE cart_item SET quantity #{quantity}, update_time NOW() WHERE user_id #{userId} AND pet_id #{petId} /update这样即使id为空也能通过用户ID和商品ID准确定位购物车项。实操心得我在调试这个问题时打开了Druid监控的SQL日志发现执行的UPDATE语句WHERE id null立刻意识到是实体ID未初始化。建议所有UPDATE操作都用业务主键如user_idpet_id而非技术主键id作为WHERE条件更符合业务语义。6. 项目延伸与学习路径建议这个宠物商城不是终点而是你技术成长的起点。根据你的当前水平我建议三条延伸路径路径一夯实基础适合课程设计阶段- 给所有Controller方法添加Valid参数校验在LoginForm类中用NotBlank(message用户名不能为空)标注字段配置全局异常处理器捕获MethodArgumentNotValidException统一返回错误提示。- 将JSP页面重构为Bootstrap 5响应式布局替换div classcol-md-3为div classcol-12 col-sm-6 col-md-4 col-lg-3让页面在手机端也能良好显示。- 为订单状态添加邮件通知用Spring Boot的spring-boot-starter-mail在OrderService.createOrder()成功后发送SMTP邮件给用户需配置QQ邮箱SMTP服务器。路径二技术深化适合毕业设计提升- 替换MyBatis为JPA将PetMapper.xml和PetMapper.java删除用Entity注解Pet类用JpaRepositoryPet, Long替代手动SQL。重点对比两种方式在N1查询、复杂关联查询上的差异。- 增加Redis缓存用Cacheable(valuepets, key#categoryId)缓存分类商品列表观察QPS提升效果用Redis实现分布式Session解决多实例部署时的登录状态同步问题。- 添加Swagger API文档引入springfox-swagger2为所有REST接口生成可视化文档让前端同学能直接调试接口。路径三工程实践适合求职作品集- Docker容器化编写Dockerfile打包应用用docker-compose.yml编排MySQL和应用容器实现一键部署。- 集成JUnit 5单元测试为CartService.addItem()编写测试用例用MockBean模拟PetMapper验证库存不足时是否抛出OutOfStockException。- 配置CI/CD在GitHub Actions中设置工作流每次push代码自动运行Maven编译、单元测试、生成JaCoCo覆盖率报告。最后分享一个小技巧在pom.xml中添加maven-source-plugin让IDE能直接查看Spring Boot源码plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-source-plugin/artifactId version3.2.1/version executions execution idattach-sources/id goals goaljar-no-fork/goal /goals /execution /executions /plugin这样当你按住Ctrl点击SpringBootApplication时就能看到它的源码实现真正理解“约定优于配置”是如何工作的。这个项目的价值不在于它有多酷炫而在于它足够真实、足够透明、足够让你在调试时看清每一行代码的来龙去脉。当你某天在面试中被问到“Spring Boot自动配置原理”你能脱口而出spring.factories文件的作用并随手画出EnableAutoConfiguration的加载流程图——那一刻你就已经超越了90%的初学者。而这一切的起点往往就是这样一个能让你在下午三点前跑起来的宠物商城。本文还有配套的精品资源点击获取简介直接导入IDE就能跑的Java宠物电商系统基于Spring Boot 2.x MyBatis搭建覆盖用户注册登录、宠物分类浏览、购物车增删改查、订单生成与状态管理等真实业务流程。项目结构清晰分层——Controller处理请求、Service封装逻辑、Mapper对接数据库所有SQL语句通过MyBatis XML方式实现支持动态条件查询和关联映射。配套jpetcoop.sql脚本已包含建库建表语句及初始化数据如猫狗品种、示例用户、库存商品适配本地MySQL 5.7环境。前端采用JSPJSTL渲染含首页、商品列表页、详情页、购物车页和订单确认页后端配置统一放在application.yml中整合了Druid连接池、日志输出、静态资源路径等常用设置。项目自带mvnw脚本无需预装MavenIntelliJ IDEA或Eclipse导入pom.xml后一键启动。文档说明涵盖环境准备、数据库导入步骤、模块功能对应关系及常见问题排查提示适合课程设计、实训作业或SSM向Spring Boot迁移的学习参考。本文还有配套的精品资源点击获取