随着电子商务的快速发展,传统零售模式面临着商品展示渠道单一、交易流程繁琐、库存与订单管理效率低下的挑战。数字化销售渠道成为企业提升竞争力、降低运营成本的关键。PC商城系统应运而生,为中小型零售企业、品牌代理商及个体创业者提供了一个功能完整、技术成熟的在线交易解决方案。
该系统采用经典的SSM(Spring + Spring MVC + MyBatis)框架组合,结合Maven项目管理和MySQL数据库,构建了一个高内聚、低耦合的三层架构应用。Spring框架作为核心容器,统一管理业务对象的生命周期和依赖注入,其声明式事务管理机制有效保障了订单处理、支付流程等核心业务的数据一致性。Spring MVC承担Web层控制职责,通过清晰的控制器映射和参数绑定机制,实现了请求路由与页面跳转的精准控制。数据持久层由MyBatis实现,通过XML配置将Java对象与SQL操作解耦,支持动态SQL生成,显著提升了商品检索、分类查询等数据库操作的效率。
前端界面采用JSP视图技术,结合JSTL标签库和jQuery框架,实现了商品图片轮播、购物车实时更新、表单异步验证等交互功能。系统集成Log4j日志框架,完善了运行时的监控和故障排查能力。
数据库架构设计精要
系统数据库包含11个核心表,采用符合第三范式的设计理念,确保数据存储的规范性和查询效率。以下重点分析几个关键表的结构设计:
商品分类表(product_category)采用双层级设计
CREATE TABLE `product_category` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(20) NOT NULL COMMENT '分类名称',
`parent_id` int(11) DEFAULT NULL COMMENT '父级分类id',
`type` int(11) DEFAULT NULL COMMENT '深度',
`icon_class` varchar(20) DEFAULT NULL COMMENT '图标',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
该表通过parent_id字段实现无限级分类扩展,type字段标识分类层级深度,icon_class字段存储前端显示图标类名。这种设计支持灵活的商品分类管理,如"笔记本电脑"→"游戏本"的多级分类体系,同时通过索引优化提升分类查询性能。
订单表(order)的字段设计体现业务完整性
CREATE TABLE `order` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`order_no` bigint(20) NOT NULL COMMENT '订单号',
`user_id` int(11) NOT NULL COMMENT '用户id',
`payment` decimal(20,2) DEFAULT NULL COMMENT '实际付款金额',
`payment_type` int(4) DEFAULT NULL COMMENT '支付类型',
`postage` decimal(20,2) DEFAULT NULL COMMENT '运费',
`status` int(10) DEFAULT NULL COMMENT '订单状态',
`payment_time` datetime DEFAULT NULL COMMENT '支付时间',
`send_time` datetime DEFAULT NULL COMMENT '发货时间',
`end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `order_no_index` (`order_no`) USING BTREE,
KEY `user_id_index` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=115 DEFAULT CHARSET=utf8;
订单表采用业务主键与逻辑主键分离策略,id作为自增主键保证插入性能,order_no作为业务唯一标识便于查询。多个时间戳字段完整记录订单生命周期,status字段通过枚举值管理订单状态流转。复合索引设计优化了用户订单查询和订单号检索效率。
购物车表(cart)实现用户会话持久化
CREATE TABLE `cart` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` int(11) NOT NULL COMMENT '用户id',
`product_id` int(11) NOT NULL COMMENT '商品id',
`quantity` int(11) NOT NULL COMMENT '数量',
`checked` int(11) NOT NULL COMMENT '是否选择',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `user_id_index` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8;
购物车表通过user_id和product_id的唯一性约束,确保同一用户的同一商品不会重复记录。checked字段实现购物车商品选择状态管理,为订单结算提供灵活的商品选择机制。这种设计支持用户跨会话持久化购物车数据,提升用户体验。
核心功能模块实现解析
商品分类与展示模块
系统采用多级分类体系组织商品信息,前端通过动态加载技术实现分类导航。商品列表页面支持按价格、销量、上架时间等多维度排序,结合分页查询优化大数据量展示性能。
商品分类查询Service层实现
@Service("categoryService")
public class CategoryServiceImpl implements CategoryService {
@Autowired
private ProductCategoryMapper categoryMapper;
@Override
public ServerResponse<List<Category>> getCategory(int categoryId) {
if(categoryId == 0) {
// 查询所有一级分类
List<ProductCategory> categoryList = categoryMapper.selectCategoryByParentId(0);
if(CollectionUtils.isEmpty(categoryList)) {
return ServerResponse.createByErrorMessage("未找到当前分类");
}
List<Category> categories = new ArrayList<>();
for(ProductCategory productCategory : categoryList) {
Category category = assembleCategory(productCategory);
categories.add(category);
}
return ServerResponse.createBySuccess(categories);
} else {
// 查询指定分类的子分类
ProductCategory productCategory = categoryMapper.selectByPrimaryKey(categoryId);
if(productCategory == null) {
return ServerResponse.createByErrorMessage("未找到当前分类");
}
List<ProductCategory> categoryList = categoryMapper.selectCategoryByParentId(categoryId);
List<Category> categories = new ArrayList<>();
if(!CollectionUtils.isEmpty(categoryList)) {
for(ProductCategory temp : categoryList) {
Category category = assembleCategory(temp);
categories.add(category);
}
}
return ServerResponse.createBySuccess(categories);
}
}
private Category assembleCategory(ProductCategory productCategory) {
Category category = new Category();
category.setId(productCategory.getId());
category.setParentId(productCategory.getParentId());
category.setName(productCategory.getName());
category.setStatus(productCategory.getStatus());
category.setSortOrder(productCategory.getSortOrder());
category.setCreateTime(productCategory.getCreateTime());
category.setUpdateTime(productCategory.getUpdateTime());
return category;
}
}
该服务类实现了分类数据的层级查询和组装逻辑,通过递归方式构建完整的分类树结构。Service层返回统一的响应对象,便于前端处理和数据展示。

