基于SSH框架的在线数码电子产品销售系统 - 源码深度解析

JavaJavaScriptSSH框架HTMLCSSMySQLJSP+Servlet
2026-02-214 浏览

文章摘要

本系统是基于SSH(Struts2 + Spring + Hibernate)集成框架开发的在线数码电子产品销售平台,旨在为消费者提供便捷、安全的电子产品购买渠道,并为商家构建标准化的线上零售管理后台。其核心业务价值在于解决了传统实体零售受限于时间与空间、商品信息更新滞后以及库存管理效率低下的核心痛...

在电子商务蓬勃发展的时代背景下,专营数码电子产品的零售商面临着实体店模式固有的局限性:营业时间与地域的束缚、商品信息更新缓慢、库存管理效率低下以及高昂的运营成本。为了解决这些核心痛点,一个基于成熟稳定的SSH(Struts2 + Spring + Hibernate)集成框架的线上销售平台应运而生。该系统为“数码优品在线商城”提供了一个功能完备、技术可靠的解决方案,实现了从商品展示、用户交互到订单处理、后台管理的全流程数字化。

该系统采用经典的三层架构设计,每一层都由特定的框架组件负责,确保了系统的高内聚、低耦合特性。表现层由Struts2框架主导,负责处理所有用户界面交互。Struts2通过其强大的拦截器机制,实现了统一的权限验证、请求日志记录和异常处理,保证了前端请求的安全性与可追溯性。业务逻辑层则由Spring框架的IoC(控制反转)容器进行统一管理。Spring通过依赖注入(DI)将各个Service组件(如ProductService, OrderService, UserService)进行解耦,使得业务逻辑的单元测试和模块替换变得异常便捷。同时,Spring的声明式事务管理为订单创建、库存扣减等核心业务操作提供了坚实的数据一致性保障。数据持久层建立在Hibernate之上,通过对象关系映射(ORM)技术,将Java实体对象与数据库表无缝关联,极大地简化了数据持久化操作,并支持使用HQL(Hibernate Query Language)进行灵活高效的数据查询。

数据库架构设计与核心表解析

一个稳健的电子商务系统,其根基在于精心设计的数据库模型。“数码优品在线商城”的数据库由7张核心表构成,它们共同支撑了用户、商品、订单等关键业务数据的存储与流转。以下重点分析其中几个具有代表性的表结构。

