Java Web搭建商城首页
下面我将为你提供一个完整的Java Web商城首页实现方案,使用Servlet+JSP技术栈。
📋 技术架构概览
层级 | 技术组件 | 职责说明 |
---|---|---|
前端展示 | JSP + EL + JSTL + Bootstrap | 页面渲染、响应式布局 |
控制层 | Servlet + Filter | 请求处理、业务逻辑控制 |
服务层 | Service 类 | 业务逻辑处理 |
数据层 | DAO 模式 + JDBC | 数据持久化操作 |
数据库 | MySQL | 数据存储 |
🗂️ 项目结构
WebContent/ ├── index.jsp # 商城首页 ├── WEB-INF/ │ ├── web.xml # 配置文件 │ ├── lib/ # 依赖库 │ └── classes/ │ ├── com/ │ │ └── eshop/ │ │ ├── controller/ # Servlet控制器 │ │ ├── service/ # 业务逻辑层 │ │ ├── dao/ # 数据访问层 │ │ ├── model/ # 实体类 │ │ └── util/ # 工具类 ├── css/ │ └── style.css # 样式文件 ├── js/ │ └── main.js # JavaScript文件 ├── images/ # 图片资源 └── uploads/ # 上传文件
🛒 核心数据模型
Product.java (商品实体类)
package com.eshop.model;import java.math.BigDecimal; import java.util.Date;public class Product {private Integer id;private String name;private String description;private BigDecimal price;private BigDecimal originalPrice; // 原价private Integer stock;private String imageUrl;private Integer categoryId;private Integer sales; // 销量private Integer status; // 状态:1-上架,0-下架private Date createTime;private Date updateTime;// 构造方法public Product() {}public Product(Integer id, String name, String description, BigDecimal price, BigDecimal originalPrice, Integer stock, String imageUrl, Integer categoryId, Integer sales, Integer status) {this.id = id;this.name = name;this.description = description;this.price = price;this.originalPrice = originalPrice;this.stock = stock;this.imageUrl = imageUrl;this.categoryId = categoryId;this.sales = sales;this.status = status;}// Getter和Setter方法public Integer getId() { return id; }public void setId(Integer id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }public String getDescription() { return description; }public void setDescription(String description) { this.description = description; }public BigDecimal getPrice() { return price; }public void setPrice(BigDecimal price) { this.price = price; }public BigDecimal getOriginalPrice() { return originalPrice; }public void setOriginalPrice(BigDecimal originalPrice) { this.originalPrice = originalPrice; }public Integer getStock() { return stock; }public void setStock(Integer stock) { this.stock = stock; }public String getImageUrl() { return imageUrl; }public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }public Integer getCategoryId() { return categoryId; }public void setCategoryId(Integer categoryId) { this.categoryId = categoryId; }public Integer getSales() { return sales; }public void setSales(Integer sales) { this.sales = sales; }public Integer getStatus() { return status; }public void setStatus(Integer status) { this.status = status; }public Date getCreateTime() { return createTime; }public void setCreateTime(Date createTime) { this.createTime = createTime; }public Date getUpdateTime() { return updateTime; }public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }// 计算折扣public int getDiscount() {if (originalPrice == null || originalPrice.compareTo(BigDecimal.ZERO) == 0) {return 0;}BigDecimal discount = originalPrice.subtract(price).divide(originalPrice, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));return discount.intValue();} }
Category.java (商品分类)
package com.eshop.model;public class Category {private Integer id;private String name;private String description;private Integer parentId; // 父级分类IDprivate Integer sortOrder; // 排序private Integer status; // 状态// 构造方法、Getter和Setterpublic Category() {}public Category(Integer id, String name, String description) {this.id = id;this.name = name;this.description = description;}public Integer getId() { return id; }public void setId(Integer id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }public String getDescription() { return description; }public void setDescription(String description) { this.description = description; }public Integer getParentId() { return parentId; }public void setParentId(Integer parentId) { this.parentId = parentId; }public Integer getSortOrder() { return sortOrder; }public void setSortOrder(Integer sortOrder) { this.sortOrder = sortOrder; }public Integer getStatus() { return status; }public void setStatus(Integer status) { this.status = status; } }
🗄️ 数据库设计
商品表 (products)
CREATE TABLE products (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(200) NOT NULL,description TEXT,price DECIMAL(10,2) NOT NULL,original_price DECIMAL(10,2),stock INT DEFAULT 0,image_url VARCHAR(500),category_id INT,sales INT DEFAULT 0,status TINYINT DEFAULT 1 COMMENT '1-上架, 0-下架',create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,INDEX idx_category (category_id),INDEX idx_status (status) );
商品分类表 (categories)
CREATE TABLE categories (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100) NOT NULL,description VARCHAR(500),parent_id INT DEFAULT 0,sort_order INT DEFAULT 0,status TINYINT DEFAULT 1,create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
🔧 数据访问层
ProductDAO.java
package com.eshop.dao;import com.eshop.model.Product; import com.eshop.util.DBUtil; import java.sql.*; import java.util.ArrayList; import java.util.List;public class ProductDAO {// 获取热门商品public List<Product> getHotProducts(int limit) {List<Product> products = new ArrayList<>();String sql = "SELECT * FROM products WHERE status = 1 ORDER BY sales DESC LIMIT ?";try (Connection conn = DBUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(sql)) {stmt.setInt(1, limit);ResultSet rs = stmt.executeQuery();while (rs.next()) {products.add(extractProductFromResultSet(rs));}} catch (SQLException e) {e.printStackTrace();}return products;}// 获取新品推荐public List<Product> getNewProducts(int limit) {List<Product> products = new ArrayList<>();String sql = "SELECT * FROM products WHERE status = 1 ORDER BY create_time DESC LIMIT ?";try (Connection conn = DBUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(sql)) {stmt.setInt(1, limit);ResultSet rs = stmt.executeQuery();while (rs.next()) {products.add(extractProductFromResultSet(rs));}} catch (SQLException e) {e.printStackTrace();}return products;}// 根据分类获取商品public List<Product> getProductsByCategory(int categoryId, int limit) {List<Product> products = new ArrayList<>();String sql = "SELECT * FROM products WHERE category_id = ? AND status = 1 ORDER BY sales DESC LIMIT ?";try (Connection conn = DBUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(sql)) {stmt.setInt(1, categoryId);stmt.setInt(2, limit);ResultSet rs = stmt.executeQuery();while (rs.next()) {products.add(extractProductFromResultSet(rs));}} catch (SQLException e) {e.printStackTrace();}return products;}// 搜索商品public List<Product> searchProducts(String keyword, int limit) {List<Product> products = new ArrayList<>();String sql = "SELECT * FROM products WHERE status = 1 AND (name LIKE ? OR description LIKE ?) ORDER BY sales DESC LIMIT ?";try (Connection conn = DBUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(sql)) {stmt.setString(1, "%" + keyword + "%");stmt.setString(2, "%" + keyword + "%");stmt.setInt(3, limit);ResultSet rs = stmt.executeQuery();while (rs.next()) {products.add(extractProductFromResultSet(rs));}} catch (SQLException e) {e.printStackTrace();}return products;}// 从ResultSet提取Product对象private Product extractProductFromResultSet(ResultSet rs) throws SQLException {Product product = new Product();product.setId(rs.getInt("id"));product.setName(rs.getString("name"));product.setDescription(rs.getString("description"));product.setPrice(rs.getBigDecimal("price"));product.setOriginalPrice(rs.getBigDecimal("original_price"));product.setStock(rs.getInt("stock"));product.setImageUrl(rs.getString("image_url"));product.setCategoryId(rs.getInt("category_id"));product.setSales(rs.getInt("sales"));product.setStatus(rs.getInt("status"));product.setCreateTime(rs.getTimestamp("create_time"));product.setUpdateTime(rs.getTimestamp("update_time"));return product;} }
CategoryDAO.java
package com.eshop.dao;import com.eshop.model.Category; import com.eshop.util.DBUtil; import java.sql.*; import java.util.ArrayList; import java.util.List;public class CategoryDAO {// 获取所有一级分类public List<Category> getTopCategories() {List<Category> categories = new ArrayList<>();String sql = "SELECT * FROM categories WHERE parent_id = 0 AND status = 1 ORDER BY sort_order";try (Connection conn = DBUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(sql);ResultSet rs = stmt.executeQuery()) {while (rs.next()) {categories.add(extractCategoryFromResultSet(rs));}} catch (SQLException e) {e.printStackTrace();}return categories;}// 根据父级ID获取子分类public List<Category> getSubCategories(int parentId) {List<Category> categories = new ArrayList<>();String sql = "SELECT * FROM categories WHERE parent_id = ? AND status = 1 ORDER BY sort_order";try (Connection conn = DBUtil.getConnection();PreparedStatement stmt = conn.prepareStatement(sql)) {stmt.setInt(1, parentId);ResultSet rs = stmt.executeQuery();while (rs.next()) {categories.add(extractCategoryFromResultSet(rs));}} catch (SQLException e) {e.printStackTrace();}return categories;}// 从ResultSet提取Category对象private Category extractCategoryFromResultSet(ResultSet rs) throws SQLException {Category category = new Category();category.setId(rs.getInt("id"));category.setName(rs.getString("name"));category.setDescription(rs.getString("description"));category.setParentId(rs.getInt("parent_id"));category.setSortOrder(rs.getInt("sort_order"));category.setStatus(rs.getInt("status"));return category;} }
⚙️ 数据库工具类
DBUtil.java
package com.eshop.util;import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException;public class DBUtil {private static final String URL = "jdbc:mysql://localhost:3306/eshop?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";private static final String USER = "root";private static final String PASSWORD = "password";static {try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}public static Connection getConnection() throws SQLException {return DriverManager.getConnection(URL, USER, PASSWORD);} }
🎮 控制器Servlet
HomeServlet.java
package com.eshop.controller;import com.eshop.dao.CategoryDAO; import com.eshop.dao.ProductDAO; import com.eshop.model.Category; import com.eshop.model.Product;import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List;@WebServlet("/home") public class HomeServlet extends HttpServlet {private ProductDAO productDAO = new ProductDAO();private CategoryDAO categoryDAO = new CategoryDAO();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {try {// 获取热门商品(销量最高)List<Product> hotProducts = productDAO.getHotProducts(8);// 获取新品推荐List<Product> newProducts = productDAO.getNewProducts(8);// 获取商品分类List<Category> categories = categoryDAO.getTopCategories();// 设置请求属性request.setAttribute("hotProducts", hotProducts);request.setAttribute("newProducts", newProducts);request.setAttribute("categories", categories);// 转发到首页request.getRequestDispatcher("/index.jsp").forward(request, response);} catch (Exception e) {e.printStackTrace();response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务器内部错误");}} }
🎨 商城首页JSP
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>电子商城 - 首页</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css"><style>.hero-section {background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);color: white;padding: 80px 0;margin-bottom: 40px;}.product-card {transition: transform 0.3s, box-shadow 0.3s;margin-bottom: 20px;}.product-card:hover {transform: translateY(-5px);box-shadow: 0 10px 20px rgba(0,0,0,0.1);}.discount-badge {position: absolute;top: 10px;right: 10px;background: #ff4444;color: white;padding: 5px 10px;border-radius: 15px;font-size: 12px;}.price {color: #ff4444;font-weight: bold;font-size: 18px;}.original-price {text-decoration: line-through;color: #999;font-size: 14px;}.section-title {border-left: 4px solid #667eea;padding-left: 15px;margin: 30px 0 20px 0;}.navbar-brand {font-weight: bold;color: #667eea !important;}</style> </head> <body><!-- 导航栏 --><nav class="navbar navbar-expand-lg navbar-light bg-light sticky-top"><div class="container"><a class="navbar-brand" href="home">电子商城</a><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav me-auto"><li class="nav-item"><a class="nav-link active" href="home">首页</a></li><c:forEach var="category" items="${categories}"><li class="nav-item"><a class="nav-link" href="category?id=${category.id}">${category.name}</a></li></c:forEach></ul><form class="d-flex me-2" action="search" method="get"><input class="form-control me-2" type="search" name="keyword" placeholder="搜索商品..." aria-label="Search"><button class="btn btn-outline-primary" type="submit">搜索</button></form><div class="navbar-nav"><a class="nav-link" href="cart.jsp"><i class="bi bi-cart3"></i> 购物车</a><a class="nav-link" href="login.jsp"><i class="bi bi-person"></i> 登录</a></div></div></div></nav><!-- 英雄区域/轮播图 --><div class="hero-section"><div class="container text-center"><h1 class="display-4 fw-bold">欢迎来到电子商城</h1><p class="lead">品质生活,从这里开始</p><a href="#hot-products" class="btn btn-light btn-lg mt-3">立即选购</a></div></div><div class="container"><!-- 热门商品 --><h2 class="section-title" id="hot-products">热门商品</h2><div class="row"><c:forEach var="product" items="${hotProducts}"><div class="col-lg-3 col-md-4 col-sm-6"><div class="card product-card h-100"><c:if test="${product.discount > 0}"><span class="discount-badge">${product.discount}% OFF</span></c:if><img src="${empty product.imageUrl ? 'images/default-product.jpg' : product.imageUrl}" class="card-img-top" alt="${product.name}" style="height: 200px; object-fit: cover;"><div class="card-body d-flex flex-column"><h5 class="card-title">${product.name}</h5><p class="card-text flex-grow-1">${product.description}</p><div class="mt-auto"><div class="price-section mb-2"><span class="price">¥${product.price}</span><c:if test="${product.originalPrice != null && product.originalPrice > product.price}"><span class="original-price ms-2">¥${product.originalPrice}</span></c:if></div><div class="d-flex justify-content-between align-items-center"><small class="text-muted">销量: ${product.sales}</small><button class="btn btn-primary btn-sm add-to-cart" data-product-id="${product.id}"><i class="bi bi-cart-plus"></i> 加入购物车</button></div></div></div></div></div></c:forEach></div><!-- 新品推荐 --><h2 class="section-title">新品推荐</h2><div class="row"><c:forEach var="product" items="${newProducts}"><div class="col-lg-3 col-md-4 col-sm-6"><div class="card product-card h-100"><c:if test="${product.discount > 0}"><span class="discount-badge">${product.discount}% OFF</span></c:if><img src="${empty product.imageUrl ? 'images/default-product.jpg' : product.imageUrl}" class="card-img-top" alt="${product.name}" style="height: 200px; object-fit: cover;"><div class="card-body d-flex flex-column"><h5 class="card-title">${product.name}</h5><p class="card-text flex-grow-1">${product.description}</p><div class="mt-auto"><div class="price-section mb-2"><span class="price">¥${product.price}</span><c:if test="${product.originalPrice != null && product.originalPrice > product.price}"><span class="original-price ms-2">¥${product.originalPrice}</span></c:if></div><button class="btn btn-primary btn-sm add-to-cart w-100" data-product-id="${product.id}"><i class="bi bi-cart-plus"></i> 加入购物车</button></div></div></div></div></c:forEach></div></div><!-- 页脚 --><footer class="bg-dark text-light mt-5 py-4"><div class="container"><div class="row"><div class="col-md-4"><h5>关于我们</h5><p>专业的电子商城,为您提供优质的商品和服务。</p></div><div class="col-md-4"><h5>联系我们</h5><p>电话: 400-123-4567</p><p>邮箱: service@eshop.com</p></div><div class="col-md-4"><h5>关注我们</h5><div class="social-links"><a href="#" class="text-light me-3"><i class="bi bi-wechat"></i></a><a href="#" class="text-light me-3"><i class="bi bi-weibo"></i></a><a href="#" class="text-light"><i class="bi bi-tiktok"></i></a></div></div></div><div class="text-center mt-3"><p>© 2024 电子商城 版权所有</p></div></div></footer><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script><script>$(document).ready(function() {// 添加购物车功能$('.add-to-cart').click(function() {const productId = $(this).data('product-id');$.ajax({url: 'addToCart',type: 'POST',data: { productId: productId, quantity: 1 },success: function(response) {if (response.success) {// 显示成功消息showMessage('商品已成功加入购物车!', 'success');} else {showMessage('加入购物车失败,请稍后重试。', 'error');}},error: function() {showMessage('网络错误,请检查网络连接。', 'error');}});});function showMessage(message, type) {// 创建消息提示const alertClass = type === 'success' ? 'alert-success' : 'alert-danger';const alertHtml = `<div class="alert ${alertClass} alert-dismissible fade show position-fixed" style="top: 20px; right: 20px; z-index: 1050; min-width: 300px;">${message}<button type="button" class="btn-close" data-bs-dismiss="alert"></button></div>`;$('body').append(alertHtml);// 3秒后自动消失setTimeout(() => {$('.alert').alert('close');}, 3000);}});</script> </body> </html>
⚙️ Web配置文件
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><display-name>电子商城</display-name><!-- 首页设置 --><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><!-- 字符编码过滤器 --><filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>com.eshop.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 错误页面配置 --><error-page><error-code>404</error-code><location>/error/404.jsp</location></error-page><error-page><error-code>500</error-code><location>/error/500.jsp</location></error-page></web-app>
🔧 字符编码过滤器
CharacterEncodingFilter.java
package com.eshop.filter;import javax.servlet.*; import java.io.IOException;public class CharacterEncodingFilter implements Filter {private String encoding = "UTF-8";@Overridepublic void init(FilterConfig filterConfig) throws ServletException {String encodingParam = filterConfig.getInitParameter("encoding");if (encodingParam != null) {encoding = encodingParam;}}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {request.setCharacterEncoding(encoding);response.setCharacterEncoding(encoding);chain.doFilter(request, response);}@Overridepublic void destroy() {// 清理资源} }
📦 依赖配置
Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.eshop</groupId><artifactId>eshop</artifactId><version>1.0.0</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><!-- Servlet API --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><!-- JSP API --><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.3</version><scope>provided</scope></dependency><!-- JSTL --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!-- JSON处理 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.3</version></dependency></dependencies><build><finalName>eshop</finalName><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build> </project>
🚀 部署和运行
-
环境要求
-
JDK 1.8+
-
Tomcat 9+
-
MySQL 5.7+CREATE DATABASE eshop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
-
USE eshop; -- 执行前面提供的建表语句
-
部署步骤
-
将项目打包为WAR文件
-
部署到Tomcat的webapps目录
-
启动Tomcat服务器
-
访问 http://localhost:8080/eshop/home
-
💡 功能扩展建议
-
购物车功能 - 添加购物车Servlet和页面
-
用户系统 - 注册、登录、个人中心
-
商品搜索 - 高级搜索和筛选
-
商品详情 - 详细的商品展示页面
-
订单系统 - 下单、支付、订单管理
-
后台管理 - 商品管理、订单管理
这个完整的Java Web商城首页实现包含了现代化的UI设计、响应式布局、前后端交互等功能,可以作为电商项目的基础进行进一步开发。