购物车与订单管理模块
购物车模块采用数据库持久化方案,支持用户登录状态的购物车数据同步。订单生成过程包含库存校验、价格计算、优惠券应用等业务逻辑,通过事务管理确保数据一致性。
购物车Controller层核心方法
@Controller
@RequestMapping("/cart/")
public class CartController {
@Autowired
private ICartService cartService;
@RequestMapping(value = "add.do", method = RequestMethod.POST)
@ResponseBody
public ServerResponse<CartVo> add(HttpSession session,
@RequestParam("productId") Integer productId,
@RequestParam("count") Integer count) {
User user = (User)session.getAttribute(Const.CURRENT_USER);
if(user == null) {
return ServerResponse.createByErrorCodeMessage(
ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
}
return cartService.add(user.getId(), productId, count);
}
@RequestMapping(value = "update.do", method = RequestMethod.POST)
@ResponseBody
public ServerResponse<CartVo> update(HttpSession session,
@RequestParam("productId") Integer productId,
@RequestParam("count") Integer count) {
User user = (User)session.getAttribute(Const.CURRENT_USER);
if(user == null) {
return ServerResponse.createByErrorCodeMessage(
ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
}
return cartService.update(user.getId(), productId, count);
}
@RequestMapping(value = "delete.do", method = RequestMethod.POST)
@ResponseBody
public ServerResponse<CartVo> delete(HttpSession session,
@RequestParam("productIds") String productIds) {
User user = (User)session.getAttribute(Const.CURRENT_USER);
if(user == null) {
return ServerResponse.createByErrorCodeMessage(
ResponseCode.NEED_LOGIN.getCode(), ResponseCode.NEED_LOGIN.getDesc());
}
return cartService.delete(user.getId(), productIds);
}
}
控制器采用RESTful风格设计,通过会话管理验证用户身份,调用服务层处理具体的购物车业务逻辑。返回的CartVo对象封装了购物车状态和商品信息,便于前端更新界面显示。

订单生成与支付流程
订单生成过程涉及复杂的业务规则校验和数据操作,系统采用事务管理确保订单创建的原子性。支付模块支持多种支付方式集成,通过状态机模式管理订单状态流转。
订单Service层核心业务逻辑
@Service("orderService")
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
@Autowired
private CartMapper cartMapper;
@Autowired
private ProductMapper productMapper;
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
@Override
@Transactional
public ServerResponse createOrder(Integer userId, Integer shippingId) {
// 从购物车中获取已选中的商品
List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId);
// 计算订单总价
ServerResponse serverResponse = this.getCartOrderItem(userId, cartList);
if(!serverResponse.isSuccess()) {
return serverResponse;
}
List<OrderItem> orderItemList = (List<OrderItem>)serverResponse.getData();
BigDecimal payment = this.getOrderTotalPrice(orderItemList);
// 生成订单
Order order = this.assembleOrder(userId, shippingId, payment);
if(order == null) {
return ServerResponse.createByErrorMessage("生成订单错误");
}
if(CollectionUtils.isEmpty(orderItemList)) {
return ServerResponse.createByErrorMessage("购物车为空");
}
for(OrderItem orderItem : orderItemList) {
orderItem.setOrderNo(order.getOrderNo());
}
// 批量插入订单明细
orderItemMapper.batchInsert(orderItemList);
// 减少商品库存
this.reduceProductStock(orderItemList);
// 清空购物车
this.cleanCart(cartList);
// 返回订单信息
OrderVo orderVo = assembleOrderVo(order, orderItemList);
return ServerResponse.createBySuccess(orderVo);
}
private ServerResponse getCartOrderItem(Integer userId, List<Cart> cartList) {
List<OrderItem> orderItemList = Lists.newArrayList();
if(CollectionUtils.isEmpty(cartList)) {
return ServerResponse.createByErrorMessage("购物车为空");
}
// 校验购物车中商品的状态和数量
for(Cart cart : cartList) {
OrderItem orderItem = new OrderItem();
Product product = productMapper.selectByPrimaryKey(cart.getProductId());
if(Const.ProductStatusEnum.ON_SALE.getCode() != product.getStatus()) {
return ServerResponse.createByErrorMessage("商品" + product.getName() + "不是在线售卖状态");
}
// 校验库存
if(cart.getQuantity() > product.getStock()) {
return ServerResponse.createByErrorMessage("商品" + product.getName() + "库存不足");
}
orderItem.setUserId(userId);
orderItem.setProductId(product.getId());
orderItem.setProductName(product.getName());
orderItem.setProductImage(product.getMainImage());
orderItem.setCurrentUnitPrice(product.getPrice());
orderItem.setQuantity(cart.getQuantity());
orderItem.setTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(), cart.getQuantity()));
orderItemList.add(orderItem);
}
return ServerResponse.createBySuccess(orderItemList);
}
}
订单创建过程包含完整的业务校验链:购物车商品状态检查、库存验证、价格计算、数据持久化和库存更新。@Transactional注解确保在异常情况下所有数据库操作都能回滚,保障数据一致性。

