从零到一:用Java+Servlet+JSP手把手搭建一个鲜花商城(附完整源码和数据库设计)

如果你正在寻找一个完整的Java Web项目实战教程,或是为毕业设计发愁,这篇指南将带你从零开始构建一个功能完善的鲜花商城系统。不同于纸上谈兵的理论分析,我们将聚焦于 可落地的代码实现 ,涵盖环境搭建、数据库设计、前后台功能开发等全流程。即使你是Servlet/JSP的初学者,也能跟着步骤完成项目。

1. 环境准备与项目初始化

1.1 开发工具清单

  • JDK 1.8+ :Java开发的基础环境
  • Eclipse/IntelliJ IDEA :推荐使用后者,对Web开发支持更友好
  • Tomcat 9.x :Servlet容器
  • MySQL 5.7+ :数据库服务
  • Navicat/MySQL Workbench :数据库可视化工具

1.2 创建Web项目

在IDE中新建Dynamic Web Project,确保勾选生成 web.xml 。项目结构应包含:

/flower-shop
  ├── src
  ├── WebContent
  │   ├── META-INF
  │   ├── WEB-INF
  │   │   ├── lib (存放依赖jar包)
  │   │   └── web.xml
  │   ├── css
  │   ├── js
  │   └── images

添加必要依赖到 lib 目录:

  • mysql-connector-java-8.0.x.jar
  • jstl-1.2.jar
  • servlet-api.jar

2. 数据库设计与实现

2.1 数据表结构

采用MySQL设计5张核心表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `email` varchar(100) NOT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `register_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username_UNIQUE` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

其他表包括:

  • category (鲜花分类)
  • product (鲜花商品)
  • cart (购物车)
  • orders (订单)

提示:字段设计需考虑扩展性,如价格使用DECIMAL而非FLOAT避免精度问题

2.2 数据库连接池配置

WEB-INF/web.xml 中添加:

<resource-ref>
  <description>MySQL Datasource</description>
  <res-ref-name>jdbc/flowerDB</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

创建 DBUtil.java 处理连接:

public class DBUtil {
    private static DataSource ds;
    static {
        try {
            Context ctx = new InitialContext();
            ds = (DataSource) ctx.lookup("java:comp/env/jdbc/flowerDB");
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}

3. 前台功能开发实战

3.1 用户认证模块

实现注册/登录的Servlet示例:

@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
        
        String username = request.getParameter("username");
        String password = SHA256Util.encrypt(request.getParameter("password"));
        
        try (Connection conn = DBUtil.getConnection()) {
            String sql = "INSERT INTO user(username, password, email) VALUES(?,?,?)";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, username);
            pstmt.setString(2, password);
            pstmt.setString(3, request.getParameter("email"));
            int result = pstmt.executeUpdate();
            
            if(result > 0) {
                request.getSession().setAttribute("user", username);
                response.sendRedirect("index.jsp");
            }
        } catch (SQLException e) {
            request.setAttribute("error", "用户名已存在");
            request.getRequestDispatcher("register.jsp").forward(request, response);
        }
    }
}

3.2 商品展示系统

商品列表JSP页面关键代码:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<table class="product-table">
  <c:forEach items="${products}" var="p">
    <tr>
      <td><img src="uploads/${p.image}" width="120"></td>
      <td>${p.name}</td>
      <td>¥${p.price}</td>
      <td>
        <a href="product_detail?id=${p.id}">查看详情</a>
        <button onclick="addToCart(${p.id})">加入购物车</button>
      </td>
    </tr>
  </c:forEach>
</table>

对应的Servlet:

@WebServlet("/product_list")
public class ProductListServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
        
        String categoryId = request.getParameter("cid");
        List<Product> products = new ArrayList<>();
        
        try (Connection conn = DBUtil.getConnection()) {
            String sql = "SELECT * FROM product WHERE status=1";
            if(categoryId != null) {
                sql += " AND category_id=" + categoryId;
            }
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery(sql);
            
            while(rs.next()) {
                Product p = new Product();
                p.setId(rs.getInt("id"));
                // 其他字段赋值...
                products.add(p);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        request.setAttribute("products", products);
        request.getRequestDispatcher("product_list.jsp").forward(request, response);
    }
}

