基于JSP+Servlet的在线鲜花商城系统 - 源码深度解析

JavaJavaScriptHTMLCSSMySQLJSP+Servlet
2026-02-095 浏览

文章摘要

基于JSP+Servlet的在线鲜花商城系统是一个典型的B2C电子商务解决方案,旨在为鲜花零售商提供一个功能完整、易于维护的线上销售平台。其核心业务价值在于解决了实体花店经营地域受限、商品展示形式单一以及客户购物流程繁琐的核心痛点。系统通过集中的在线商品目录和标准化的购物流程,将选花、下单、支付环节...

在传统鲜花零售行业数字化转型的浪潮中,一个高效、稳定且易于维护的在线销售平台成为花店商家的核心竞争力。本文深入剖析一个采用经典J2EE技术栈构建的企业级鲜花电商解决方案,该系统通过模块化设计和严谨的数据库建模,实现了商品展示、购物车管理、订单处理等完整电商功能。

系统架构与技术栈

该系统严格遵循MVC设计模式,采用分层架构确保代码的可维护性和可扩展性。表现层使用JSP动态页面技术,结合JSTL标签库和EL表达式实现数据渲染,有效分离了业务逻辑与页面展示。控制层由Servlet组件担当,负责请求路由、参数验证和业务调度。数据持久层基于JDBC直接操作MySQL数据库,通过连接池技术优化数据库访问性能。

技术选型体现了经典Java Web开发的最佳实践:Servlet 3.0+规范提供异步处理能力,JSP 2.0+支持表达式语言简化页面开发,MySQL 5.7+提供事务支持和外键约束,前端采用HTML5+CSS3+JavaScript构建响应式用户界面。

数据库设计亮点分析

商品模块的精细化设计

goods表的字段设计体现了电商系统对商品管理的深度思考:

CREATE TABLE `goods` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `name` varchar(255) DEFAULT NULL COMMENT '名字',
  `cover` varchar(255) DEFAULT NULL COMMENT '主图',
  `image1` varchar(255) DEFAULT NULL COMMENT '图片1',
  `image2` varchar(255) DEFAULT NULL COMMENT '图片2',
  `price` float DEFAULT NULL COMMENT '价格',
  `intro` varchar(255) DEFAULT NULL COMMENT '介绍',
  `stock` int(11) DEFAULT NULL COMMENT '库存',
  `type_id` int(11) DEFAULT NULL COMMENT '类型ID',
  PRIMARY KEY (`id`),
  KEY `fk_type_id_idx` (`type_id`),
  CONSTRAINT `fk_type_id` FOREIGN KEY (`type_id`) REFERENCES `type` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8

设计亮点

  • 多图片存储策略coverimage1image2字段分别存储商品主图和详情图,支持多角度展示
  • 价格精度优化:采用float类型平衡存储效率与计算精度,适合电商价格计算
  • 库存实时监控stock字段确保库存数据的实时准确性,防止超卖
  • 外键约束保障数据完整性:通过type_id外键关联商品分类,维护数据一致性

订单项模型的关联设计

orderitem表的设计展现了电商系统核心业务逻辑的数据建模:

CREATE TABLE `orderitem` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `price` float DEFAULT NULL COMMENT '价格',
  `amount` int(11) DEFAULT NULL COMMENT '数量',
  `goods_id` int(11) DEFAULT NULL COMMENT '商品ID',
  `order_id` int(11) DEFAULT NULL COMMENT '订单ID',
  PRIMARY KEY (`id`),
  KEY `fk_order_id_idx` (`order_id`),
  KEY `fk_orderitem_goods_id_idx` (`goods_id`),
  CONSTRAINT `fk_order_id` FOREIGN KEY (`order_id`) REFERENCES `order` (`id`),
  CONSTRAINT `fk_orderitem_goods_id` FOREIGN KEY (`goods_id`) REFERENCES `goods` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8

优化分析

  • 历史价格追踪:独立存储price字段记录下单时的商品价格,避免后续价格变动影响已成交订单
  • 双重外键约束:同时关联订单和商品表,确保数据关系的严格一致性
  • 复合索引策略:为order_idgoods_id分别建立索引,优化订单查询和商品销售统计性能

推荐系统的灵活扩展

recommend表支持多种推荐策略的实现:

CREATE TABLE `recommend` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
  `type` tinyint(1) DEFAULT NULL COMMENT '类型',
  `goods_id` int(11) DEFAULT NULL COMMENT '商品ID',
  PRIMARY KEY (`id`),
  KEY `fk_goods_id_idx` (`goods_id`),
  CONSTRAINT `fk_goods_id` FOREIGN KEY (`goods_id`) REFERENCES `goods` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8

扩展性设计

  • 多类型推荐支持type字段用tinyint类型标识不同推荐位(如首页轮播、热销推荐、新品上市等)
  • 级联删除优化ON DELETE CASCADE确保商品删除时自动清理推荐记录,避免数据冗余

核心功能实现解析

商品展示与分类浏览

系统首页采用瀑布流布局展示商品,支持按分类筛选。商品列表Servlet负责数据处理:

@WebServlet("/goods/list")
public class GoodsListServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String typeId = request.getParameter("typeId");
        String pageStr = request.getParameter("page");
        int page = StringUtils.isNotEmpty(pageStr) ? Integer.parseInt(pageStr) : 1;
        int pageSize = 12;
        
        GoodsService goodsService = new GoodsService();
        PageInfo<Goods> pageInfo = goodsService.findGoodsByType(typeId, page, pageSize);
        
        TypeService typeService = new TypeService();
        List<Type> typeList = typeService.findAllTypes();
        
        request.setAttribute("pageInfo", pageInfo);
        request.setAttribute("typeList", typeList);
        request.setAttribute("typeId", typeId);
        
        request.getRequestDispatcher("/goods_list.jsp").forward(request, response);
    }
}

对应的JSP页面使用JSTL标签库动态渲染商品列表:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div class="goods-container">
    <c:forEach items="${pageInfo.list}" var="goods">
        <div class="goods-item">
            <img src="${ctx}/uploads/${goods.cover}" alt="${goods.name}">
            <h3>${goods.name}</h3>
            <p class="price">¥${goods.price}</p>
            <a href="${ctx}/goods/detail?id=${goods.id}" class="btn-detail">查看详情</a>
        </div>
    </c:forEach>
</div>

商品分类浏览

购物车管理实现

购物车功能基于HttpSession实现,确保用户数据的临时存储和状态保持:

public class CartServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String action = request.getParameter("action");
        String goodsId = request.getParameter("goodsId");
        String quantity = request.getParameter("quantity");
        
        HttpSession session = request.getSession();
        Cart cart = (Cart) session.getAttribute("cart");
        if (cart == null) {
            cart = new Cart();
            session.setAttribute("cart", cart);
        }
        
        GoodsService goodsService = new GoodsService();
        Goods goods = goodsService.findById(Integer.parseInt(goodsId));
        
        if ("add".equals(action)) {
            cart.addItem(goods, Integer.parseInt(quantity));
        } else if ("update".equals(action)) {
            cart.updateQuantity(goods.getId(), Integer.parseInt(quantity));
        } else if ("remove".equals(action)) {
            cart.removeItem(goods.getId());
        }
        
        response.sendRedirect(request.getContextPath() + "/cart/view");
    }
}

购物车实体类封装了核心业务逻辑:

public class Cart {
    private Map<Integer, CartItem> items = new HashMap<>();
    private double totalPrice;
    
    public void addItem(Goods goods, int quantity) {
        CartItem item = items.get(goods.getId());
        if (item != null) {
            item.setQuantity(item.getQuantity() + quantity);
        } else {
            item = new CartItem(goods, quantity);
            items.put(goods.getId(), item);
        }
        calculateTotalPrice();
    }
    
    public void removeItem(int goodsId) {
        items.remove(goodsId);
        calculateTotalPrice();
    }
    
    private void calculateTotalPrice() {
        totalPrice = 0;
        for (CartItem item : items.values()) {
            totalPrice += item.getSubtotal();
        }
    }
    
    // Getter methods...
}

添加到购物车

订单处理流程

订单创建涉及复杂的事务处理,确保数据一致性:

@WebServlet("/order/create")
public class OrderCreateServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false); // 开启事务
            
            // 1. 获取购物车数据
            HttpSession session = request.getSession();
            Cart cart = (Cart) session.getAttribute("cart");
            User user = (User) session.getAttribute("user");
            
            if (cart == null || cart.getItems().isEmpty()) {
                throw new RuntimeException("购物车为空");
            }
            
            // 2. 创建订单主记录
            Order order = new Order();
            order.setUserId(user.getId());
            order.setTotalPrice(cart.getTotalPrice());
            order.setStatus(OrderStatus.PENDING_PAYMENT);
            order.setCreateTime(new Date());
            
            OrderService orderService = new OrderService();
            int orderId = orderService.createOrder(conn, order);
            
            // 3. 创建订单明细
            OrderItemService orderItemService = new OrderItemService();
            for (CartItem cartItem : cart.getItems().values()) {
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderId(orderId);
                orderItem.setGoodsId(cartItem.getGoods().getId());
                orderItem.setPrice(cartItem.getGoods().getPrice());
                orderItem.setAmount(cartItem.getQuantity());
                
                orderItemService.addOrderItem(conn, orderItem);
                
                // 4. 更新商品库存
                GoodsService goodsService = new GoodsService();
                goodsService.updateStock(conn, cartItem.getGoods().getId(), 
                    -cartItem.getQuantity());
            }
            
            conn.commit(); // 提交事务
            cart.clear(); // 清空购物车
            
            response.sendRedirect(request.getContextPath() + "/order/success?id=" + orderId);
            
        } catch (Exception e) {
            if (conn != null) {
                try { conn.rollback(); } catch (SQLException ex) {}
            }
            request.setAttribute("error", "订单创建失败: " + e.getMessage());
            request.getRequestDispatcher("/error.jsp").forward(request, response);
        } finally {
            DBUtil.closeConnection(conn);
        }
    }
}

订单提交页面

后台商品管理

管理员商品管理界面支持商品的CRUD操作:

@WebServlet("/admin/goods")
public class AdminGoodsServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        String method = request.getParameter("method");
        GoodsService goodsService = new GoodsService();
        
        if ("add".equals(method)) {
            // 处理文件上传
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            
            try {
                List<FileItem> items = upload.parseRequest(request);
                Goods goods = new Goods();
                
                for (FileItem item : items) {
                    if (item.isFormField()) {
                        processFormField(item, goods);
                    } else {
                        processUploadFile(item, goods);
                    }
                }
                
                goodsService.addGoods(goods);
                response.sendRedirect("goods_list.jsp?msg=添加成功");
                
            } catch (Exception e) {
                response.sendRedirect("goods_add.jsp?error=添加失败");
            }
        }
    }
    
    private void processFormField(FileItem item, Goods goods) {
        String fieldName = item.getFieldName();
        String value = item.getString();
        
        switch (fieldName) {
            case "name": goods.setName(value); break;
            case "price": goods.setPrice(Double.parseDouble(value)); break;
            case "stock": goods.setStock(Integer.parseInt(value)); break;
            case "typeId": goods.setTypeId(Integer.parseInt(value)); break;
            case "intro": goods.setIntro(value); break;
        }
    }
}

后台商品管理

实体模型设计

系统采用经典的领域模型设计,核心实体关系清晰:

// 商品实体类
public class Goods {
    private Integer id;
    private String name;
    private String cover;
    private String image1;
    private String image2;
    private Double price;
    private String intro;
    private Integer stock;
    private Integer typeId;
    private Type type; // 关联对象
    
    // 构造方法、getter、setter
}

