在当今电子商务蓬勃发展的时代,传统电子产品零售商面临着渠道单一、库存管理效率低下和客户触达范围有限等多重挑战。针对这些痛点,采用SSH(Struts2 + Spring + Hibernate)整合框架开发的电子产品在线销售平台应运而生,为企业提供了一个功能完备、稳定可靠的B2C电子商务解决方案。
系统架构与技术栈
该平台采用经典的三层架构设计,通过成熟的Java EE技术栈实现高内聚、低耦合的系统结构。表现层使用Struts2框架处理用户请求和页面跳转,利用其拦截器机制实现统一的权限验证和数据校验。业务逻辑层由Spring框架的IoC容器管理,通过依赖注入方式解耦各个Service组件,如商品查询服务、订单生成服务等。数据持久层依托Hibernate实现对象关系映射,通过HQL语言简化复杂查询操作,并利用缓存机制提升数据访问性能。
技术栈配置如下:
<!-- Struts2核心依赖 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.30</version>
</dependency>
<!-- Spring框架依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.18</version>
</dependency>
<!-- Hibernate依赖 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.10.Final</version>
</dependency>
数据库设计亮点
订单表设计优化
订单表(indent)的设计体现了电商系统对数据完整性和查询性能的深度考量:
CREATE TABLE `indent` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`total` float DEFAULT NULL COMMENT '总价',
`amount` int(11) DEFAULT NULL COMMENT '商品总数',
`status` tinyint(4) DEFAULT 1 COMMENT '订单状态(1未付款/2已付款/3已发货/4已完成)',
`paytype` tinyint(4) DEFAULT 0 COMMENT '支付方式 (1微信/2支付宝/3货到付款)',
`systime` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT '下单时间',
`user_id` int(11) DEFAULT NULL COMMENT '下单用户',
`name` varchar(11) DEFAULT NULL COMMENT '收货人姓名',
`idcardno` varchar(20) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='订单表'
该表设计具有以下技术亮点:
- 状态字段优化:使用tinyint类型存储订单状态和支付方式,既节省存储空间又提高查询效率
- 时间戳管理:systime字段采用timestamp类型并设置自动更新机制,确保订单状态变更时间准确记录
- 索引策略:主键id自增设计配合InnoDB引擎的聚簇索引,保证订单数据的物理存储顺序与逻辑顺序一致
商品表关系设计
商品相关的表结构设计展现了良好的范式规范和扩展性:
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL COMMENT '名称',
`cover` varchar(255) DEFAULT NULL COMMENT '封面',
`price` float DEFAULT NULL COMMENT '价格',
`intro` varchar(255) DEFAULT NULL COMMENT '介绍',
`stock` int(11) DEFAULT NULL COMMENT '库存',
`category_id` int(11) DEFAULT NULL COMMENT '分类',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品表'
CREATE TABLE `product_show` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) DEFAULT NULL COMMENT '商品ID',
`showtext` varchar(255) DEFAULT NULL COMMENT '展示图片',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品展示表'
这种分离设计实现了商品基本信息与展示内容的解耦,支持一个商品对应多个展示图片的需求,符合第三范式要求。

核心功能实现
用户购物车管理
购物车功能通过shopcart表实现用户商品的临时存储,关键代码如下:
// 购物车实体类
@Entity
@Table(name="shopcart")
public class ShopCart {
@Id
@GeneratedValue
private int id;
private int amount;
@ManyToOne
@JoinColumn(name="product_id")
private Product product;
@ManyToOne
@JoinColumn(name="user_id")
private User user;
// getter和setter方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public int getAmount() { return amount; }
public void setAmount(int amount) { this.amount = amount; }
public Product getProduct() { return product; }
public void setProduct(Product product) { this.product = product; }
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
}
// 购物车Service实现
@Service
@Transactional
public class ShopCartService {
@Autowired
private ShopCartDAO shopCartDAO;
public void addToCart(Product product, User user, int amount) {
ShopCart existingItem = shopCartDAO.findByUserAndProduct(user, product);
if (existingItem != null) {
existingItem.setAmount(existingItem.getAmount() + amount);
shopCartDAO.update(existingItem);
} else {
ShopCart newItem = new ShopCart();
newItem.setProduct(product);
newItem.setUser(user);
newItem.setAmount(amount);
shopCartDAO.save(newItem);
}
}
public List<ShopCart> getCartItems(User user) {
return shopCartDAO.findByUser(user);
}
}