4. 后台管理系统开发

4.1 管理员登录验证

使用Filter实现权限控制:

@WebFilter("/admin/*")
public class AdminFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, 
        FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest req = (HttpServletRequest) request;
        HttpSession session = req.getSession();
        
        if(session.getAttribute("admin") == null) {
            ((HttpServletResponse)response).sendRedirect("../admin_login.jsp");
            return;
        }
        chain.doFilter(request, response);
    }
}

4.2 商品管理功能

文件上传处理Servlet:

@WebServlet("/admin/product_upload")
@MultipartConfig(
    fileSizeThreshold = 1024 * 1024 * 1, // 1MB
    maxFileSize = 1024 * 1024 * 10,      // 10MB
    maxRequestSize = 1024 * 1024 * 100   // 100MB
)
public class ProductUploadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
        
        Part filePart = request.getPart("product_image");
        String fileName = System.currentTimeMillis() + "_" + 
            filePart.getSubmittedFileName();
        
        String uploadPath = getServletContext().getRealPath("") + "uploads";
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) uploadDir.mkdir();
        
        filePart.write(uploadPath + File.separator + fileName);
        
        // 保存到数据库
        try (Connection conn = DBUtil.getConnection()) {
            String sql = "INSERT INTO product(name, price, image) VALUES(?,?,?)";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, request.getParameter("name"));
            pstmt.setBigDecimal(2, new BigDecimal(request.getParameter("price")));
            pstmt.setString(3, fileName);
            pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        response.sendRedirect("product_list.jsp");
    }
}

5. 项目部署与优化

5.1 Tomcat部署要点

  1. 导出WAR包: 右键项目 → Export → WAR file
  2. 部署到Tomcat的 webapps 目录
  3. 配置 conf/server.xml 的Context:
<Context 
  docBase="/path/to/flower-shop" 
  path="/flowershop" 
  reloadable="true" 
  source="org.eclipse.jst.jee.server:flower-shop"/>

5.2 性能优化技巧

  • 数据库连接池 :配置Tomcat的 context.xml
  • 静态资源缓存 :在 web.xml 中添加:
<filter>
  <filter-name>ExpiresFilter</filter-name>
  <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
  <init-param>
    <param-name>ExpiresByType image</param-name>
    <param-value>access plus 1 month</param-value>
  </init-param>
</filter>
  • JSP预编译 :使用 jspc 工具提前编译

6. 常见问题解决方案

6.1 中文乱码处理

全局编码过滤器:

@WebFilter("/*")
public class EncodingFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, 
        FilterChain chain) throws IOException, ServletException {
        
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        chain.doFilter(request, response);
    }
}

6.2 分页查询实现

分页工具类核心方法:

public class Pagination<T> {
    private int pageSize = 10;
    private int currentPage;
    private int totalCount;
    private List<T> items;
    
    // 计算总页数
    public int getTotalPages() {
        return (int) Math.ceil((double)totalCount / pageSize);
    }
    
    // SQL分页语句生成
    public static String getPageSql(String baseSql, int page, int size) {
        return baseSql + " LIMIT " + (page-1)*size + "," + size;
    }
}

7. 项目扩展方向

  1. 支付接口集成 :接入支付宝沙箱环境
  2. 搜索优化 :实现Elasticsearch商品搜索
  3. 缓存机制 :引入Redis缓存热门商品
  4. 安全加固 :增加CSRF防护和XSS过滤

完整项目源码已托管至GitHub,包含详细的README和SQL脚本。在实际开发中遇到最多的问题是JSP页面元素定位,建议使用Chrome开发者工具逐步调试CSS样式。

更多推荐