// 订单项实体类
public class OrderItem {
    private Integer id;
    private Double price; // 下单时的价格
    private Integer amount;
    private Integer goodsId;
    private Integer orderId;
    private Goods goods; // 关联商品信息
    
    public Double getSubtotal() {
        return price * amount;
    }
}

// 分页包装类
public class PageInfo<T> {
    private List<T> list;
    private int pageNum;
    private int pageSize;
    private int totalPages;
    private long totalRecords;
    
    // 分页逻辑方法
    public boolean hasPreviousPage() {
        return pageNum > 1;
    }
    
    public boolean hasNextPage() {
        return pageNum < totalPages;
    }
}

功能展望与优化方向

1. 性能优化与缓存策略

现状分析:当前系统每次访问都需要查询数据库,商品列表等高频访问数据没有缓存 优化方案:引入Redis作为缓存层,缓存商品分类、热门商品等数据

// 伪代码示例
public class GoodsServiceWithCache {
    private Jedis redis;
    
    public List<Goods> findHotGoods() {
        String cacheKey = "hot_goods";
        String cached = redis.get(cacheKey);
        if (cached != null) {
            return JSON.parseArray(cached, Goods.class);
        }
        
        List<Goods> goodsList = goodsMapper.findHotGoods();
        redis.setex(cacheKey, 300, JSON.toJSONString(goodsList)); // 缓存5分钟
        return goodsList;
    }
}

2. 微服务架构改造

现状分析:单体架构在业务扩展时存在部署耦合问题 优化方案:拆分为商品服务、订单服务、用户服务等独立微服务

# docker-compose.yml 示例
version: '3'
services:
  product-service:
    image: flower-mall/product:1.0
    ports: ["8081:8080"]
    
  order-service:
    image: flower-mall/order:1.0  
    ports: ["8082:8080"]
    
  api-gateway:
    image: flower-mall/gateway:1.0
    ports: ["80:8080"]

3. 搜索引擎集成

现状分析:当前商品搜索基于数据库LIKE查询,性能较差 优化方案:集成Elasticsearch提供高级搜索功能

// Elasticsearch集成示例
@Service
public class ProductSearchService {
    private RestHighLevelClient client;
    
    public SearchResponse searchProducts(String keyword, int page, int size) {
        SearchRequest request = new SearchRequest("products");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        
        sourceBuilder.query(QueryBuilders.multiMatchQuery(keyword, "name", "intro"));
        sourceBuilder.from((page - 1) * size).size(size);
        sourceBuilder.sort("_score", SortOrder.DESC);
        
        request.source(sourceBuilder);
        return client.search(request, RequestOptions.DEFAULT);
    }
}

4. 移动端适配与PWA支持

现状分析:当前系统主要面向PC端,移动体验有待优化 优化方案:采用响应式设计+Progressive Web App技术

<!-- 响应式布局示例 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="manifest" href="/manifest.json">

<style>
.goods-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
}

@media (max-width: 768px) {
    .goods-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 10px;
    }
}
</style>

5. 智能化推荐系统

现状分析:当前推荐功能基于人工配置,缺乏个性化 优化方案:基于用户行为数据实现协同过滤推荐

@Service
public class RecommendationService {
    public List<Goods> getPersonalizedRecommendations(Integer userId) {
        // 基于用户历史行为计算相似用户
        List<Integer> similarUsers = findSimilarUsers(userId);
        
        // 获取相似用户喜欢的商品
        List<Goods> recommendations = goodsMapper.findGoodsByUserPreferences(similarUsers);
        
        // 过滤已购买商品,按评分排序
        return recommendations.stream()
            .filter(g -> !hasPurchased(userId, g.getId()))
            .sorted(Comparator.comparingDouble(Goods::getRecommendationScore).reversed())
            .limit(10)
            .collect(Collectors.toList());
    }
}

总结

该鲜花电商平台基于成熟的J2EE技术栈,通过严谨的

本文关键词
JSPServlet在线鲜花商城源码解析数据库设计

上下篇

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