在电子产品消费市场日益成熟的背景下,专业化的B2C电商平台成为连接品牌商与终端用户的重要桥梁。显示器作为办公、设计和娱乐场景的核心硬件设备,其线上销售渠道需要解决产品参数复杂、用户决策成本高等独特挑战。这一平台采用SpringBoot框架构建,实现了从商品展示到交易完成的完整电商功能闭环。
系统架构与技术栈设计
该平台采用经典的三层架构模式,基于SpringBoot 2.x版本进行开发。技术栈选择体现了现代Java Web应用的最佳实践:
后端技术栈:
- 核心框架:SpringBoot 2.x提供自动配置和起步依赖,简化了传统SSM框架的复杂配置
- 数据持久层:Spring Data JPA实现对象关系映射,配合Hibernate作为JPA提供商
- 模板引擎:Thymeleaf 3.x负责服务端页面渲染,支持自然的HTML模板语法
- 依赖管理:Maven统一管理项目依赖,确保构建过程的可重复性
前端技术栈:
- UI框架:Bootstrap 4.x提供响应式布局和组件化界面元素
- 客户端脚本:原生JavaScript处理动态交互,jQuery简化DOM操作
- 样式设计:CSS3实现现代化视觉效果,确保跨浏览器兼容性
数据库与服务器:
- 数据存储:MySQL 5.7+作为关系型数据库,采用InnoDB存储引擎
- 应用服务器:内嵌Tomcat服务器,支持快速部署和独立运行
项目的配置文件体现了生产环境的最佳实践,以下为关键配置示例:
server:
servlet:
session:
timeout: PT2H
context-path: /boot_xsqshop
spring:
profiles:
active: pro
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mybatis:
mapper-locations: classpath:mappers/*.xml,classpath:mappers/customize/*.xml
pagehelper:
helper-dialect: mysql
reasonable: true
数据库架构深度解析
数据库设计体现了电商系统的典型特征,在表结构设计中充分考虑了数据一致性、查询性能和业务扩展性。
商品信息表的核心设计
display表作为系统的核心数据载体,其设计体现了专业电商平台对商品信息管理的严谨性:
CREATE TABLE `display` (
`display_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '书籍编号',
`category_code` varchar(20) DEFAULT NULL COMMENT '书籍分类代码',
`display_name` varchar(50) NOT NULL DEFAULT '' COMMENT '书籍名称',
`isbn` varchar(50) NOT NULL DEFAULT '' COMMENT 'ISBN',
`author` varchar(50) NOT NULL DEFAULT '' COMMENT '作者',
`press` varchar(50) NOT NULL DEFAULT '' COMMENT '出版社',
`pub_date` date NOT NULL COMMENT '出版日期',
`image` varchar(255) NOT NULL DEFAULT '' COMMENT '书籍图片',
`description` varchar(500) NOT NULL DEFAULT '' COMMENT '书籍描述',
`price` decimal(10,2) unsigned NOT NULL DEFAULT 0.00 COMMENT '书籍单价',
`stock` int(10) unsigned NOT NULL COMMENT '书籍库存',
`create_time` datetime NOT NULL DEFAULT current_timestamp() COMMENT '上架时间',
PRIMARY KEY (`display_id`) USING BTREE,
UNIQUE KEY `display_id` (`display_id`) USING BTREE,
KEY `category_code` (`category_code`) USING BTREE,
CONSTRAINT `display_ibfk_1` FOREIGN KEY (`category_code`) REFERENCES `category` (`category_code`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1044 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC
设计亮点分析:
- 字段类型优化:价格字段使用
decimal(10,2)确保金融计算的精确性,库存使用无符号整型防止负数出现 - 索引策略:主键索引采用自增ID,分类代码建立普通索引加速分类查询,同时设置外键约束保证数据完整性
- 存储优化:使用
ROW_FORMAT=DYNAMIC适应可变长度行的存储,提高存储效率 - 字符集统一:UTF8编码支持多语言产品描述,满足国际化潜在需求
订单系统的关系设计
订单系统采用主从表结构,orders表记录订单概要信息,order_item表存储订单明细:
CREATE TABLE `orders` (
`order_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '订单ID',
`user_id` int(10) unsigned NOT NULL COMMENT '用户ID',
`consignee_name` varchar(10) NOT NULL DEFAULT '' COMMENT '收货人姓名',
`address` varchar(255) NOT NULL DEFAULT '' COMMENT '收货地址',
`zip` varchar(50) NOT NULL DEFAULT '' COMMENT '邮政编号',
`phone_number` varchar(50) NOT NULL DEFAULT '' COMMENT '联系方式',
`status` bit(1) NOT NULL DEFAULT b'0' COMMENT '审核状态',
`create_time` datetime NOT NULL DEFAULT current_timestamp() COMMENT '创建时间',
PRIMARY KEY (`order_id`) USING BTREE,
KEY `user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC COMMENT='订单表'
CREATE TABLE `order_item` (
`order_item_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '订单子项ID',
`order_id` int(10) unsigned NOT NULL COMMENT '订单ID',
`display_id` int(10) unsigned NOT NULL COMMENT '书籍ID',
`price` decimal(10,2) NOT NULL COMMENT '价格',
`quantity` int(10) unsigned NOT NULL COMMENT '购买数量',
PRIMARY KEY (`order_item_id`) USING BTREE,
KEY `order_id` (`order_id`) USING BTREE,
KEY `display_id` (`display_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=DYNAMIC COMMENT='订单子项表'
关系模型优势:
- 数据一致性:通过外键关联确保订单项与主订单的对应关系
- 查询性能:订单ID和商品ID建立索引,优化关联查询效率
- 扩展性:分离的设计支持一个订单包含多个商品,符合电商业务场景
- 状态管理:使用bit类型存储审核状态,节省存储空间

核心业务功能实现
后台管理系统路由控制
后台管理模块采用清晰的URL映射策略,通过专门的控制器处理管理页面的路由跳转:
package edu.hut.displayshop.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/admin")
public class AdminRouterController {
@GetMapping("/user_manage")
public String toUserManage(){
return "admin/user";
}
@GetMapping({"/","/display_manage"})
public String toDisplayManage(){
return "admin/displays";
}
@GetMapping("/category_manage")
public String toCategoryManage(){
return "admin/category";
}
@GetMapping("/order_manage")
public String toOrderManage(){
return "admin/order";
}
@GetMapping("/add_display")
public String AddDisplay(){
return "admin/add_display";
}
@GetMapping("/login")
public String toAdminLogin(){
return "admin/login";
}
}
这种设计实现了前后端分离的路由管理,后端控制器专注于页面跳转逻辑,前端模板负责具体页面渲染。
购物车业务逻辑实现
购物车模块采用经典的session与数据库结合方案,确保用户数据的持久化和临时存储的平衡:
@Service
public class ShoppingCartService {
@Autowired
private ShoppingCartRepository cartRepository;
@Autowired
private DisplayRepository displayRepository;
public void addToCart(Integer userId, Integer displayId, Integer quantity) {
// 检查商品库存
Display display = displayRepository.findById(displayId)
.orElseThrow(() -> new RuntimeException("商品不存在"));
if (display.getStock() < quantity) {
throw new RuntimeException("库存不足");
}
// 查询用户购物车中是否已存在该商品
ShoppingCart cartItem = cartRepository.findByUserIdAndDisplayId(userId, displayId);
if (cartItem != null) {
// 更新数量
cartItem.setQuantity(cartItem.getQuantity() + quantity);
} else {
// 新增购物车项
cartItem = new ShoppingCart();
cartItem.setUserId(userId);
cartItem.setDisplayId(displayId);
cartItem.setPrice(display.getPrice());
cartItem.setQuantity(quantity);
}
cartRepository.save(cartItem);
}
public List<ShoppingCartVO> getCartItems(Integer userId) {
return cartRepository.findCartDetailsByUserId(userId);
}
}

订单处理流程设计
订单生成过程涉及库存校验、价格计算、状态流转等多个业务环节:
@Service
@Transactional
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderItemRepository orderItemRepository;
@Autowired
private DisplayRepository displayRepository;
@Autowired
private ShoppingCartRepository cartRepository;
public Order createOrder(OrderDTO orderDTO) {
// 验证收货信息
validateOrderInfo(orderDTO);
// 创建主订单
Order order = new Order();
BeanUtils.copyProperties(orderDTO, order);
order.setCreateTime(new Date());
order.setStatus(false); // 初始状态为待审核
Order savedOrder = orderRepository.save(order);
// 处理订单项
List<OrderItem> orderItems = new ArrayList<>();
BigDecimal totalAmount = BigDecimal.ZERO;
for (CartItemDTO cartItem : orderDTO.getCartItems()) {
// 库存检查
Display display = displayRepository.findById(cartItem.getDisplayId())
.orElseThrow(() -> new RuntimeException("商品不存在"));
if (display.getStock() < cartItem.getQuantity()) {
throw new RuntimeException("商品库存不足: " + display.getDisplayName());
}
// 扣减库存
display.setStock(display.getStock() - cartItem.getQuantity());
displayRepository.save(display);
// 创建订单项
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(savedOrder.getOrderId());
orderItem.setDisplayId(cartItem.getDisplayId());
orderItem.setPrice(display.getPrice());
orderItem.setQuantity(cartItem.getQuantity());
orderItems.add(orderItem);
// 计算总金额
totalAmount = totalAmount.add(
display.getPrice().multiply(new BigDecimal(cartItem.getQuantity())));
// 清除购物车
cartRepository.deleteByUserIdAndDisplayId(orderDTO.getUserId(), cartItem.getDisplayId());
}
// 批量保存订单项
orderItemRepository.saveAll(orderItems);
return savedOrder;
}
}
商品搜索与分页实现
商品列表查询采用MyBatis PageHelper实现高效分页,支持多条件组合搜索:
@Controller
@RequestMapping("/display")
public class DisplayController {
@Autowired
private DisplayService displayService;
@GetMapping("/list")
public String listDisplays(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "12") Integer pageSize,
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String categoryCode,
Model model) {
// 设置分页参数
PageHelper.startPage(pageNum, pageSize);
// 构建查询条件
DisplayQueryDTO queryDTO = new DisplayQueryDTO();
queryDTO.setKeyword(keyword);
queryDTO.setCategoryCode(categoryCode);
// 执行查询
List<Display> displays = displayService.searchDisplays(queryDTO);
PageInfo<Display> pageInfo = new PageInfo<>(displays);
model.addAttribute("displays", displays);
model.addAttribute("pageInfo", pageInfo);
model.addAttribute("queryDTO", queryDTO);
return "display/list";
}
}
对应的MyBatis映射文件实现了灵活的查询逻辑:
<!-- mappers/DisplayMapper.xml -->
<select id="selectByCondition" parameterType="DisplayQueryDTO" resultType="Display">
SELECT * FROM display
<where>
<if test="keyword != null and keyword != ''">
AND (display_name LIKE CONCAT('%', #{keyword}, '%')
OR author LIKE CONCAT('%', #{keyword}, '%')
OR description LIKE CONCAT('%', #{keyword}, '%'))
</if>
<if test="categoryCode != null and categoryCode != ''">
AND category_code = #{categoryCode}
</if>
AND stock > 0
</where>
ORDER BY create_time DESC
</select>

实体模型设计与业务对象映射
用户实体建模
用户实体采用标准的JPA注解进行对象关系映射,确保数据访问层的简洁性:
@Entity
@Table(name = "user_info")
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Integer userId;
@Column(name = "user_name", nullable = false, length = 50)
private String username;
@Column(name = "password", nullable = false, length = 80)
private String password;
@Column(name = "email", length = 80)
private String email;
@Column(name = "avatar")
private String avatar;
@Column(name = "join_time")
@Temporal(TemporalType.TIMESTAMP)
private Date joinTime;
// Spring Security相关方法实现
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
// getter和setter方法
}
商品实体与DTO设计
商品实体采用数据传输对象模式实现前后端数据交换的隔离:
@Entity
@Table(name = "display")
public class Display {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "display_id")
private Integer displayId;
@Column(name = "display_name", length = 50)
private String displayName;
@Column(name = "price", precision = 10, scale = 2)
private BigDecimal price;
@Column(name = "stock")
private Integer stock;
@Column(name = "image")
private String image;
@Column(name = "description", length = 500)
private String description;
@ManyToOne
@JoinColumn(name = "category_code")
private Category category;
// 其他字段和方法...
}
@Data
public class DisplayDTO {
private Integer displayId;
private String displayName;
private BigDecimal price;
private Integer stock;
private String imageUrl;
private String description;
private String categoryName;
// 转换方法
public static DisplayDTO fromEntity(Display display) {
DisplayDTO dto = new DisplayDTO();
BeanUtils.copyProperties(display, dto);
if (display.getCategory() != null) {
dto.setCategoryName(display.getCategory().getCategoryName());
}
return dto;
}
}

系统优化与功能扩展展望
基于当前架构,平台在以下方面具有显著的优化和扩展空间:
1. 缓存策略优化
引入Redis作为分布式缓存,显著提升商品列表、用户会话等高频访问数据的响应速度:
@Service
public class DisplayServiceWithCache {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String DISPLAY_CACHE_KEY = "display:";
private static final long CACHE_EXPIRE_HOURS = 24;
public Display getDisplayById(Integer displayId) {
String cacheKey = DISPLAY_CACHE_KEY + displayId;
Display display = (Display) redisTemplate.opsForValue().get(cacheKey);
if (display == null) {
display = displayRepository.findById(displayId).orElse(null);
if (display != null) {
redisTemplate.opsForValue().set(cacheKey, display,
CACHE_EXPIRE_HOURS, TimeUnit.HOURS);
}
}
return display;
}
}
2. 异步处理与消息队列
使用RabbitMQ或Kafka处理订单生成、库存更新等耗时操作,提升系统吞吐量:
@Component
public class OrderMessageProducer {
@Autowired
private AmqpTemplate rabbitTemplate;
public void sendOrderCreateMessage(OrderDTO orderDTO) {
rabbitTemplate.convertAndSend("order.exchange", "order.create", orderDTO);
}
}
@Component
@RabbitListener(queues = "order.queue")
public class OrderMessageConsumer {
@RabbitHandler
public void processOrderCreate(OrderDTO orderDTO) {
// 异步处理订单创建逻辑
orderService.createOrderAsync(orderDTO);
}
}
3. 微服务架构改造
将单体应用拆分为商品服务、订单服务、用户服务等独立微服务,提升系统可维护性和扩展性:
# 商品服务配置示例
spring:
application:
name: display-service
cloud:
nacos:
discovery:
server-addr: localhost: