
简介本资源是一套完整的基于SSM框架的化妆品销售网站毕业设计项目面向计算机专业本科生及Java初学者助力毕设开发与企业级Web系统实战能力提升。压缩包共3个文件1个SQL数据库脚本、1个含源码的ZIP包、1个项目说明TXT总大小24.08MB结构清晰、开箱即用——SQL脚本可一键初始化MySQL数据ZIP内含完整Eclipse工程及Tomcat部署配置TXT详述环境搭建与运行步骤。目前已有1192人学习下载热度持续走高。读者可直接获取经严格调试、功能完备的全栈实现前台涵盖用户注册登录、商品浏览/收藏/下单/评论等核心电商流程后台支持用户、商品、订单、公告等多维度管理技术栈覆盖SpringSpringMVCMyBatis主流组合代码规范、注释充分适合作为毕设参考、课程设计范例或SSM整合学习样板。1. 为什么一个基于SSM的化妆品销售网站至今仍是计算机专业毕设的“稳态选择”很多同学在大四上学期打开教务系统选题时会发现「基于SSM的化妆品销售网站」常年排在Java方向毕设列表前五——不是因为它多前沿而是它恰好卡在「技术边界清晰、业务逻辑可闭环、数据库关系易建模、部署验证无黑盒」这四个毕业设计刚性需求的交点上。它不涉及分布式事务的复杂协调不需要对接第三方支付风控网关也不依赖GPU算力或实时消息中间件但又能完整覆盖用户注册/登录、商品分类管理、购物车增删改查、订单生成与状态流转、后台SKU库存同步等典型电商核心链路。对指导老师而言它便于分模块验收Controller层是否RESTful、Service层事务是否生效、MyBatis动态SQL是否防注入对学生而言从IDEA新建Maven项目到Tomcat跑出首页全程可控、日志可追、报错可定位。尤其当答辩PPT需要展示「数据库ER图→Mapper XML映射→Controller接口文档→前端页面跳转逻辑」这条证据链时这个项目能自然撑起8分钟陈述——它不是玩具Demo而是用成熟框架把真实业务切片落地的最小可行系统。2. SSM三层架构如何精准适配化妆品销售场景的业务粒度2.1 为什么选SSM而非Spring Boot——毕设场景下的技术选型逻辑在毕设开发中SSMSpring Spring MVC MyBatis的显式分层比Spring Boot的自动装配更具教学穿透力。学生需手动配置applicationContext.xml声明Service Bean、springmvc-servlet.xml定义HandlerMapping、mybatis-config.xml绑定TypeAlias这种“显式声明”迫使开发者理解IoC容器初始化顺序、DispatcherServlet拦截路径、SqlSessionFactory构建流程。例如当学生遇到「Controller接收参数为空」问题时排查路径是检查RequestMapping路径是否匹配web.xml中servlet-mapping、确认RequestParam是否漏写value属性、验证mvc:annotation-driven/是否启用数据绑定——每一步都对应Spring MVC生命周期中的具体节点。而Spring Boot的SpringBootApplication会隐藏这些细节导致调试时无法定位到HandlerMethodArgumentResolver的执行时机。此外学校实验室服务器多为CentOS 6.x Tomcat 7SSM对JDK 1.7、Servlet 2.5的兼容性更稳妥避免因Spring Boot 2.x要求JDK 8引发环境冲突。提示若学校明确要求使用较新环境如JDK 11可将SSM升级为Spring 5.3.x MyBatis 3.4.x组合保留XML配置风格的同时获得Java 11语法支持无需切换Boot。2.2 化妆品领域模型的关键实体设计与MyBatis映射策略化妆品销售业务中「品类-品牌-功效-适用肤质」构成多维交叉分类体系需避免传统单表继承导致的查询冗余。我们采用「主表关联表」设计product表存储通用字段id, name, price, stockproduct_category表定义类目树id, name, parent_id通过product_category_rel关联产品与类目。特别注意「功效标签」需支持多选如「美白抗皱保湿」因此单独建product_effect表并用product_effect_rel维护多对多关系。MyBatis映射时对一对多查询采用collection嵌套结果映射!-- ProductMapper.xml -- resultMap idProductWithCategories typeProduct id propertyid columnp_id/ result propertyname columnp_name/ collection propertycategories ofTypeCategory id propertyid columnc_id/ result propertyname columnc_name/ /collection /resultMap select idselectProductWithCategories resultMapProductWithCategories SELECT p.id as p_id, p.name as p_name, c.id as c_id, c.name as c_name FROM product p LEFT JOIN product_category_rel rel ON p.id rel.product_id LEFT JOIN product_category c ON rel.category_id c.id WHERE p.id #{id} /select此写法比Select注解更易调试SQL且collection的ofType指定具体类型后MyBatis能自动完成List 实例化避免手动循环set。2.3 Spring事务管理在订单创建场景中的精确控制化妆品订单需保证「扣减库存」与「生成订单记录」的原子性但MyBatis默认不开启事务。必须在Spring配置中声明事务管理器并在Service方法上标注Transactional!-- applicationContext.xml -- bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean tx:annotation-driven transaction-managertransactionManager/// OrderServiceImpl.java Transactional(rollbackFor Exception.class) public Order createOrder(Order order, ListOrderItem items) { // 1. 扣减库存先查后更新防止超卖 for (OrderItem item : items) { int affected productMapper.decreaseStock(item.getProductId(), item.getQuantity()); if (affected 0) { throw new RuntimeException(库存不足商品ID item.getProductId()); } } // 2. 插入订单主表 orderMapper.insert(order); // 3. 插入订单明细 for (OrderItem item : items) { item.setOrderId(order.getId()); orderItemMapper.insert(item); } return order; }关键参数说明rollbackFor Exception.class确保所有异常触发回滚默认仅RuntimeException回滚decreaseStock方法需在Mapper中使用UPDATE product SET stock stock - #{quantity} WHERE id #{productId} AND stock #{quantity}利用数据库行锁避免并发超卖。3. 从源码到可运行系统的四步落地实操3.1 搭建SSM基础环境Maven依赖与目录结构标准化新建Maven项目后在pom.xml中声明核心依赖。注意版本兼容性Spring 4.3.29.RELEASE与MyBatis 3.4.6可稳定共存避免引入Spring 5.x导致web.xml中listener类名变更dependencies !-- Spring核心 -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version4.3.29.RELEASE/version /dependency !-- Spring MVC -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version4.3.29.RELEASE/version /dependency !-- MyBatis -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.4.6/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.47/version /dependency !-- JSTL用于JSP页面 -- dependency groupIdjstl/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies标准目录结构必须包含src/main/java/com/example/cosmetic/下分controller、service、dao、entity包src/main/resources存放applicationContext.xml、springmvc-servlet.xml、mybatis-config.xml、jdbc.propertiessrc/main/webapp/WEB-INF/放web.xml和jsp页面src/main/webapp/static/存放CSS/JS/图片避免JSP中路径混乱注意web.xml中servlet-class必须为org.springframework.web.servlet.DispatcherServlet且init-param指定contextConfigLocation为classpath:springmvc-servlet.xml否则Spring MVC无法加载。3.2 数据库脚本执行要点字符集、外键约束与测试数据填充提供的cosmetic_db.sql脚本需在MySQL 5.7环境下执行。关键检查点首行必须包含CREATE DATABASE IF NOT EXISTS cosmetic DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;所有表ENGINEInnoDB以支持事务外键约束需显式声明如order_item表中order_id引用order表主键-- 示例product表创建语句 CREATE TABLE product ( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL COMMENT 商品名称, price decimal(10,2) NOT NULL COMMENT 售价, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 填充测试数据避免空表导致页面报错 INSERT INTO product (name, price, stock) VALUES (兰蔻小黑瓶精华, 1080.00, 50), (雅诗敦水润面膜, 199.00, 200);执行后验证在MySQL命令行输入SHOW CREATE TABLE product\G确认DEFAULT CHARSETutf8mb4存在用SELECT character_set_database;检查库级字符集是否为utf8mb4否则中文插入会乱码。3.3 IDEA中配置Tomcat并解决常见启动失败在IDEA中配置Tomcat Server时需修改Deployment选项卡Application context设为/cosmetic与web.xml中display-name一致Artifacts选择cosmetic:war exploded启动失败高频原因及修复404错误检查web.xml中servlet-mapping的url-pattern是否为/且springmvc-servlet.xml中mvc:annotation-driven/已启用ClassNotFoundException确认WEB-INF/lib下存在spring-webmvc-4.3.29.RELEASE.jar若使用Maven则需在Project Structure → Artifacts中勾选Include in project build数据库连接失败验证jdbc.properties中jdbc.urljdbc:mysql://localhost:3306/cosmetic?useUnicodetruecharacterEncodingutf8mb4末尾参数缺失会导致中文乱码3.4 前端页面与后端Controller的请求映射验证首页index.jsp通过c:url value/product/list/生成URL对应Controller方法Controller RequestMapping(/product) public class ProductController { Autowired private ProductService productService; RequestMapping(value /list, method RequestMethod.GET) public String listProducts(Model model) { ListProduct products productService.findAll(); model.addAttribute(products, products); return product/list; // 解析为 /WEB-INF/jsp/product/list.jsp } }验证步骤启动Tomcat后访问http://localhost:8080/cosmetic/product/list查看浏览器开发者工具Network标签确认返回HTTP 200且响应体含商品HTML若返回空白页检查product/list.jsp中c:forEach items${products} varp是否正确遍历${p.name}能否输出4. 毕设答辩前必须验证的5个技术证据链4.1 数据库操作安全性验证SQL注入防护实测MyBatis的#{}占位符能有效防止SQL注入但需验证是否误用$符号。在ProductMapper.xml中搜索所有$确保仅用于动态表名/列名如ORDER BY ${sortBy}且sortBy参数经白名单校验// ProductService.java public ListProduct searchByKeyword(String keyword, String sortBy) { // 白名单校验 if (!Arrays.asList(price, sales, create_time).contains(sortBy)) { sortBy create_time; } return productMapper.search(keyword, sortBy); }实测方法在商品搜索框输入 OR 11观察后台SQL日志开启MyBatis log4j日志是否生成WHERE name LIKE %\ OR \1\\1%——若出现则#{keyword}生效若生成WHERE name LIKE % OR 11%说明误用了${keyword}。4.2 事务失效场景复现与修复日志故意制造事务失效在OrderServiceImpl.createOrder()方法内添加int i 1/0;抛出ArithmeticException启动应用并提交订单。预期结果数据库中无新订单记录库存未扣减。若发现订单已插入但库存未减少说明事务未生效需检查Transactional是否在public方法上private方法无效是否调用的是代理对象方法避免this.createOrder()导致绕过代理applicationContext.xml中tx:annotation-driven/是否配置且transaction-manager引用正确4.3 分页功能性能验证LIMIT OFFSET vs ROW_NUMBER()化妆品商品列表常需分页MyBatis PageHelper插件虽方便但毕设需体现底层原理。在ProductMapper.xml中手写分页SQL!-- 方式1MySQL LIMIT适合小数据量 -- select idselectByPage resultTypeProduct SELECT * FROM product ORDER BY create_time DESC LIMIT #{offset}, #{limit} /select !-- 方式2ROW_NUMBER()MySQL 8.0大数据量更优 -- select idselectByPageWithRowNum resultTypeProduct SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY create_time DESC) AS rn FROM product ) t WHERE t.rn BETWEEN #{offset}1 AND #{offset}#{limit} /select验证时用EXPLAIN分析执行计划LIMIT方式应显示typeALL全表扫描而ROW_NUMBER()方式若索引有效则typerange。答辩时可对比10万条测试数据下两种方式的查询耗时单位ms。4.4 用户权限控制的最小实现验证化妆品后台需区分普通用户与管理员web.xml中配置安全约束security-constraint web-resource-collection web-resource-nameAdmin Area/web-resource-name url-pattern/admin/*/url-pattern /web-resource-collection auth-constraint role-nameadmin/role-name /auth-constraint /security-constraint login-config auth-methodFORM/auth-method form-login-page/login.jsp/form-login-page form-error-page/error.jsp/form-error-page /login-config security-role role-nameadmin/role-name /security-role验证未登录时访问/admin/user/list应重定向至login.jsp登录后request.isUserInRole(admin)返回true。注意role-name必须与数据库user_role表中role_name字段值完全一致。4.5 日志输出规范性检查Log4j配置与关键节点埋点log4j.properties需包含控制台与文件双输出log4j.rootLoggerINFO, stdout, file log4j.appender.stdoutorg.apache.log4j.ConsoleAppender log4j.appender.stdout.layoutorg.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} [%p] %c{1} - %m%n log4j.appender.fileorg.apache.log4j.RollingFileAppender log4j.appender.file.Filelogs/cosmetic.log log4j.appender.file.MaxFileSize10MB log4j.appender.file.MaxBackupIndex5在ProductController.listProducts()开头添加日志logger.info(开始查询商品列表当前用户IP{}, request.getRemoteAddr());启动后查看logs/cosmetic.log是否生成带时间戳的日志行且request.getRemoteAddr()能正确输出客户端IP非127.0.0.1。5. 毕设代码优化的3个实战技巧让评审老师一眼看到技术深度5.1 使用MyBatis二级缓存降低数据库压力化妆品商品信息变动频率低新品上架除外开启二级缓存可显著减少重复查询。在ProductMapper.xml顶部添加mapper namespacecom.example.cosmetic.dao.ProductMapper cache evictionLRU flushInterval60000 size1024 readOnlytrue/ select idfindById resultTypeProduct useCachetrue SELECT * FROM product WHERE id #{id} /select /mapper关键参数说明evictionLRU淘汰最近最少使用缓存项flushInterval60000每60秒自动清空缓存避免脏数据size1024最多缓存1024个对象readOnlytrue返回对象不可修改提升性能验证连续两次访问同一商品详情页观察MySQL慢查询日志是否只记录第一次SQL执行。注意cache标签需配合update语句的flushCachetrue如updateProduct方法确保缓存及时失效。5.2 前端静态资源分离Nginx配置加速页面加载毕设演示时页面加载慢易被质疑将static目录移至Nginx服务下可提升体验。在nginx.conf中添加server { listen 80; server_name localhost; # 静态资源走Nginx location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { root /path/to/cosmetic/static; expires 1d; } # 动态请求转发给Tomcat location / { proxy_pass http://127.0.0.1:8080/cosmetic/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }效果CSS/JS文件由Nginx直接返回毫秒级JSP页面仍由Tomcat渲染。需在web.xml中将welcome-file-list指向index.jsp且JSP中引用静态资源路径改为/css/style.css绝对路径。5.3 数据库连接池监控Druid配置与连接泄漏检测HikariCP虽快但监控能力弱Druid提供可视化监控页。在applicationContext.xml中替换数据源bean iddataSource classcom.alibaba.druid.pool.DruidDataSource init-methodinit destroy-methodclose property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ property nameinitialSize value5/ property nameminIdle value5/ property namemaxActive value20/ property nametimeBetweenEvictionRunsMillis value60000/ property nameminEvictableIdleTimeMillis value300000/ property namevalidationQuery valueSELECT 1/ property nametestWhileIdle valuetrue/ property nameremoveAbandonedOnBorrow valuetrue/ property nameremoveAbandonedOnMaintenance valuetrue/ property namelogAbandoned valuetrue/ /bean启动后访问http://localhost:8080/cosmetic/druid/index.htmlDruid内置监控页可查看SQL执行耗时TOP10、活跃连接数、SQL防火墙拦截记录。logAbandonedtrue会在连接泄漏时打印堆栈帮助定位未关闭Connection的代码位置。提示若学校服务器禁用Druid监控页可将property namefilters valuestat,wall/替换为property namefilters valuestat/关闭防火墙仅保留性能统计。本文还有配套的精品资源点击获取