订单处理流程
订单生成和处理是电商平台的核心业务,实现代码展示了Struts2 Action与Spring Service的整合:
// 订单Action控制器
@Controller
@Scope("prototype")
public class IndentAction extends ActionSupport {
private Indent indent;
private List<ShopCart> cartItems;
@Autowired
private IndentService indentService;
@Autowired
private ShopCartService shopCartService;
// 生成订单方法
public String createIndent() {
try {
// 获取当前用户购物车商品
User user = (User) ActionContext.getContext().getSession().get("currentUser");
cartItems = shopCartService.getCartItems(user);
// 计算总价和商品数量
float total = 0;
int amount = 0;
for (ShopCart item : cartItems) {
total += item.getProduct().getPrice() * item.getAmount();
amount += item.getAmount();
}
// 设置订单信息
indent.setTotal(total);
indent.setAmount(amount);
indent.setUser(user);
indent.setStatus(1); // 未付款状态
indent.setSystime(new Date());
// 保存订单
indentService.createIndent(indent, cartItems);
// 清空购物车
shopCartService.clearCart(user);
return SUCCESS;
} catch (Exception e) {
addActionError("订单生成失败: " + e.getMessage());
return ERROR;
}
}
// getter和setter方法
public Indent getIndent() { return indent; }
public void setIndent(Indent indent) { this.indent = indent; }
}
// 订单Service业务逻辑
@Service
@Transactional
public class IndentService {
@Autowired
private IndentDAO indentDAO;
@Autowired
private ProductDAO productDAO;
public void createIndent(Indent indent, List<ShopCart> cartItems) {
// 保存订单主信息
indentDAO.save(indent);
// 保存订单明细并更新库存
for (ShopCart item : cartItems) {
IndentDetail detail = new IndentDetail();
detail.setIndent(indent);
detail.setProduct(item.getProduct());
detail.setAmount(item.getAmount());
detail.setPrice(item.getProduct().getPrice());
// 更新商品库存
Product product = item.getProduct();
product.setStock(product.getStock() - item.getAmount());
productDAO.update(product);
}
}
}

商品展示与详情管理
商品详情页通过多表关联查询实现丰富的内容展示:
// 商品详情Action
@Controller
@Scope("prototype")
public class ProductAction extends ActionSupport {
private int productId;
private Product product;
private List<ProductShow> showImages;
@Autowired
private ProductService productService;
public String detail() {
product = productService.getProductById(productId);
showImages = productService.getProductShowImages(productId);
return SUCCESS;
}
// 商品列表分页查询
public String list() {
Map<String, Object> params = new HashMap<>();
if (categoryId > 0) {
params.put("categoryId", categoryId);
}
Page<Product> page = productService.getProductsByPage(currentPage, pageSize, params);
// 设置分页数据到值栈
getValueStack().set("productPage", page);
return SUCCESS;
}
}
// 商品Service实现
@Service
@Transactional
public class ProductService {
@Autowired
private ProductDAO productDAO;
@Autowired
private ProductShowDAO productShowDAO;
public Product getProductById(int id) {
return productDAO.findById(id);
}
public List<ProductShow> getProductShowImages(int productId) {
String hql = "FROM ProductShow WHERE product_id = :productId ORDER BY id";
return productShowDAO.find(hql, Map.of("productId", productId));
}
public Page<Product> getProductsByPage(int page, int size, Map<String, Object> params) {
StringBuilder hql = new StringBuilder("FROM Product WHERE 1=1");
Map<String, Object> queryParams = new HashMap<>();
if (params.containsKey("categoryId")) {
hql.append(" AND category_id = :categoryId");
queryParams.put("categoryId", params.get("categoryId"));
}
hql.append(" ORDER BY id DESC");
return productDAO.findPage(hql.toString(), page, size, queryParams);
}
}

