JDBC+Servlet+JSP 入门实战
大家好今天给大家分享一个从零搭建的简易电商后台项目用到了最基础的 Java Web 技术栈JDBC 操作数据库、Servlet 处理请求、JSP 渲染页面全程都是原生实现没有框架加持特别适合新手练手帮你彻底搞懂 Java Web 的底层流程。一、项目整体架构先给大家梳理一下整个项目的结构标准的 Maven Web 项目分层清晰方便后续扩展mall ├── src │ ├── main │ │ ├── java │ │ │ ├── com │ │ │ │ ├── entity # 实体类User、Product │ │ │ │ ├── dao # 数据访问层数据库操作 │ │ │ │ ├── service # 业务逻辑层 │ │ │ │ ├── servlet # 控制层处理请求 │ │ │ │ └── util # 工具类JDBC连接池封装 │ │ ├── resources │ │ └── webapp │ │ └── index.jsp # 前端页面 │ └── test/java # JUnit单元测试类 └── pom.xml # Maven依赖配置整体遵循经典的MVC 分层架构Entity 层数据库表对应的实体类和表字段一一映射DAO 层直接和数据库交互封装增删改查操作Service 层处理业务逻辑调用 DAO 层方法Servlet 层接收前端请求调用 Service 层转发到 JSP 页面JSP 层渲染页面展示数据二、环境准备与依赖配置1. Maven 依赖项目需要用到 JUnit、Servlet、JSTL、Lombok、MySQL 驱动这些核心依赖直接在pom.xml里配置即可dependencies !-- JUnit单元测试 -- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.13.2/version scopetest/scope /dependency !-- Servlet API -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- JSTL标签库 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency dependency groupIdtaglibs/groupId artifactIdstandard/artifactId version1.1.2/version /dependency !-- Lombok简化实体类 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version scopeprovided/scope /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency /dependencies这些依赖覆盖了测试、Web 开发、数据库连接、工具简化等场景Lombok 的Data注解能帮我们省去 getter/setter/toString 这些重复代码非常方便。2. 数据库创建先创建电商项目需要的数据库和两张核心表用户表user和商品表productSQL 脚本如下-- 创建数据库 CREATE DATABASE IF NOT EXISTS mall DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE mall; -- 创建用户表 CREATE TABLE IF NOT EXISTS user ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT 用户ID主键自增, name VARCHAR(50) NOT NULL COMMENT 用户名, password VARCHAR(100) NOT NULL COMMENT 密码, email VARCHAR(100) DEFAULT NULL COMMENT 邮箱, birthday DATE DEFAULT NULL COMMENT 生日 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表; -- 创建商品表 CREATE TABLE IF NOT EXISTS product ( id INT NOT NULL AUTO_INCREMENT COMMENT 商品id, name VARCHAR(255) DEFAULT NULL COMMENT 商品名称, product_desc VARCHAR(255) DEFAULT NULL COMMENT 商品描述信息, price DECIMAL(10,2) DEFAULT NULL COMMENT 商品价格, detail VARCHAR(255) DEFAULT NULL COMMENT 商品详细描述, num INT DEFAULT NULL COMMENT 商品库存数量, img VARCHAR(255) DEFAULT NULL COMMENT 商品图片路径, category VARCHAR(255) DEFAULT NULL COMMENT 商品分类, status INT DEFAULT NULL COMMENT 商品状态 0不可售 1可售, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表; -- 插入用户测试数据 INSERT INTO user (name, password, email, birthday) VALUES (张三, 123456, zhangsanqq.com, 2000-01-10), (李四, 654321, lisi163.com, 1999-05-20), (王五, abc123, wangwusina.com, 2001-08-15); -- 插入商品测试数据 INSERT INTO product (name, product_desc, price, detail, num, img, category, status) VALUES (Apple iPhone 15 Pro, 苹果旗舰智能手机, 7999.00, 6.7英寸超视网膜XDR显示屏钛金属设计, 88, https://img11.360buyimg.com/xxx.jpg, 手机数码, 1), (华为 Mate 60 Pro, 华为旗舰商务手机, 6999.00, 卫星通话昆仑玻璃, 66, https://img10.360buyimg.com/xxx.jpg, 手机数码, 1);运行脚本后我们的mall数据库就创建好了两张表也有了基础的测试数据后续操作就基于这两张表进行。三、核心工具类JDBC 连接封装每次写 JDBC 都要重复加载驱动、获取连接、关闭资源太麻烦了我们可以封装一个DButil工具类统一处理这些操作package com.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class DButil { // 数据库连接信息记得改成你自己的账号密码 public static String URLjdbc:mysql://localhost:3306/mall?serverTimezoneGMT%2B8useSSLfalse; public static String USERNAMEroot; public static String PASSWORD你的数据库密码; public static String DRIVERcom.mysql.jdbc.Driver; // MySQL 5.x驱动类 // 获取数据库连接 public static Connection getConnection(){ Connection connnull; try{ Class.forName(DRIVER); // 加载驱动 connDriverManager.getConnection(URL,USERNAME,PASSWORD); // 建立连接 }catch (Exception e){ e.printStackTrace(); } return conn; } // 关闭数据库资源结果集、执行对象、连接 public static void close(ResultSet rs, Statement st,Connection con){ try{ if (rs!null) rs.close(); if (st!null) st.close(); if (con!null) con.close(); }catch (Exception e){ e.printStackTrace(); } } }封装好之后后续所有 DAO 层操作直接调用DButil.getConnection()就能拿到连接操作完调用close()方法统一关闭资源代码清爽很多。四、实体类与 DAO 层实现1. 实体类Entity用 Lombok 的Data注解简化实体类和数据库表字段一一对应// User实体类 package com.entity; import lombok.Data; Data public class User { private int id; private String name; private String password; private String email; private String birthday; public User(){} public User(int id,String name){ this.idid; this.namename; } } // Product实体类 package com.entity; import lombok.Data; Data public class Product { private int id; private String name; private String product_desc; private float price; private String detail; private int num; private String img; private String category; private int status; }2. 用户 DAO 层UserDao UserDao1UserDao实现了查询所有用户的功能UserDao1封装了增、删、改用户的操作// UserDao查询所有用户 package com.dao; import com.entity.User; import com.util.DButil; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; public class UserDao { public ListUser getAll(){ Connection connull; Statement stmtnull; ResultSet rsnull; ListUser users new ArrayList(); String sql select * from User; try{ con DButil.getConnection(); stmt con.createStatement(); rs stmt.executeQuery(sql); while(rs.next()){ User user new User(); user.setId(rs.getInt(id)); user.setName(rs.getString(name)); user.setBirthday(rs.getString(birthday)); user.setEmail(rs.getString(email)); user.setPassword(rs.getString(password)); users.add(user); } }catch (Exception e){ e.printStackTrace(); }finally { DButil.close(rs,stmt,con); } return users; } } // UserDao1用户增删改操作 package com.dao; import com.entity.User; import com.util.DButil; import java.sql.Connection; import java.sql.PreparedStatement; public class UserDao1 { // 新增用户 public int add(User user){ int num 0; Connection conn DButil.getConnection(); try{ String sql insert into User(name,email,password,birthday) values(?,?,?,?); PreparedStatement pst conn.prepareStatement(sql); pst.setString(1,user.getName()); pst.setString(2,user.getEmail()); pst.setString(3,user.getPassword()); pst.setString(4,user.getBirthday()); num pst.executeUpdate(); DButil.close(null,pst,conn); }catch (Exception e){ e.printStackTrace(); } return num; } // 修改用户密码 public int updateUser(int id,String password){ int num 0; Connection conn DButil.getConnection(); try{ String sql update user set password? where id?; PreparedStatement pst conn.prepareStatement(sql); pst.setString(1,password); pst.setInt(2,id); num pst.executeUpdate(); DButil.close(null,pst,conn); }catch (Exception e){ e.printStackTrace(); } return num; } // 删除用户 public int deleteUser(int id){ int num 0; Connection con DButil.getConnection(); try{ String sql delete from user where id ?; PreparedStatement pst con.prepareStatement(sql); pst.setInt(1,id); num pst.executeUpdate(); DButil.close(null,pst,con); }catch (Exception e){ e.printStackTrace(); } return num; } }3. 商品 DAO 层ProductDao ProductDaoImpl先定义 DAO 接口再写实现类方便后续扩展五、Service 层与 Servlet 层实现1. 商品 Service 层Service 层调用 DAO 层方法处理业务逻辑// ProductService接口 package com.service; import com.entity.Product; import java.util.List; public interface ProductService { ListProduct getProductList(); int add(Product product); } // ProductServiceImpl实现类 package com.service; import com.dao.ProductDaoImpl; import com.entity.Product; import java.util.List; public class ProductServiceImpl implements ProductService { ProductDaoImpl pdi new ProductDaoImpl(); Override public ListProduct getProductList() { return pdi.getProsuctList(); } Override public int add(Product product) { return 0; } }2. ProductServlet处理请求并转发到 JSP用 Servlet 接收请求调用 Service 层获取商品列表再转发到 JSP 页面展示package com.Servlet; import com.service.ProductServiceImpl; import com.entity.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(/p) public class ProductServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ProductServiceImpl imp new ProductServiceImpl(); ListProduct products imp.getProductList(); // 把商品列表存入request域传递给JSP页面 req.setAttribute(products, products); // 转发到index.jsp页面 req.getRequestDispatcher(index.jsp).forward(req, resp); } }这里用WebServlet(/p)注解配置 Servlet 路径访问/p就会触发这个 Servlet 的doGet方法。六、JSP 页面渲染数据最后写一个简单的 JSP 页面用 JSTL 标签遍历商品列表展示数据% page contentTypetext/html;charsetUTF-8 languagejava isELIgnoredfalse % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title商品列表/title /head body h1商品列表/h1 c:forEach items${products} varitem p商品ID${item.id}/p p商品名称${item.name}/p p商品描述${item.product_desc}/p p商品价格${item.price}元/p hr /c:forEach /body /htmlisELIgnoredfalse是为了让 JSP 支持 EL 表达式c:forEach标签用来遍历 Servlet 传递过来的products集合。七、JUnit 单元测试验证 DAO 层功能我们写了几个单元测试类分别测试数据库连接、用户增删改查功能确保 DAO 层的代码是正确的1. 数据库连接测试import org.junit.Test; import java.sql.Connection; import java.sql.DriverManager; public class uint51 { Test public void test(){ try{ // 1、加载驱动 Class.forName(com.mysql.jdbc.Driver); // 2、连接信息 String urljdbc:mysql://localhost:3306/mall?serverTimezoneGMT%2B8useSSLfalse; String username你的数据库账号; String password你的数据库密码; // 获取连接 Connection con DriverManager.getConnection(url,username,password); System.out.println(数据库链接正常); con.close(); }catch(Exception e){ System.out.println(数据库链接失败); e.printStackTrace(); } } }运行测试后控制台输出数据库链接正常说明数据库连接没问题。2. 用户增删改测试// 新增用户测试 import com.entity.User; import com.dao.UserDao1; import org.junit.Test; public class AddTest { Test public void test(){ User user new User(); user.setName(李明); user.setEmail(lingming163.com); user.setPassword(123456); user.setBirthday(2003-04-20); UserDao1 userDao1 new UserDao1(); int num userDao1.add(user); if (num0) { System.out.println(插入数据成功了); } } } // 删除用户测试 import com.dao.UserDao1; import org.junit.Test; public class deleteTest { Test public void test(){ UserDao1 userDao1 new UserDao1(); int num userDao1.deleteUser(4); if (num 0){ System.out.println(删除成功); } } } // 修改用户密码测试 import com.dao.UserDao1; import org.junit.Test; public class updateTest { Test public void test(){ UserDao1 userDao1 new UserDao1(); int num userDao1.updateUser(1, newPassword123); if(num0){ System.out.println(密码修改成功); } } } // 查询所有用户测试 import com.dao.UserDao; import com.entity.User; import org.junit.Test; import java.util.ArrayList; import java.util.List; public class uint52 { Test public void test(){ UserDao userDao new UserDao(); ListUser users new ArrayList(); users userDao.getAll(); for(User u:users){ System.out.println(u); } } }这些测试都通过后说明我们的 DAO 层增删改查功能是完全正常的后续业务开发就可以放心调用了。八、项目运行效果把项目部署到 Tomcat 服务器启动后就能看到 JSP 页面渲染的商品列表了数据是从 MySQL 数据库里查出来的实现了最基础的数据库 - DAO - Service - Servlet - JSP完整流程。