ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SSM在线手机品牌商城实战:从数据库设计到框架整合部署全解析

SSM在线手机品牌商城实战:从数据库设计到框架整合部署全解析 做JavaWeb方向的课程设计和毕业设计SSM在线手机品牌商城是出现频率很高的一个选题。这个项目用SpringSpringMVCMyBatis这套SSM组合打底前端走JSPjQueryAjax数据库落到MySQL上技术栈非常典型。我最初带学生做这个项目时也踩了不少坑从环境配置到框架整合、从前端调试到上线部署几乎每一层都有可以聊的细节。这篇文章不打算给你抄一套现成代码而是把整个项目的设计思路、数据库结构、SSM整合步骤、前端交互方式以及常见问题排查全部分享出来。1. 项目整体设计与技术选型思路1.1 为什么是SSM而不是Spring Boot很多人会问现在都Spring Boot了为什么课程设计和毕设还在用SSM。这里有个现实原因很多高校的JavaWeb课程大纲仍然是SpringSpringMVCMyBatis的组合教学体系决定了题目要求就是SSM。另一个原因是面试和考试中SSM的XML配置能更好地考察对框架原理的理解比如IoC容器怎么管理Bean、SpringMVC的DispatcherServlet怎么路由请求、MyBatis的SqlSessionFactory怎么创建。从工程角度看SSM并非过时它只是把Spring Boot自动配置的部分“手动化”了。手写配置虽然繁琐但能让人真正理解配置背后的逻辑。你只要把SSM跑通一遍再去看Spring Boot的自动配置很多概念都是相通的学习成本反而更低。我用的是Spring 5.1.x SpringMVC 5.1.x MyBatis 3.5.x的组合JDK 1.8Tomcat 8.5MySQL 8.0。这套版本组合在IDEA下运行稳定网上能查到的资料也最多。1.2 商城系统的功能边界划分一个在线手机品牌商城核心用户有这么几类游客、注册用户、管理员。围绕这三类角色我把系统拆成前台用户系统和后台管理系统两条线。前台用户系统包含用户注册登录、手机品牌分类展示、商品列表分页与排序、商品详情、购物车管理、订单结算这六个核心模块。后台管理系统包含商品管理、品牌管理、库存管理、订单状态管理、用户管理五个核心模块。这里有一个设计上的取舍购物车是存Session还是存数据库我的做法是未登录状态用Session存储登录后同步到数据库这样既保证用户体验又为换设备保留数据。很多初级项目只放Session用户一清缓存购物车就没了这个细节在答辩时经常被问到。1.3 分层架构与目录规划项目的包结构按照经典三层架构划分我在自己项目里用的是以下结构com.shop ├── controller // 控制层接收前端请求 ├── service // 业务层处理业务逻辑 │ └── impl ├── mapper // MyBatis的Mapper接口 ├── pojo // 实体类 │ ├── entity // 与数据库表对应的实体 │ ├── vo // 视图对象组合页面所需数据 │ └── dto // 前端传参对象 ├── interceptor // 拦截器处理登录权限 ├── utils // 工具类 └── config // 配置类JSP页面放在webapp目录下按功能模块分子目录user、phone、cart、order、admin公共部分如header.jsp、footer.jsp单独放一块用include标签复用。前端静态资源css、js、images也独立分类这样部署后Nginx处理静态资源、Tomcat专门跑JSP时不会乱。2. 数据库设计与核心表结构2.1 数据表关系梳理商城系统数据库我设计了五张核心表用户表、品牌表、手机商品表、订单表、订单明细表。这五张表的关系很清晰一个品牌对应多个商品一个用户对应多个订单一个订单对应多个明细每个明细关联一个商品。建表之前先想清楚业务约束这里分享几个设计经验。商品表除了基本字段外一定要有库存字段且设置默认值为0防止新增商品时因未填库存导致空值异常。状态字段如is_deleted这类逻辑删除标记默认值设为0可以避免物理删数据带来的关联问题。价格字段用DECIMAL类型不要用FLOAT或DOUBLE浮点型在货币计算中会出现精度丢失。2.2 手机商品表与用户表设计示例以下是商品表和用户表的建表语句我直接贴出来供参考CREATE TABLE phone ( id int(11) NOT NULL AUTO_INCREMENT, brand_id int(11) NOT NULL COMMENT 品牌ID, name varchar(100) NOT NULL COMMENT 手机名称, model varchar(100) DEFAULT NULL COMMENT 型号, price decimal(10,2) NOT NULL COMMENT 价格, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存默认0, sales int(11) NOT NULL DEFAULT 0 COMMENT 销量, image_url varchar(255) DEFAULT NULL COMMENT 商品图片, description text COMMENT 商品描述, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 1上架 0下架, is_deleted tinyint(1) NOT NULL DEFAULT 0 COMMENT 逻辑删除标记, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_brand_id (brand_id) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4;CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 用户名, password varchar(64) NOT NULL COMMENT 密码MD5加密存储, phone varchar(20) DEFAULT NULL COMMENT 联系电话, email varchar(100) DEFAULT NULL COMMENT 邮箱, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 账户状态, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4;订单表和订单明细表也是类似的思路。订单表记录总金额、下单人、订单状态订单明细表记录每个商品的单价、数量和小计金额。特别注意订单表要冗余一个下单时的商品快照字段比如商品名称和单价。原因很简单商品价格后续会调整下单后订单里的价格不能跟着变否则对账时会很麻烦。2.3 数据库连接池与排序查询策略数据库连接池我推荐Druid相比默认的DBCPDruid自带监控页面可以实时看到SQL执行时间、活跃连接数等指标。在调试慢查询时非常有用我经常通过Druid监控页面发现某个商品列表页在数据库层面慢了200毫秒然后针对性优化SQL。配置连接池时几个关键参数要注意。initialSize初始连接数设为5maxActive最大连接数设为20maxWait获取连接超时设为60000毫秒。还可以配置testWhileIdle和validationQuery为SELECT 1避免因为MySQL的wait_timeout导致连接失效。商品列表排序功能是前台的高频操作。MySQL的排序语法很简单但实际开发时要注意多字段排序的场景比如按销量降序、同销量按价格升序SELECT * FROM phone WHERE status 1 AND is_deleted 0 ORDER BY sales DESC, price ASC LIMIT #{offset}, #{pageSize}给这个查询加上联合索引后发现性能提升明显每次分页查询都在几十毫秒内完成。没有索引时数据量大就会走全表扫描这是性能优化的一个典型场景。3. 环境搭建与SSM框架整合实操3.1 本地环境的安装与版本匹配如果你是第一次在IDEA里建JSP项目环境配置环节最容易出问题。我先说一下我的环境搭配JDK 1.8、IDEA 2022.3、Maven 3.8、Tomcat 8.5、MySQL 8.0。这里强调版本匹配我试过用Tomcat 10搭配Spring 5会直接报错因为Tomcat 10的Servlet规范升级了包名从javax.servlet变成了jakarta.servlet。MySQL 8.0安装后有两个坑容易踩。一个是驱动类名变了8.0版本驱动类名是com.mysql.cj.jdbc.Driver不是以前5.x版本的com.mysql.jdbc.Driver。另一个是连接字符串必须加上serverTimezone参数否则会有时区报错。完整的连接串这样配jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/shop?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password你的密码如果你用Navicat或其他图形工具连不上MySQL先检查MySQL服务有没有启动再检查用户权限。问题通常出在root账号默认只允许localhost访问远程连接需要单独授权。3.2 Maven依赖与各个配置文件的配合SSM整合的核心在pom.xml和各处配置文件。我先把pom.xml的关键依赖列出来dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.1.8.RELEASE/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.4/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.4/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.19/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.1.21/version /dependency dependency groupIdjstl/groupId artifactIdjstl/artifactId version1.2/version /dependency dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.9.9/version /dependency依赖里Jackson很关键它负责把Controller返回的对象转成JSONAjax接口全靠它。SSM的Spring配置我拆成三个文件applicationContext.xml管Spring核心扫码、数据源、事务、spring-mvc.xml管SpringMVC视图解析器、注解驱动、mybatis-config.xml管MyBatis驼峰映射、分页插件。分文件好处是职责清晰出了问题定位也快。spring-mvc.xml里两个配置要特别注意。一个是注解驱动一个是视图解析器context:component-scan base-packagecom.shop.controller / mvc:annotation-driven / bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/ / property namesuffix value.jsp / /bean mvc:resources mapping/static/** location/static/ /3.3 IDEA部署JSP项目的关键配置IDEA里运行这类传统JSP项目我总结了一套固定流程。从Maven侧面板点clean和package打war包然后在Project Structure里确认Artifacts设置正确。运行配置新建Tomcat Server LocalDeployment标签页添加ArtifactsApplication context设为/shop。这样访问路径就是http://localhost:8080/shop/。有几个经典错误我要提前说出来。第一是Artifacts没有把依赖的jar包带进WEB-INF/lib启动直接报ClassNotFoundException。第二是启动后页面404多半是Application context路径配错了。第三是JSP编译报错检查IDEA的Project SDK是不是1.8Maven的Java版本也要一致。以前打包传统JSP项目是打成war包放到Tomcat的webapps目录下自动解压部署。现在开发时直接以war exploded方式部署到Tomcat好处是支持热更新改JSP不用重启。生产环境就老老实实用war包或者用Docker里跑Tomcat挂载war文件。4. 核心功能模块实现与前端交互细节4.1 用户登录注册与Ajax校验用户模块是最基础也最能体现细节的模块。注册页面我做了用户名唯一性校验用jQuery的blur事件触发Ajax请求把输入的用户名提交给后端校验接口返回结果后动态提示“该用户名可用”或“用户名已被占用”。这样做不用提交表单就能提前校验体验比整页刷新友好太多。Ajax请求写法是这样的$.post(/shop/user/checkUsername, { username: $(#username).val() }, function(data) { if (data.code 200) { $(#tip).text(用户名可用).css(color, green); } else { $(#tip).text(data.msg).css(color, red); } });登录模块还涉及一个安全细节密码不能明文存储。我用MD5加盐的方式处理注册时把用户名和随机盐拼起来再MD5数据库里存密文和盐值。登录时用同样的规则重新计算比对。虽然MD5不是最强方案但在课程设计和传统SSM项目里已经是合格水准比明文存储强太多了。JSP页面里用EL表达式和JSTL标签渲染后端数据比如用户中心个人信息展示页面直接通过${sessionScope.user.username}输出用户名。这套组合是传统J2EE项目的标配理解以后对后续学Spring Boot搭配thymeleaf有很大帮助。4.2 商品列表分页与排序查询商品列表页是前台访问量最大的页面。我实现了按品牌筛选、按价格区间筛选、按销量/价格排序以及分页展示。后端Controller接收pageNum、pageSize、brandId、keyword等参数调用Service层拼接动态SQL。MyBatis的动态SQL用 标签非常方便下面是商品列表查询的Mapper写法select idselectPhoneList resultTypecom.shop.pojo.entity.Phone SELECT * FROM phone where status 1 AND is_deleted 0 if testbrandId ! null AND brand_id #{brandId} /if if testkeyword ! null and keyword ! AND name LIKE CONCAT(%, #{keyword}, %) /if /where choose when testsortType priceAsc ORDER BY price ASC /when when testsortType salesDesc ORDER BY sales DESC, price ASC /when otherwise ORDER BY create_time DESC /otherwise /choose LIMIT #{offset}, #{pageSize} /select分页条我用jQuery做了动态展示。页面上点击页码时先收集筛选条件再通过Ajax请求数据拿到新数据后重新渲染商品卡片。这里有一个性能细节每次Ajax重新渲染整个列表区域数据量大时DOM操作会比较重。实测二十条数据这个范围完全没压力可以放心用。4.3 购物车与订单结算逻辑购物车模块我用Session加数据库两条腿走路。未登录状态先把商品加到Session中用户登录后点击结算时把Session里的购物车同步到数据库。购物车表字段不含商品价格明细只存用户ID、商品ID和数量真正的价格在结算时从商品表实时读取。这样做的好处是用户刷新页面或换浏览器购物车数据不丢。订单结算的流程是确认收货地址、读取购物车数据、计算总价、生成订单、生成订单明细、扣减库存、清空购物车。这里有一个很关键的点扣减库存一定要放在数据库层面做用UPDATE语句的原子操作不是先查库存再判断再更新。如果并发下单先查后更新会出现超卖。扣减库存的SQL是这样的UPDATE phone SET stock stock - #{num}, sales sales #{num} WHERE id #{id} AND stock #{num}执行后判断受影响行数如果为0说明库存不足整个事务回滚。这个细节我在答辩时讲给评委听基本都会追问并认可。订单生成时我用当前时间加随机数生成订单号在商品数量大的情况下能保证唯一性。订单列表中状态字段用数字表示0待付款、1已付款待发货、2已发货、3已完成、4已取消。前端通过switch语句把数字转换成对应中文和操作按钮。4.4 前端通用交互技巧与整合整个商城用到的交互模式主要集中在几个方面Ajax异步提交、表单序列化、列表高亮、表格内容溢出处理。购物车结算页我用jQuery的serialize()方法把表单直接序列化成查询字符串提交省去手动拼接参数的麻烦。商品分页列表中的当前页高亮用CSS类加jQuery的addClass/removeClass切换。商品列表表格里商品描述字段经常很长直接显示会撑破布局。这时我用了title属性加CSS单行省略的方式单元格内容超过一定宽度后显示省略号鼠标悬浮时通过title属性展示完整数据。纯jQuery不依赖插件就能实现体验也不错。如果项目用了Bootstrap Table或DataTables可以直接开启自带的tooltip配置比如jQuery DataTables结合tooltip插件效果是一样的。手机上浏览商城时页面宽度要适配所以我引入Bootstrap框架做响应式布局。商品卡片用栅格系统处理一行在小屏显示1列、中屏2列、大屏4列。导航栏折叠效果也是Bootstrap自带的省了不少工作量。5. 常见问题排查与避坑实录5.1 数据库连接与乱码问题排查整合阶段最常遇到的问题分两类数据库连接问题和JSP乱码问题。数据库连接问题集中在无法连接MySQL和连接超时上。无法连接时先检查MySQL服务Windows下在服务管理器里看mysql服务是否启动。MySQL 8连接时遇到ERROR 2002 HY000提示常见原因是socket路径问题或服务没启动Linux下用systemctl status mysqld查看服务状态。我遇到的乱码问题主要有两层。第一层是数据库层面建表时就用utf8mb4字符集连接串加useUnicodetrue和characterEncodingutf8。第二层是Web层面web.xml中必须配置CharacterEncodingFilter过滤器强制请求和响应都用UTF-8。JSP页面顶部加page指令设置pageEncoding。这三处都配置正确后中文基本不会乱码。我在web.xml里的过滤器配置如下filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping5.2 SSM整合常见报错与解决方案我整理了一份踩坑记录表按现象、原因、解决方案三列排版排查问题时对照着查很方便。报错现象常见原因解决方案启动Tomcat报ClassNotFoundExceptionMaven依赖未打包进lib目录检查Artifacts确认lib已添加页面404Application context配置错误或Controller扫描失败检查context配置确认Controller注解生效Controller返回JSON但Ajax拿不到数据缺少Jackson依赖或返回类型不对确认pom中有jackson-databind用ResponseBodySQL执行报Unknown column实体类字段和表字段不一致开启MyBatis驼峰命名转换mapUnderscoreToCamelCaseJSP页面访问报500Servlet版本和Tomcat版本不匹配检查web.xml头部的schema版本数据库连接密码报错MySQL8默认认证插件问题连接串加allowPublicKeyRetrievaltrueAjax返回数据中文乱码响应编码设置不对在RequestMapping的produces中指定UTF-85.3 开发调试建议与优化心得这么多模块开发下来我的最大心得是从后往前调试。先把数据库表和Mapper调通用测试类跑一遍查询再调Service和Controller用Postman模拟请求最后才联调前端页面。这样出错时能快速定位到后端还是前端效率提升非常明显。日志配置也很重要。项目里我用的是log4j2把SQL日志级别调成DEBUG可以在控制台直接看到MyBatis生成的SQL和参数。排查SQL问题时不用去盲猜。我建议把Druid监控页开启访问/druid/index.html就能看到每个SQL的执行时间性能瓶颈一眼定位。谈谈SEO和搜索引擎优化的角度。设置商品列表页URL语义清晰可以作为个人项目展示的加分项但不必过度关注。作为一个学习项目我更看重的是功能完整性和代码规范包括统一返回结果类、全局异常处理器、日志记录。这些工程化习惯会伴随整个职业生涯。5.4 扩展方向与动手实践建议项目跑通以后我建议做几件锦上添花的事。给密码加密升级为BCrypt把MD5换成BCrypt算法安全性会更好。商品列表加入全文搜索用MySQL的全文索引实现。后台管理加一个数据统计Dashboard按周统计订单量、销售金额、Top10商品排行这部分用存储过程预聚合也可以但商品量不大时直接用SQL计算就够用。我的经验是每扩展一个功能都要回归测试一遍核心链路用户注册、商品浏览、下单支付这套主流程千万不能坏。主流程稳定后才去碰新功能否则最后整出来的项目能演示但不能跑通主链路答辩时很被动。我个人实际带项目的体会是做这类SSM商城最容易忽略的不是技术难点而是业务逻辑的边界情况比如库存为负、重复下单、用户未登录直接访问购物车页面。这些边界情况在开发时多花一小时处理问题能在答辩和演示时少踩很多坑。做技术学习项目最重要的不是炫技而是把一个系统做得完整可靠。希望这篇经验总结能帮你在课程设计和毕设路上少走一些弯路。
返回列表