1. 商品信息表(product

商品表是系统的核心数据载体,其设计直接影响到商品管理的灵活性和查询性能。

CREATE TABLE `product` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `pname` varchar(255) DEFAULT NULL,
  `market_price` double DEFAULT NULL,
  `shop_price` double DEFAULT NULL,
  `pimage` varchar(255) DEFAULT NULL,
  `pdate` date DEFAULT NULL,
  `is_hot` int(11) DEFAULT NULL,
  `pdesc` varchar(255) DEFAULT NULL,
  `pflag` int(11) DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  `csid` int(11) DEFAULT NULL,
  PRIMARY KEY (`pid`),
  KEY `FKED8DCCEFB9B74E02` (`cid`),
  KEY `FKED8DCCEF3DB8B0AD` (`csid`),
  CONSTRAINT `FKED8DCCEF3DB8B0AD` FOREIGN KEY (`csid`) REFERENCES `categorysecond` (`csid`),
  CONSTRAINT `FKED8DCCEFB9B74E02` FOREIGN KEY (`cid`) REFERENCES `category` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=74 DEFAULT CHARSET=utf8;

该表设计的亮点在于:

  • 价格策略字段:同时定义了market_price(市场价)和shop_price(商城价),为营销活动(如显示原价与折扣价)提供了数据支持。
  • 商品状态标识:通过is_hot(是否热门)和pflag(商品状态,如上架/下架)等标志位,实现了商品的可视化与精细化运营。
  • 二级分类关联:通过cid(一级分类ID)和csid(二级分类ID)两个外键,与分类表建立了多级关联。这种设计支持了“手机 -> 智能手机”这样的层级导航,使得商品归类清晰,用户筛选便捷。外键约束确保了分类数据的完整性和一致性。

2. 订单表(orders

订单表记录了交易的最终结果,是电商业务流程的枢纽。

CREATE TABLE `orders` (
  `oid` int(11) NOT NULL AUTO_INCREMENT,
  `total` double DEFAULT NULL,
  `ordertime` datetime DEFAULT NULL,
  `state` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `addr` varchar(30) DEFAULT NULL,
  `uid` int(11) DEFAULT NULL,
  PRIMARY KEY (`oid`),
  KEY `FKC3DF62E5AA3D9C7` (`uid`),
  CONSTRAINT `FKC3DF62E5AA3D9C7` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=10004 DEFAULT CHARSET=utf8;

该表设计的核心考量是:

  • 订单状态流state字段用于标识订单的生命周期状态,如1(未付款)、2(已付款未发货)、3(已发货)、4(已完成)等。这是驱动后台订单处理流程和前台用户查看进度的重要依据。
  • 冗余信息存储:订单中存储了收货人name、电话phone和地址addr。这是一个关键设计。它保存了下单瞬间的快照信息,即使用户后续修改了默认收货地址,历史订单的配送信息也不会改变,保证了交易记录的不可篡改性。
  • 用户关联:通过uid与用户表关联,建立了用户与其所有订单的一对多关系。

3. 订单项表(orderitem

订单项表是解决“订单-商品”多对多关系的典型中间表设计。

CREATE TABLE `orderitem` (
  `itemid` int(11) NOT NULL AUTO_INCREMENT,
  `count` int(11) DEFAULT NULL,
  `subtotal` double DEFAULT NULL,
  `pid` int(11) DEFAULT NULL,
  `oid` int(11) DEFAULT NULL,
  PRIMARY KEY (`itemid`),
  KEY `FKE8B2AB6166C01961` (`oid`),
  KEY `FKE8B2AB6171DB7AE4` (`pid`),
  CONSTRAINT `FKE8B2AB6166C01961` FOREIGN KEY (`oid`) REFERENCES `orders` (`oid`),
  CONSTRAINT `FKE8B2AB6171DB7AE4` FOREIGN KEY (`pid`) REFERENCES `product` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;

其核心价值在于:

  • 解耦订单与商品:一个订单(oid)可以包含多个商品(pid),一个商品也可以出现在多个订单中。此表完美地描述了这种复杂的多对多关系。
  • 快照与汇总:该表存储了商品购买时的数量(count)和小计金额(subtotal)。即使商品后续价格变动,订单项中的历史价格和金额依然保持不变,确保了财务数据的准确性。订单的总金额(orders.total)本质上是由其关联的所有订单项的subtotal汇总而成。

核心业务功能的技术实现

1. 商品浏览与多级分类检索

系统首页和商品列表页需要高效地展示商品,并支持按分类、价格、热度等多维度筛选。这主要通过Hibernate的动态查询来实现。

实现代码示例:商品分页查询Service方法

// ProductService.java
@Service
@Transactional
public class ProductService {
    @Autowired
    private ProductDao productDao;

    public PageBean<Product> findByPage(Integer cid, Integer csid, String pname, 
                                         int page, int limit) {
        PageBean<Product> pageBean = new PageBean<>();
        // 设置当前页
        pageBean.setPage(page);
        // 设置每页记录数
        pageBean.setLimit(limit);

        // 调用Dao层获取总记录数
        int totalCount = productDao.findCount(cid, csid, pname);
        pageBean.setTotalCount(totalCount);

        // 计算总页数
        int totalPage = (totalCount % limit == 0) ? (totalCount / limit) : (totalCount / limit + 1);
        pageBean.setTotalPage(totalPage);

        // 计算开始索引
        int begin = (page - 1) * limit;
        // 调用Dao层获取分页列表数据
        List<Product> list = productDao.findByPage(cid, csid, pname, begin, limit);
        pageBean.setList(list);

        return pageBean;
    }
}
// ProductDaoImpl.java
@Repository
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
    @Autowired
    public void setSessionFactoryOverride(SessionFactory sessionFactory) {
        super.setSessionFactory(sessionFactory);
    }

    @Override
    public int findCount(Integer cid, Integer csid, String pname) {
        String hql = "select count(*) from Product p where 1=1 ";
        Map<String, Object> params = new HashMap<>();
        if (cid != null) {
            hql += " and p.category.cid = :cid ";
            params.put("cid", cid);
        }
        if (csid != null) {
            hql += " and p.categorySecond.csid = :csid ";
            params.put("csid", csid);
        }
        if (pname != null && !pname.trim().isEmpty()) {
            hql += " and p.pname like :pname ";
            params.put("pname", "%" + pname + "%");
        }
        Query query = this.getSessionFactory().getCurrentSession().createQuery(hql);
        for (String key : params.keySet()) {
            query.setParameter(key, params.get(key));
        }
        return ((Long) query.uniqueResult()).intValue();
    }

    @Override
    public List<Product> findByPage(Integer cid, Integer csid, String pname, 
                                     int begin, int limit) {
        String hql = "from Product p where 1=1 ";
        Map<String, Object> params = new HashMap<>();
        if (cid != null) {
            hql += " and p.category.cid = :cid ";
            params.put("cid", cid);
        }
        if (csid != null) {
            hql += " and p.categorySecond.csid = :csid ";
            params.put("csid", csid);
        }
        if (pname != null && !pname.trim().isEmpty()) {
            hql += " and p.pname like :pname ";
            params.put("pname", "%" + pname + "%");
        }
        hql += " order by p.pdate desc"; // 按上架时间倒序排列
        Query query = this.getSessionFactory().getCurrentSession().createQuery(hql);
        for (String key : params.keySet()) {
            query.setParameter(key, params.get(key));
        }
        query.setFirstResult(begin);
        query.setMaxResults(limit);
        return query.list();
    }
}

技术解析:上述代码展示了后端分页查询的经典模式。PageBean是一个封装了分页信息(当前页、总页数、数据列表等)的通用类。ProductService的业务方法通过动态拼接HQL语句,根据传入的分类ID、二级分类ID和商品名称关键字构建查询条件,并使用setFirstResultsetMaxResults方法实现数据库层面的分页,有效避免了内存溢出和性能瓶颈。

商品详情页

2. 购物车管理与订单生成

购物车是连接商品浏览与订单结算的桥梁,其核心是维护一个临时的商品清单及其数量。

实现代码示例:购物车实体与添加商品操作

// Cart.java (购物车实体)
public class Cart {
    // 购物项集合: key为商品ID, value为购物项
    private Map<Integer, CartItem> map = new HashMap<>();
    private double total; // 购物车总金额

    // 添加商品到购物车
    public void addCart(Product product, int count) {
        Integer pid = product.getPid();
        // 判断购物车中是否存在该购物项
        if (map.containsKey(pid)) {
            // 存在,修改数量和小计
            CartItem cartItem = map.get(pid);
            cartItem.setCount(cartItem.getCount() + count);
        } else {
            // 不存在,创建新的购物项
            CartItem cartItem = new CartItem();
            cartItem.setProduct(product);
            cartItem.setCount(count);
            map.put(pid, cartItem);
        }
        // 设置总金额
        total += product.getShop_price() * count;
    }

    // 从购物车移除购物项
    public void removeCart(Integer pid) {
        CartItem cartItem = map.remove(pid);
        total -= cartItem.getSubtotal();
    }

    // 清空购物车
    public void clearCart() {
        map.clear();
        total = 0;
    }
    // ... getters and setters
}
// CartAction.java (Struts2 Action)
public class CartAction extends ActionSupport implements SessionAware {
    private Integer pid; // 接收商品ID
    private Integer count; // 接收购买数量
    private Map<String, Object> session;

    public String addToCart() {
        // 1. 根据pid查询商品信息
        Product product = productService.findByPid(pid);
        // 2. 从Session中获取购物车
        Cart cart = (Cart) session.get("cart");
        if (cart == null) {
            cart = new Cart();
            session.put("cart", cart);
        }
        // 3. 将商品添加到购物车
        cart.addCart(product, count);
        return "addToCartSuccess";
    }

    @Override
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }
    // ... getters and setters
}

技术解析:购物车通常存储在用户的Session中,以保证在同一浏览器会话期间数据的连续性。Cart类内部使用一个Map来管理购物项(CartItem),键为商品ID,值为包含商品、数量和小计的购物项对象。这种设计使得添加、删除和更新商品数量的操作非常高效(时间复杂度接近O(1))。CartAction接收前端传递的商品ID和数量,调用Service层获取完整的商品对象,然后操作Session中的购物车。

添加到购物车

3. 订单创建与事务管理

订单生成是电商系统最核心、最复杂的业务,涉及购物车清理、订单主表记录生成、多个订单项记录生成、库存扣减等多个步骤,必须保证在一个事务内完成。

实现代码示例:订单生成Service方法

// OrderServiceImpl.java
@Service
@Transactional // 声明式事务管理:整个方法在一个事务中执行
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private ProductDao productDao;

    @Override
    public void save(Orders order, Cart cart) {
        // 1. 保存订单主表数据 (向orders表插入一条记录)
        orderDao.save(order);

        // 2. 遍历购物车,生成订单项 (向orderitem表插入多条记录)
        for (CartItem cartItem : cart.getCartItems()) {
            OrderItem orderItem = new OrderItem();
            orderItem.setOrders(order); // 设置所属订单
            orderItem.setProduct(cartItem.getProduct()); // 设置商品
            orderItem.setCount(cartItem.getCount()); // 设置数量
            orderItem.setSubtotal(cartItem.getSubtotal()); // 设置小计
            orderDao.saveItem(orderItem);

            // 3. 更新商品库存(此处示例,实际表结构中需有stock字段)
            Product product = cartItem.getProduct();
            int newStock = product.getStock() - cartItem.getCount();
            if (newStock < 0) {
                throw new RuntimeException("商品[" + product.getPname() + "]库存不足");
            }
            product.setStock(newStock);
            productDao.update(product); // 更新商品库存
        }

        // 4. 清空购物车
        cart.clearCart();
    }
}

技术解析:该方法使用了Spring的@Transactional注解进行声明式事务管理。这是至关重要的。如果在保存订单项或更新库存的过程中发生任何异常(如库存不足、数据库连接中断),Spring会自动回滚整个事务,确保不会产生脏数据(例如,订单创建了却没有扣减库存)。这种“原子性”操作是保证系统数据一致性的基石。OrderOrderItem实体类之间通过Hibernate配置了一对多的关联关系。

确认订单

4. 后台商品与订单管理

后台管理系统为商家提供了商品上架、信息修改、订单处理等核心功能。

实现代码示例:商品上架Action

// AdminProductAction.java
public class AdminProductAction extends ActionSupport implements ModelDriven<Product> {
    private Product product = new Product();
    // 上传文件相关属性
    private File upload; // 上传的文件本身
    private String uploadFileName; // 上传文件的原始名称
    private String uploadContentType;

    @Autowired
    private ProductService productService;

    public String save() throws IOException {
        // 1. 处理图片上传
        if (upload != null) {
            String filePath = "路径/to/upload/";
            // 生成唯一文件名,防止覆盖
            String uuid = UUID.randomUUID().toString().replace("-", "");
            String realName = uuid + "_" + uploadFileName;
            File destFile = new File(filePath + realName);
            FileUtils.copyFile(upload, destFile); // 使用commons-io工具类
            product.setPimage("products/" + realName); // 设置图片路径
        }

        // 2. 设置其他属性(如时间)
        product.setPdate(new Date());

        // 3. 调用Service保存商品
        productService.save(product);
        return "saveSuccess";
    }

    @Override
    public Product getModel() {
        return product;
    }
    // ... getters and setters for upload fields
}

技术解析:此Action使用

本文关键词
SSH框架在线销售系统数码电子产品源码解析电子商务系统

上下篇

上一篇
没有更多文章
下一篇
没有更多文章