用户权限与会话管理
系统采用基于Session的认证机制,通过拦截器实现对用户访问权限的控制。管理员和普通用户具有不同的功能权限,通过角色标识实现界面和功能的差异化展示。
用户登录验证拦截器
public class AuthorityInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 获取请求的Session
HttpSession session = request.getSession();
User user = (User)session.getAttribute(Const.CURRENT_USER);
if(user == null) {
// 用户未登录,返回错误信息
if("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
// AJAX请求
response.setHeader("sessionstatus", "timeout");
response.sendError(518, "session timeout");
} else {
// 普通请求
response.sendRedirect(request.getContextPath() + "/user/login.do");
}
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
}
拦截器通过检查Session中存储的用户信息实现访问控制,支持普通请求和AJAX请求的不同处理方式。这种设计既保证了系统安全性,又提供了良好的用户体验。
商品搜索与筛选功能
系统实现基于多条件的商品搜索功能,支持关键字匹配、价格区间、分类筛选等复合查询条件。MyBatis的动态SQL能力有效支持了复杂查询条件的组装。
商品搜索Mapper XML配置
<!-- 商品搜索动态SQL -->
<select id="selectBySearch" parameterType="map" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM product
<where>
<if test="keyword != null and keyword != ''">
AND (name LIKE CONCAT('%',#{keyword},'%')
OR subtitle LIKE CONCAT('%',#{keyword},'%'))
</if>
<if test="categoryId != null">
AND category_id = #{categoryId}
</if>
<if test="priceMin != null">
AND price >= #{priceMin}
</if>
<if test="priceMax != null">
AND price <= #{priceMax}
</if>
<if test="status != null">
AND status = #{status}
</if>
ORDER BY
<choose>
<when test="orderBy != null and orderBy != ''">
${orderBy}
</when>
<otherwise>
create_time DESC
</otherwise>
</choose>
</where>
</select>
该动态SQL语句通过条件判断实现灵活的查询条件组合,支持按相关度、价格、销量等多种排序方式。${orderBy}参数需进行安全过滤防止SQL注入攻击。

实体模型与数据交互设计
系统实体模型严格遵循领域驱动设计原则,核心实体包括用户(User)、商品(Product)、订单(Order)、购物车(Cart)等。这些实体通过MyBatis的ORM映射与数据库表结构对应,实现了对象关系映射的透明化。
商品实体类设计
public class Product {
private Integer id;
private Integer categoryId;
private String name;
private String subtitle;
private String mainImage;
private String subImages;
private String detail;
private BigDecimal price;
private Integer stock;
private Integer status;
private Date createTime;
private Date updateTime;
// 省略getter和setter方法
public enum Status {
ON_SALE(1, "在售"),
OFF_SALE(2, "下架"),
DELETE(3, "删除");
private int code;
private String desc;
Status(int code, String desc) {
this.code = code;
this.desc = desc;
}
// 枚举值处理方法
public static Status codeOf(Integer code) {
for(Status status : values()) {
if(status.getCode() == code) {
return status;
}
}
return null;
}
}
}
实体类通过枚举类型定义业务状态码,提高了代码的可读性和维护性。与数据库字段的映射通过MyBatis的配置文件实现,支持灵活的字段映射和类型转换。
系统优化与功能扩展方向
基于当前系统架构,以下优化方向可进一步提升系统性能和用户体验:
缓存机制集成:引入Redis作为缓存层,缓存热点商品数据、分类信息和用户会话,减轻数据库压力。商品详情页等读多写少的场景特别适合采用缓存策略。
搜索引擎集成:对于大规模商品数据,可集成Elasticsearch实现全文检索和高级搜索功能,提升搜索准确性和响应速度。
分布式会话管理:采用Spring Session配合Redis实现分布式会话存储,支持