随着互联网技术的快速发展,电子商务模式已经从传统的B2C向更加多元化的B2B2C模式演进。零食行业作为快消品的重要组成部分,面临着渠道分散、信息不对称、小型商家线上运营能力不足等挑战。多商家零食集市平台应运而生,它通过集中化的技术架构,为零食供应商提供统一的线上销售渠道,同时为消费者打造一站式购物体验。
本平台采用经典的J2EE MVC架构,前端使用JSP结合JSTL标签库进行页面渲染,业务逻辑层由Servlet控制器统一处理,数据持久层基于JDBC和DAO模式实现。这种分层架构确保了系统的高内聚低耦合,便于后续功能扩展和维护。
系统架构与技术栈
平台采用典型的三层架构设计,每一层都有明确的职责分工:
表示层:使用JSP技术结合JSTL标签库和EL表达式,实现动态页面渲染。通过严格的MVC分离,确保业务逻辑不侵入视图层。
// 典型的Servlet控制器示例
@WebServlet("/product/*")
public class ProductServlet extends HttpServlet {
private ProductDAO productDAO;
@Override
public void init() throws ServletException {
productDAO = new ProductDAOImpl();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getPathInfo();
switch (action) {
case "/list":
listProducts(request, response);
break;
case "/detail":
showProductDetail(request, response);
break;
default:
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
private void listProducts(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String categoryId = request.getParameter("categoryId");
List<Product> products = productDAO.findByCategory(categoryId);
request.setAttribute("products", products);
request.getRequestDispatcher("/WEB-INF/views/product/list.jsp").forward(request, response);
}
}
业务逻辑层:Servlet作为控制器,负责请求路由、参数验证、业务处理和数据传递。每个功能模块都有对应的Servlet处理相关请求。
数据访问层:采用DAO设计模式,通过接口与实现类分离的方式,提供统一的数据访问接口。
// 商品数据访问接口
public interface ProductDAO {
Product findById(int id);
List<Product> findByCategory(String categoryId);
List<Product> findByShop(String shopId);
void save(Product product);
void update(Product product);
void delete(int id);
}
// JDBC实现类
public class ProductDAOImpl implements ProductDAO {
private Connection getConnection() throws SQLException {
return DataSourceManager.getConnection();
}
@Override
public Product findById(int id) {
String sql = "SELECT * FROM pros WHERE id = ?";
try (Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, id);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
return mapResultSetToProduct(rs);
}
} catch (SQLException e) {
throw new RuntimeException("数据库查询失败", e);
}
return null;
}
private Product mapResultSetToProduct(ResultSet rs) throws SQLException {
Product product = new Product();
product.setId(rs.getInt("id"));
product.setProshop(rs.getString("proshop"));
product.setProname(rs.getString("proname"));
product.setPrice(rs.getString("price"));
product.setDiscount(rs.getString("discount"));
product.setFilename(rs.getString("filename"));
product.setBei(rs.getString("bei"));
product.setExtbei(rs.getString("extbei"));
product.setStatus(rs.getString("status"));
product.setSavetime(rs.getString("savetime"));
product.setCjnum(rs.getString("cjnum"));
return product;
}
}
数据库设计亮点分析
商品表(pros)设计优化
商品表作为核心业务表,其设计直接影响到系统性能和扩展性:
CREATE TABLE `pros` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`proshop` varchar(255) DEFAULT NULL COMMENT '商品店铺',
`proname` varchar(255) DEFAULT NULL COMMENT '商品名称',
`price` varchar(255) DEFAULT NULL COMMENT '商品价格',
`discount` varchar(255) DEFAULT NULL COMMENT '折扣',
`filename` varchar(255) DEFAULT NULL COMMENT '文件名',
`bei` varchar(255) DEFAULT NULL COMMENT '备注',
`extbei` varchar(255) DEFAULT NULL COMMENT '扩展备注',
`status` varchar(255) DEFAULT NULL COMMENT '状态',
`savetime` varchar(255) DEFAULT NULL COMMENT '保存时间',
`cjnum` varchar(255) DEFAULT NULL COMMENT '成交数量',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品表'
设计亮点分析:
- 字段类型优化:价格字段采用varchar类型存储,虽然在实际应用中建议使用DECIMAL类型确保精度,但varchar设计便于处理复杂的价格格式(如区间价格、促销价等)
- 扩展性设计:通过
bei和extbei两个备注字段,为商品信息提供了良好的扩展性,可以存储各种自定义属性 - 状态管理:
status字段支持商品上下架、审核等状态流转,cjnum字段记录成交数量便于热门商品推荐
商品类别表(splb)层级设计
类别表采用经典的父子层级结构,支持无限级分类:
CREATE TABLE `splb` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` varchar(255) DEFAULT NULL COMMENT '父级ID',
`lbname` varchar(255) DEFAULT NULL COMMENT '类别名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品类别表'
层级查询优化方案:
-- 递归查询所有子类别(MySQL 8.0+)
WITH RECURSIVE category_tree AS (
SELECT id, pid, lbname, 1 as level
FROM splb
WHERE pid = '0'
UNION ALL
SELECT c.id, c.pid, c.lbname, ct.level + 1
FROM splb c
INNER JOIN category_tree ct ON c.pid = ct.id
)
SELECT * FROM category_tree ORDER BY level, id;
-- 传统方法:应用层递归处理
public List<Category> buildCategoryTree(List<Category> allCategories) {
Map<String, Category> categoryMap = new HashMap<>();
List<Category> rootCategories = new ArrayList<>();
// 建立ID到对象的映射
for (Category category : allCategories) {
categoryMap.put(String.valueOf(category.getId()), category);
}
// 构建树形结构
for (Category category : allCategories) {
if ("0".equals(category.getPid())) {
rootCategories.add(category);
} else {
Category parent = categoryMap.get(category.getPid());
if (parent != null) {
parent.addChild(category);
}
}
}
return rootCategories;
}
订单表(prosorder)业务设计
订单表设计充分考虑了电商业务的复杂性:
CREATE TABLE `prosorder` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uname` varchar(255) DEFAULT NULL COMMENT '用户名',
`savetime` varchar(255) DEFAULT NULL COMMENT '下单时间',
`prosinfo` varchar(255) DEFAULT NULL COMMENT '商品信息',
`toshop` varchar(255) DEFAULT NULL COMMENT '收货地址',
`status` varchar(255) DEFAULT NULL COMMENT '订单状态',
`fkstatus` varchar(255) DEFAULT NULL COMMENT '付款状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='商品订单表'
状态机设计实现:
// 订单状态机管理
public class OrderStatusManager {
private static final Map<String, List<String>> STATUS_FLOW = new HashMap<>();
static {
// 定义订单状态流转规则
STATUS_FLOW.put("待付款", Arrays.asList("已付款", "已取消"));
STATUS_FLOW.put("已付款", Arrays.asList("已发货", "退款中"));
STATUS_FLOW.put("已发货", Arrays.asList("已完成", "退货中"));
STATUS_FLOW.put("已完成", Collections.emptyList());
STATUS_FLOW.put("已取消", Collections.emptyList());
}
public static boolean canChangeStatus(String currentStatus, String targetStatus) {
return STATUS_FLOW.getOrDefault(currentStatus, Collections.emptyList())
.contains(targetStatus);
}
}
核心功能实现详解
多商家商品展示系统
平台支持多个商家独立管理商品,前端通过统一的商品展示组件渲染不同商家的商品:

商品查询服务实现:
// 商品搜索和筛选服务
public class ProductSearchService {
private ProductDAO productDAO;
public ProductSearchService(ProductDAO productDAO) {
this.productDAO = productDAO;
}
public SearchResult searchProducts(ProductSearchCriteria criteria) {
StringBuilder sql = new StringBuilder("SELECT * FROM pros WHERE 1=1");
List<Object> params = new ArrayList<>();
if (StringUtils.isNotBlank(criteria.getKeyword())) {
sql.append(" AND (proname LIKE ? OR bei LIKE ?)");
params.add("%" + criteria.getKeyword() + "%");
params.add("%" + criteria.getKeyword() + "%");
}
if (StringUtils.isNotBlank(criteria.getShopId())) {
sql.append(" AND proshop = ?");
params.add(criteria.getShopId());
}
if (StringUtils.isNotBlank(criteria.getCategoryId())) {
sql.append(" AND id IN (SELECT product_id FROM product_category WHERE category_id = ?)");
params.add(criteria.getCategoryId());
}
// 分页处理
sql.append(" ORDER BY cjnum DESC LIMIT ? OFFSET ?");
params.add(criteria.getPageSize());
params.add((criteria.getPageNumber() - 1) * criteria.getPageSize());
return executeSearch(sql.toString(), params.toArray());
}
}
购物车与订单管理
购物车功能采用Session存储临时数据,确保用户体验的流畅性:

购物车业务逻辑:
// 购物车管理服务
public class ShoppingCartService {
private Map<String, CartItem> cartItems = new HashMap<>();
public void addItem(Product product, int quantity) {
String key = generateItemKey(product);
CartItem existingItem = cartItems.get(key);
if (existingItem != null) {
existingItem.setQuantity(existingItem.getQuantity() + quantity);
} else {
CartItem newItem = new CartItem(product, quantity);
cartItems.put(key, newItem);
}
}
public void removeItem(String productId) {
cartItems.remove(productId);
}
public BigDecimal calculateTotal() {
return cartItems.values().stream()
.map(item -> item.getProduct().getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
public Order createOrder(String username, String shippingAddress) {
Order order = new Order();
order.setUname(username);
order.setToshop(shippingAddress);
order.setSavetime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
order.setStatus("待付款");
order.setFkstatus("未付款");
String productsInfo = cartItems.values().stream()
.map(item -> item.getProduct().getProname() + "×" + item.getQuantity())
.collect(Collectors.joining(","));
order.setProsinfo(productsInfo);
return order;
}
}
订单处理流程
订单处理采用状态模式管理订单生命周期:

订单状态管理:
// 订单状态处理上下文
public class OrderProcessor {
private OrderState currentState;
private Order order;
public OrderProcessor(Order order) {
this.order = order;
this.currentState = OrderStateFactory.createState(order.getStatus());
}
public void pay() {
currentState.pay(this);
}
public void ship() {
currentState.ship(this);
}
public void complete() {
currentState.complete(this);
}
public void cancel() {
currentState.cancel(this);
}
public void setState(OrderState state) {
this.currentState = state;
// 更新数据库中的订单状态
updateOrderStatus(state.getStatus());
}
}
// 订单状态接口
public interface OrderState {
void pay(OrderProcessor processor);
void ship(OrderProcessor processor);
void complete(OrderProcessor processor);
void cancel(OrderProcessor processor);
String getStatus();
}
// 待付款状态实现
public class PendingPaymentState implements OrderState {
@Override
public void pay(OrderProcessor processor) {
// 处理支付逻辑
processor.setState(new PaidState());
// 记录支付日志
logPayment(processor.getOrder());
}
@Override
public void cancel(OrderProcessor processor) {
processor.setState(new CancelledState());
// 释放库存
releaseInventory(processor.getOrder());
}
}
新闻资讯系统
平台内置新闻发布系统,支持管理员发布平台公告和行业资讯:

新闻管理服务:
// 新闻业务逻辑处理
public class NewsService {
private NewsDAO newsDAO;
public List<News> getLatestNews(int limit) {
return newsDAO.findLatest(limit);
}
public void publishNews(News news) {
news.setSavetime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
newsDAO.save(news);
// 可选:发送新消息通知
notifySubscribers(news);
}
public Page<News> getNewsByType(String infoType, int page, int size) {
return newsDAO.findByType(infoType, page, size);
}
}
用户留言反馈系统
留言系统支持用户与平台互动,管理员可以及时回复用户反馈:

留言处理Servlet:
@WebServlet("/message/*")
public class MessageServlet extends HttpServlet {
private MessageDAO messageDAO;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getPathInfo();
switch (action) {
case "/add":
addMessage(request, response);
break;
case "/reply":
replyMessage(request, response);
break;
default:
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
private void addMessage(HttpServletRequest request, HttpServletResponse response)
throws IOException {
String saver = request.getParameter("saver");
String content = request.getParameter("content");
Message message = new Message();
message.setSaver(saver);
message.setContent(content);
message.setSavetime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
messageDAO.save(message);
response.sendRedirect(request.getContextPath() + "/message/success.jsp");
}
}
实体模型设计
系统采用面向对象的设计思想,构建了完整的实体模型体系:
// 商品实体类
public class Product {
private Integer id;
private String proshop;
private String proname;
private String price;
private String discount;
private String filename;
private String bei;
private String extbei;
private String status;
private String savetime;
private String cjnum;
// 构造函数、getter、setter方法
public Product() {}
public BigDecimal getFinalPrice() {
BigDecimal originalPrice = new BigDecimal(price);
if (discount != null && !discount.isEmpty()) {
BigDecimal discountRate = new BigDecimal(discount);
return originalPrice.multiply(discountRate);
}
return originalPrice;
}
public boolean isAvailable() {
return "上架".equals(status);
}
}
// 订单实体类
public class Order {
private Integer id;
private String uname;
private String savetime;
private String prosinfo;
private String toshop;
private String status;
private String fkstatus;
public List<OrderItem> parseItems() {
// 解析商品信息字符串为订单项列表
return Arrays.stream(prosinfo.split(","))
.map(item -> {
String[] parts = item.split("×");
return new OrderItem(parts[0], Integer.parseInt(parts[1]));
})
.collect(Collectors.toList());
}
}
功能展望与优化方向
基于当前架构,平台有以下优化和发展方向:
1. 引入Redis缓存层
现状分析:商品信息、类别信息等热点数据频繁查询,直接访问数据库压力较大。
优化方案:
// 缓存增强的商品服务
@Service
public class CachedProductService {
private final ProductDAO productDAO;
private final RedisTemplate<String, Object> redisTemplate;
private static final String PRODUCT_KEY_PREFIX = "product:";
private static final String CATEGORY_PRODUCTS_KEY_P