基于SSM框架的在线宠物商城销售系统 - 源码深度解析
随着电子商务的蓬勃发展,垂直领域的专业化电商平台成为市场新趋势。宠物经济作为近年来快速增长的千亿级市场板块,对数字化交易平台提出了更高的专业化和个性化要求。传统宠物用品购买渠道普遍存在信息不对称、商品质量参差不齐、活体宠物配送不专业等痛点,亟需一个集活体宠物、食品、用品、医疗服务于一体的综合性解决方案。
系统架构与技术栈设计
该平台采用经典的SSM(Spring+Spring MVC+MyBatis)框架组合,构建了高内聚低耦合的分层架构:
核心框架设计理念
- Spring框架:作为IoC容器,通过依赖注入管理所有业务组件的生命周期,利用AOP实现日志记录、性能监控等横切关注点,通过声明式事务管理确保订单、库存等关键业务的数据一致性
- Spring MVC:基于前端控制器模式,通过
DispatcherServlet统一处理请求分发,支持RESTful风格的URL映射,配合视图解析器实现前后端数据交互 - MyBatis:作为轻量级持久层框架,通过灵活的XML配置实现对象关系映射,支持动态SQL和二级缓存,显著简化数据库操作复杂度
技术栈详细配置
项目采用Maven进行依赖管理,确保第三方库版本的一致性,关键配置如下:
<!-- Maven核心依赖配置 -->
<dependencies>
<!-- Spring MVC Web框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!-- MyBatis与Spring整合 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- MySQL数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!-- 数据连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
</dependencies>
技术选型优势:
- 前端使用HTML5+CSS3+JavaScript构建响应式界面,兼容移动端设备
- 后端采用Java 8的Lambda表达式和Stream API提升代码简洁性
- 数据库选用MySQL 5.7,支持InnoDB事务处理和查询优化
- 使用Druid连接池实现数据库连接的高效管理
数据库架构深度解析
地址管理模块的精细化设计
地址表的设计体现了电商系统对用户数据管理的专业性,采用三级行政区划联动设计,通过外键关联确保数据一致性:
CREATE TABLE `address` (
`addr_Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '地址ID',
`addr_province` varchar(20) DEFAULT NULL COMMENT '省份',
`addr_city` varchar(20) DEFAULT NULL COMMENT '城市',
`addr_area` varchar(20) DEFAULT NULL COMMENT '区域',
`addr_detail` varchar(60) DEFAULT NULL COMMENT '详细地址',
`addr_user` int(11) DEFAULT NULL COMMENT '用户ID',
`addr_zipcode` varchar(255) DEFAULT NULL COMMENT '邮政编码',
`addr_phone` varchar(255) DEFAULT NULL COMMENT '联系电话',
`addr_nickname` varchar(255) DEFAULT NULL COMMENT '地址昵称',
`addr_state` int(11) DEFAULT 1 COMMENT '1 正常 -1删除',
PRIMARY KEY (`addr_Id`),
KEY `addr_user` (`addr_user`),
CONSTRAINT `address_ibfk_1` FOREIGN KEY (`addr_user`) REFERENCES `users` (`user_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COMMENT='地址表'
设计亮点深度分析:
1. 索引优化策略
- 在
addr_user字段建立普通索引,显著加速基于用户ID的地址查询 - 采用最左前缀原则,支持复合查询优化
2. 数据完整性保障
- 通过外键约束确保地址数据与用户表的引用完整性
- 使用InnoDB存储引擎支持事务处理和行级锁定
3. 业务逻辑优化
- 软删除机制:通过
addr_state字段实现逻辑删除,保留历史订单的地址信息 - 字段长度优化:详细地址字段设定60字符,平衡存储效率与用户体验
- 地址昵称设计:支持"家庭地址"、"公司地址"等个性化标识
行政区划数据的关系模型
行政区划表采用层级关联设计,实现高效的地区数据管理和快速查询:
-- 省份信息表
CREATE TABLE `provinces` (
`province_Id` varchar(20) NOT NULL COMMENT '省份ID',
`province_Name` varchar(50) NOT NULL COMMENT '省份名称',
PRIMARY KEY (`province_Id`),
KEY `provinceid` (`province_Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='省份信息表'
-- 城市信息表
CREATE TABLE `cities` (
`city_Id` varchar(20) NOT NULL COMMENT '城市ID',
`city_Name` varchar(50) NOT NULL COMMENT '城市名称',
`province_Id` varchar(20) NOT NULL COMMENT '省份ID',
PRIMARY KEY (`city_Id`),
KEY `provinceId` (`province_Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='行政区域地州市信息表'
-- 区域信息表
CREATE TABLE `areas` (
`area_Id` varchar(20) NOT NULL COMMENT '区域ID',
`area_Name` varchar(50) NOT NULL COMMENT '区域名称',
`city_Id` varchar(20) NOT NULL COMMENT '城市ID',
PRIMARY KEY (`area_Id`),
KEY `cityId` (`city_Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='行政区域县区信息表'
数据库设计优势:
- 层级关系明确,支持高效的级联查询和下拉联动
- 使用MyISAM引擎提升读取性能,适合静态数据存储
- 统一的编码规范,便于与第三方地图服务集成
核心业务功能实现
地址管理功能的技术实现
地址控制器采用RESTful风格设计,支持完整的CRUD操作,确保代码的可维护性和扩展性:
@Controller
@RequestMapping("/address")
public class AddressController {
@Autowired
private IAddressService addressService;
@Autowired
private IProCityAreaService pService;
/**
* 根据用户ID查询地址列表
*/
@RequestMapping(value = "/findAddrByUserId", method = RequestMethod.GET)
@ResponseBody
public ResponseResult<List<Address>> findAddrByUserId(HttpServletRequest request) {
try {
HttpSession session = request.getSession();
Users user = (Users) session.getAttribute("user");
if (user == null) {
return ResponseResult.error("用户未登录");
}
List<Address> addressList = addressService.findAddressByUserId(user.getUserId());
return ResponseResult.success("查询成功", addressList);
} catch (Exception e) {
logger.error("查询用户地址失败", e);
return ResponseResult.error("系统异常");
}
}
/**
* 新增收货地址
*/
@RequestMapping(value = "/addAddress", method = RequestMethod.POST)
@ResponseBody
public ResponseResult<String> addAddress(@Valid Address addr, BindingResult result,
HttpServletRequest request) {
// 参数校验
if (result.hasErrors()) {
return ResponseResult.error("参数格式错误");
}
try {
// 行政区划ID到名称的转换
String provinceId = addr.getAddrProvince();
String cityId = addr.getAddrCity();
String areaId = addr.getAddrArea();
Provinces province = pService.findProvinceById(provinceId);
Cities city = pService.findCityById(cityId);
Areas area = pService.findAreaById(areaId);
// 设置完整的地址信息
addr.setAddrProvince(province.getProvinceName());
addr.setAddrCity(city.getCityName());
addr.setAddrArea(area.getAreaName());
// 关联用户信息
HttpSession session = request.getSession();
Users user = (Users) session.getAttribute("user");
addr.setAddrUser(user.getUserId());
// 执行业务逻辑
Integer rs = addressService.addAddress(addr);
return rs > 0 ? ResponseResult.success("添加成功") : ResponseResult.error("添加失败");
} catch (Exception e) {
logger.error("添加地址异常", e);
return ResponseResult.error("系统异常");
}
}
/**
* 更新地址信息
*/
@RequestMapping(value = "/updateAddress", method = RequestMethod.PUT)
@ResponseBody
public ResponseResult<String> updateAddress(@Valid Address addr, BindingResult result) {
// 实现细节...
}
/**
* 删除地址(软删除)
*/
@RequestMapping(value = "/deleteAddress/{addrId}", method = RequestMethod.DELETE)
@ResponseBody
public ResponseResult<String> deleteAddress(@PathVariable("addrId") Integer addrId) {
// 实现细节...
}
}

购物车与订单处理逻辑
购物车功能采用Session与数据库结合的混合存储策略,既保证用户体验的连贯性,又确保数据的持久化安全:
@Service
@Transactional
public class CartServiceImpl implements ICartService {
@Autowired
private CartMapper cartMapper;
@Autowired
private GoodsMapper goodsMapper;
/**
* 添加商品到购物车
*/
@Override
public ResponseResult<String> addToCart(Cart cart) {
try {
// 参数验证
if (cart.getCartUser() == null || cart.getCartGoods() == null) {
return ResponseResult.error("参数不完整");
}
// 检查商品库存
Goods goods = goodsMapper.findGoodsById(cart.getCartGoods());
if (goods == null || goods.getGoodsStock() <= 0) {
return ResponseResult.error("商品不存在或库存不足");
}
// 检查商品是否已存在购物车
Cart existCart = cartMapper.findCartByUserIdAndGoodsId(
cart.getCartUser(), cart.getCartGoods());
if (existCart != null) {
// 更新数量,检查库存限制
int newNum = existCart.getCartNum() + cart.getCartNum();
if (newNum > goods.getGoodsStock()) {
return ResponseResult.error("超过库存限制");
}
existCart.setCartNum(newNum);
cartMapper.updateCart(existCart);
} else {
// 新增购物车记录
if (cart.getCartNum() > goods.getGoodsStock()) {
return ResponseResult.error("超过库存限制");
}
cart.setAddTime(new Date());
cartMapper.addCart(cart);
}
return ResponseResult.success("添加成功");
} catch (Exception e) {
logger.error("添加购物车异常", e);
throw new RuntimeException("系统异常");
}
}
/**
* 获取用户购物车列表
*/
@Override
public ResponseResult<List<CartVO>> getCartList(Integer userId) {
// 实现购物车商品信息查询,包括商品图片、价格等详细信息
}
/**
* 更新购物车商品数量
*/
@Override
public ResponseResult<String> updateCartNum(Integer cartId, Integer num) {
// 实现数量更新和库存验证
}
/**
* 批量删除购物车商品
*/
@Override
public ResponseResult<String> batchDeleteCart(List<Integer> cartIds) {
// 实现批量删除操作
}
}
系统安全与性能优化
安全防护措施
- SQL注入防护:使用MyBatis的参数绑定机制,避免字符串拼接
- XSS攻击防护:对用户输入进行过滤和转义处理
- CSRF防护:采用Token验证机制保护重要操作
- 会话安全:设置Session超时时间,使用HTTPS传输敏感数据
性能优化策略
- 数据库优化:合理使用索引,避免全表扫描
- 缓存机制:对热点数据使用Redis缓存
- 连接池优化:配置合适的连接池参数
- 静态资源优化:使用CDN加速图片等静态资源加载
该系统通过严谨的架构设计和精细的代码实现,为宠物电商领域提供了一个稳定、可扩展的技术解决方案,具有良好的示范意义和实用价值。