管理员权限控制
后台管理系统通过Struts2拦截器实现权限验证:
// 管理员权限拦截器
public class AdminAuthInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext context = invocation.getInvocationContext();
HttpSession session = (HttpSession) context.get(ServletActionContext.HTTP_SESSION);
Admin admin = (Admin) session.getAttribute("admin");
if (admin == null) {
// 未登录,跳转到登录页
return "login";
}
// 检查权限
String actionName = invocation.getProxy().getActionName();
if (!hasPermission(admin, actionName)) {
throw new Exception("权限不足");
}
return invocation.invoke();
}
private boolean hasPermission(Admin admin, String actionName) {
// 根据管理员角色和请求的action进行权限验证
// 实现具体的权限逻辑
return true;
}
}
// Struts2配置
<struts>
<package name="admin" namespace="/admin" extends="struts-default">
<interceptors>
<interceptor name="auth" class="com.interceptor.AdminAuthInterceptor"/>
<interceptor-stack name="adminStack">
<interceptor-ref name="auth"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="adminStack"/>
<action name="product_*" class="productAction" method="{1}">
<result name="success">/admin/product_list.jsp</result>
<result name="login">/admin/login.jsp</result>
</action>
</package>
</struts>

实体模型设计
系统采用JPA注解方式进行实体关系映射,确保对象模型与数据库表结构的精确对应:
// 订单实体类
@Entity
@Table(name = "indent")
public class Indent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Float total;
private Integer amount;
@Column(name = "status")
private Byte status;
@Column(name = "paytype")
private Byte paytype;
@Temporal(TemporalType.TIMESTAMP)
private Date systime;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
private String name;
private String idcardno;
@OneToMany(mappedBy = "indent", cascade = CascadeType.ALL)
private Set<IndentDetail> details = new HashSet<>();
// 枚举类型定义订单状态
public static class Status {
public static final byte UNPAID = 1;
public static final byte PAID = 2;
public static final byte SHIPPED = 3;
public static final byte COMPLETED = 4;
}
// getter和setter方法
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
// 其他getter/setter方法...
}
// Spring配置整合
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = "com.service")
public class AppConfig {
@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setPackagesToScan("com.entity");
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
hibernateProperties.setProperty("hibernate.format_sql", "true");
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update");
sessionFactory.setHibernateProperties(hibernateProperties);
return sessionFactory;
}
@Bean
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory);
return transactionManager;
}
}
功能展望与优化
基于当前系统架构,以下优化方向可进一步提升平台性能和用户体验:
1. 引入Redis缓存层
// 商品信息缓存示例
@Service
public class ProductCacheService {
@Autowired
private RedisTemplate<String, Product> redisTemplate;
private static final String PRODUCT_KEY_PREFIX = "product:";
private static final long CACHE_EXPIRE = 3600; // 1小时
public Product getProductById(int id) {
String key = PRODUCT_KEY_PREFIX + id;
Product product = redisTemplate.opsForValue().get(key);
if (product == null) {
product = productDAO.findById(id);
if (product != null) {
redisTemplate.opsForValue().set(key, product, CACHE_EXPIRE, TimeUnit.SECONDS);
}
}
return product;
}
}
2. 微服务架构改造
将单体应用拆分为商品服务、订单服务、用户服务等独立微服务,通过Spring Cloud实现服务治理:
# 商品服务配置
spring:
application:
name: product-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
# API网关路由配置
spring:
cloud:
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
3. Elasticsearch搜索集成
实现商品全文检索和高级搜索功能:
// 商品搜索服务
@Service
public class ProductSearchService {
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
public Page<Product> searchProducts(String keyword, int page, int size) {
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
queryBuilder.withQuery(QueryBuilders.multiMatchQuery(keyword, "name", "intro", "category.name"))
.withPageable(PageRequest.of(page, size))
.withSort(SortBuilders.scoreSort());
SearchHits<Product> searchHits = elasticsearchTemplate.search(queryBuilder.build(), Product.class);
return new PageImpl<>(searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList()),
PageRequest.of(page, size), searchHits.getTotalHits());
}
}
4. 消息队列异步处理
使用RabbitMQ处理订单创建、库存更新等异步操作:
// 订单消息生产者
@Component
public class OrderMessageProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendOrderCreatedMessage(Indent indent) {
OrderMessage message = new OrderMessage(indent.getId(), indent.getTotal(), indent.getUser().getId());
rabbitTemplate