1. 项目概述与背景
作为一名长期从事Java Web开发的工程师,我最近完成了一个基于SSM框架的服装商城毕业设计项目。这个系统专门针对中小型服装企业的实际需求,解决了传统服装行业在信息化转型过程中遇到的诸多痛点。
服装行业与其他零售领域相比有着显著的特殊性——每件商品都涉及款式、颜色、尺码、材质等多维度属性。我曾亲眼见过一家小型服装店的老板,每天打烊后要花两三个小时手工记录库存变动,还经常出现记录错误导致库存不准的情况。这种低效的管理方式在数字化时代显得尤为落后。
本系统采用SSM(Spring+SpringMVC+MyBatis)框架组合,这是目前Java Web开发中最成熟稳定的技术方案之一。Spring框架提供了强大的IoC容器和AOP支持,SpringMVC处理Web层请求响应,MyBatis则负责数据持久化。三者结合既保证了系统性能,又保持了良好的可维护性。
2. 系统架构设计
2.1 技术选型考量
选择SSM框架而非更流行的Spring Boot主要基于以下考虑:
- 毕业设计需要展示对基础框架的深入理解
- 手动配置过程能更好掌握框架整合原理
- 中小型系统对快速启动需求不高
数据库选用MySQL 5.7而非更新的8.0版本,主要因为:
- 5.7版本稳定性经过长期验证
- 对硬件资源要求更低
- 社区支持完善,问题更易解决
前端采用Vue.js+Layui混合方案:
- Vue.js负责数据驱动视图更新
- Layui提供现成的UI组件和工具方法
- 这种组合既保持了现代前端开发的效率,又降低了学习成本
2.2 系统分层架构
系统严格遵循MVC模式分层:
表现层:
- 基于SpringMVC框架
- 采用@Controller处理HTTP请求
- 统一异常处理机制
- 参数校验注解化
业务逻辑层:
- Service接口与实现分离
- 事务管理通过@Transactional注解
- 业务规则集中处理
- 日志记录AOP实现
持久层:
- MyBatis映射器接口+XML配置
- 动态SQL生成
- 二级缓存配置
- 分页插件集成
数据访问层:
- MySQL关系型数据库
- Druid连接池管理
- 读写分离设计(预留接口)
- 定期备份机制
3. 核心功能实现
3.1 会员管理模块
会员系统采用分级设计:
- 普通会员(可浏览、购买)
- VIP会员(享受折扣)
- 管理员(后台管理)
关键实现细节:
java复制// 会员注册逻辑核心代码
@Transactional
public Result register(Member member) {
// 校验用户名唯一性
if(memberMapper.checkUsernameExist(member.getUsername()) > 0){
return Result.error("用户名已存在");
}
// 密码加密存储
String salt = UUID.randomUUID().toString();
String encryptedPwd = DigestUtils.md5DigestAsHex(
(member.getPassword()+salt).getBytes());
member.setPassword(encryptedPwd);
member.setSalt(salt);
// 设置默认会员等级
member.setLevel(1);
member.setRegisterTime(new Date());
// 写入数据库
if(memberMapper.insert(member) == 1){
return Result.success("注册成功");
}
return Result.error("注册失败");
}
注意:密码必须加盐存储,直接MD5加密已不再安全。这里采用UUID生成随机盐值,与密码拼接后再进行MD5加密。
3.2 服装多属性管理
服装商品的SKU管理是系统最大难点。我们采用"主表+属性关联表"的设计模式:
数据库设计:
sql复制CREATE TABLE `t_clothing` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`category_id` int(11) NOT NULL,
`price` decimal(10,2) NOT NULL,
`main_image` varchar(255) DEFAULT NULL,
`status` tinyint(4) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `t_clothing_sku` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`clothing_id` int(11) NOT NULL,
`color_id` int(11) NOT NULL,
`size_id` int(11) NOT NULL,
`stock` int(11) NOT NULL DEFAULT '0',
`barcode` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_clothing_color_size` (`clothing_id`,`color_id`,`size_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
前端SKU组合生成:
使用Vue.js动态生成SKU表格:
javascript复制// 当选择颜色和尺码后生成SKU组合
generateSKUs() {
this.skus = [];
this.selectedColors.forEach(color => {
this.selectedSizes.forEach(size => {
this.skus.push({
colorId: color.id,
colorName: color.name,
sizeId: size.id,
sizeName: size.name,
stock: 0,
price: this.form.price
});
});
});
}
3.3 库存管理实现
库存变动采用"操作日志+实时更新"双写机制:
- 任何库存变动都记录操作日志(包含操作人、时间、原因)
- 实时更新SKU表中的库存数量
- 定期进行库存盘点校对
库存预警功能实现逻辑:
java复制// 每日凌晨检查库存
@Scheduled(cron = "0 0 2 * * ?")
public void checkInventoryWarning() {
List<ClothingSku> lowStockSkus = skuMapper.selectLowStock(10); // 阈值10件
if(!lowStockSkus.isEmpty()){
String content = "以下商品库存不足:\n";
for(ClothingSku sku : lowStockSkus){
content += String.format("%s %s %s 剩余%d件\n",
sku.getClothingName(),
sku.getColorName(),
sku.getSizeName(),
sku.getStock());
}
// 发送邮件通知
emailService.sendInventoryWarning(content);
}
}
4. 关键技术实现细节
4.1 SSM框架整合
关键配置项:
- Spring与MyBatis整合
xml复制<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.fashion.entity"/>
</bean>
<!-- 配置Mapper扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.fashion.dao"/>
</bean>
- 事务管理配置
java复制@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
4.2 高并发优化方案
- 数据库连接池配置(Druid)
properties复制# 初始连接数
spring.datasource.initialSize=5
# 最小空闲连接
spring.datasource.minIdle=5
# 最大活跃连接
spring.datasource.maxActive=20
# 获取连接超时时间(毫秒)
spring.datasource.maxWait=60000
- Redis缓存热点数据
java复制@Cacheable(value = "clothing", key = "#id")
public Clothing getClothingById(Integer id) {
return clothingMapper.selectByPrimaryKey(id);
}
@CacheEvict(value = "clothing", key = "#clothing.id")
public void updateClothing(Clothing clothing) {
clothingMapper.updateByPrimaryKey(clothing);
}
- 页面静态化处理
- 商品详情页生成静态HTML
- 使用Nginx直接服务静态内容
- 设置合理的缓存头
5. 系统安全设计
5.1 认证与授权
采用Spring Security实现RBAC模型:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/member/**").hasAnyRole("MEMBER","ADMIN")
.antMatchers("/**").permitAll()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.and()
.logout()
.logoutSuccessUrl("/");
}
}
5.2 常见攻击防护
- SQL注入防护
- 严格使用MyBatis参数绑定
- 禁止拼接SQL语句
- 正则过滤特殊字符
- XSS防护
- 前端使用vue-sanitize过滤输入
- 后端对富文本内容使用JSoup清洗
java复制String safeHtml = Jsoup.clean(rawHtml,
Whitelist.basicWithImages()
.addAttributes(":all", "style"));
- CSRF防护
- 启用Spring Security的CSRF保护
- 敏感操作要求二次验证
6. 部署与运维方案
6.1 系统部署流程
- 环境准备
bash复制# 安装JDK
yum install java-1.8.0-openjdk-devel
# 安装MySQL
wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
rpm -ivh mysql57-community-release-el7-11.noarch.rpm
yum install mysql-community-server
# 安装Tomcat
tar -zxvf apache-tomcat-7.0.107.tar.gz
mv apache-tomcat-7.0.107 /usr/local/tomcat
- 数据库初始化
sql复制CREATE DATABASE fashion_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON fashion_db.* TO 'fashion'@'%' IDENTIFIED BY 'StrongPassword123';
FLUSH PRIVILEGES;
- 应用部署
xml复制<!-- Maven打包配置 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<warName>fashion</warName>
</configuration>
</plugin>
6.2 监控与维护
- 健康检查接口
java复制@RestController
@RequestMapping("/monitor")
public class MonitorController {
@Autowired
private DataSource dataSource;
@GetMapping("/health")
public Result healthCheck() {
try(Connection conn = dataSource.getConnection()){
return Result.success("系统运行正常");
} catch(Exception e) {
return Result.error("数据库连接异常");
}
}
}
- 日志收集方案
- 使用Logback记录日志
- 按天滚动日志文件
- 关键操作记录审计日志
- 备份策略
bash复制# 数据库备份脚本
mysqldump -u fashion -p fashion_db > /backup/fashion_$(date +%Y%m%d).sql
# 打包备份文件
tar -czvf /backup/fashion_$(date +%Y%m%d).tar.gz /usr/local/tomcat/webapps/fashion
7. 开发经验与心得
在开发这个服装商城系统的过程中,我积累了一些宝贵的经验教训:
-
关于SKU管理的思考
最初尝试使用JSON字段存储所有属性,虽然灵活但查询效率低下。最终回归关系型数据库设计,通过合理的表结构解决多属性查询问题。这让我明白:不要为了追求新技术而放弃经过验证的方案。 -
事务处理的坑
在一次库存扣减操作中,由于没有正确处理事务隔离级别,导致出现了超卖情况。解决方法是在更新语句中添加库存检查:
sql复制UPDATE t_clothing_sku
SET stock = stock - #{quantity}
WHERE id = #{id} AND stock >= #{quantity}
-
缓存一致性问题
引入Redis缓存后,出现过缓存与数据库不一致的情况。最终采用"先更新数据库,再删除缓存"的策略,虽然可能产生短暂不一致,但简单可靠。 -
前端性能优化
商品列表页最初加载缓慢,通过以下优化将加载时间从3s降到800ms:
- 启用数据库查询缓存
- 实现分页查询
- 使用懒加载图片
- 压缩静态资源
这个项目从开题到最终完成历时4个月,期间经历了多次架构调整和代码重构。最大的收获是认识到:一个好的系统不是一蹴而就的,而是在不断解决实际问题中逐步完善的。