Skip to content

1.介绍

学习完servlet 和 jsp 之后的第一个小demo

学习目的:第一次 打通 前端 后端 数据库 ,看到完整的javaweb 项目 基本流程

技术栈: servlet + jsp + jdbc + mysql + tomcat + maven + bootstrap +

2.准备工作:

准备数据库

sql
/*
SQLyog Ultimate v11.33 (64 bit)
MySQL - 5.7.15 : Database - ssm
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`ssm` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;

USE `ssm`;

/*Table structure for table `t_student` */

DROP TABLE IF EXISTS `t_student`;

CREATE TABLE `t_student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `sex` varchar(3) DEFAULT NULL,
  `birthday` datetime DEFAULT NULL,
  `phone` varchar(32) DEFAULT NULL,
  `address` varchar(32) DEFAULT NULL,
  `hobby` varchar(200) DEFAULT NULL,
  `pic` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=93 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

/*Data for the table `t_student` */

insert  into `t_student`(`id`,`name`,`sex`,`birthday`,`phone`,`address`,`hobby`,`pic`) values (9,'李逍垚','男','2022-03-29 00:00:00','123333','郑州','coding','https://qf2201.oss-cn-beijing.aliyuncs.com/img/1650957654174.png'),(14,'刘洁','女','2022-03-14 00:00:00','123','郑州','coding','https://qf2201.oss-cn-beijing.aliyuncs.com/img/1651025986871.png'),(17,'刘洁','女','2022-03-08 00:00:00','12333334444','郑州','1113','https://qf2201.oss-cn-beijing.aliyuncs.com/img/1651026006687.png'),(18,'张文桧','男','2022-03-13 00:00:00','888','郑州111','听音乐','https://qf2201.oss-cn-beijing.aliyuncs.com/img/1651114571498.png'),(19,'胡图图123','男','2022-03-14 00:00:00','888','郑州','听音乐','https://qf2201.oss-cn-beijing.aliyuncs.com/img/1651114700812.png'),(25,'李孟阳123','女','2022-03-14 00:00:00','13511111','郑州','playgame',''),(27,'李垚','男','2022-03-15 16:43:03','1239','郑州','coding',NULL),(32,'张飞','男','2022-03-15 16:54:20','123','郑州','eating',NULL),(37,'张文桧','男','2022-03-15 17:20:18','888','郑州','听音乐',NULL),(40,'海龙战神','男','2022-03-15 17:52:57','111','郑州','貂蝉',NULL),(45,'哦哦','男','2022-03-15 18:34:37','123','郑州','郑州',NULL),(53,'张义博','男','2022-03-17 09:55:25','123','上海','coding',NULL),(55,'妲己222','女','2022-03-25 00:00:00','123','123','123',NULL),(66,'李垚','男','2022-04-24 00:00:00','111','222','写代码','https://qf2201.oss-cn-beijing.aliyuncs.com/img/1650794347858.png'),(73,'骚琦','男','2022-07-20 00:00:00','123','郑州','喊麦','https://java2207.oss-cn-hangzhou.aliyuncs.com/2207/saoqi.jpg'),(76,'晓雨3','女','2022-07-15 00:00:00','123','4567','play','https://java2207.oss-cn-hangzhou.aliyuncs.com/image/1658310400041.jpg'),(79,'zs','男','2022-10-11 00:00:00','123','123','123','123'),(80,'zszzzz','男','2022-10-11 00:00:00','123','123','123','123'),(81,'321','保密','2022-10-11 00:00:00','2222','zz','1232222','123'),(82,'afeng','男','2022-10-11 00:00:00','123','123','111','https://java2212.oss-cn-hangzhou.aliyuncs.com/image/1665474350740.jpg'),(83,'xiaomei','女','2022-10-12 00:00:00','123','123','123','https://java2212.oss-cn-hangzhou.aliyuncs.com/image/1665474464939.jpg'),(84,'222','保密','2022-10-12 00:00:00','222','222','222',''),(85,'张三','男','1999-11-11 00:00:00',NULL,'222','coding',NULL),(86,'李思思','女','1999-12-12 00:00:00',NULL,'222','coding',NULL),(87,'zzz','男','1999-11-11 00:00:00',NULL,'222','coding',NULL),(88,'qqqq','男','1999-11-11 00:00:00',NULL,'222','coding',NULL),(91,'zs','男','1999-11-11 00:00:00',NULL,NULL,'coding',NULL),(92,'ls','女','1999-12-12 00:00:00',NULL,NULL,'coding',NULL);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

3.创建maven 形式的web 工程

1.先创建一个 empty project

2.创建module 以maven 的形式 使用骨架 创建web工程 注意 路径要放在刚才的project 下面

3.添加依赖

java
<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!--添加servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- 引入jsp依赖 -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
      <scope>provided</scope>
    </dependency>

    <!--    lombok依赖-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <!--druid连接池的依赖-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.3</version>
    </dependency>
    <!--mysql驱动 注意 8 的驱动 对应的 url 和  driverClass 的写法-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.21</version>
    </dependency>

  </dependencies>

4.修改web.xml

​ 因为自动创建的web.xml 约束版本为2.3 ,修改如下

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">

</web-app>

5.创建基本的包 , 实体类 数据库配置文件

image-20230330165911828

db.properties

java
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
username=root
password=123456
# ----- 加入druid的一些连接配置
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->
maxWait=5000

DbUtil工具类

java
package com.glls.utils;



import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class DBUtil {

    static Properties properties = new Properties( );
    // 声明Druid连接池对象
    private static DruidDataSource druidDataSource;

    static {
        try {
            // 将配置文件读作输入流
            InputStream stream = DBUtil.class.getResourceAsStream("/db.properties");
            // properties对象加载流,即配置信息都在properties对象里面
            properties.load(stream);
            // 通过配置信息创建出druidDataSource数据源
            druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace( );
        }
    }

    /**
     * 通过DruidDataSource获得连接
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            // 2 获得连接
            conn = druidDataSource.getConnection( );
        } catch (Exception e) {
            e.printStackTrace( );
        }
        return conn;
    }

    /**
     * 抽取关流的方法
     */
    public static void closeAll(Connection conn, Statement s) {
        if (conn != null) {
            try {
                conn.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (s != null) {
            try {
                s.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
    }

    public static void closeAll(Connection conn, Statement s, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (s != null) {
            try {
                s.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
        if (rs != null) {
            try {
                rs.close( );
            } catch (SQLException e) {
                e.printStackTrace( );
            }
        }
    }

    /**
     * 封装查询一个对象
     *
     * @param sql  有?的sql语句
     * @param t    要封装的实体类字节码文件
     * @param args 要给?赋值的值
     *             select * from tb_user where id = ?
     */
    public static <T> T selectOne(String sql, Class<T> t, Object... args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        T target = null;
        Field[] fields = t.getDeclaredFields( );
        try {
            conn = getConnection( );
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject((i + 1), args[i]);
            }

            rs = ps.executeQuery( );
            if (rs.next( )) {
                target = t.newInstance( );
                for (Field field : fields) {
                    String name = field.getName( );
                    // 因为ORM,所以属性名就是列名
                    Object value = rs.getObject(name);
                    if (value == null) {
                        continue;
                    }
                    field.setAccessible(true);
                    field.set(target, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace( );
        } finally {
            closeAll(conn, ps, rs);
        }
        return target;
    }


    public static <T> List<T> selectAll(String sql, Class<T> t, Object... args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        T target = null;
        Field[] fields = t.getDeclaredFields( );
        ArrayList<T> list = new ArrayList<>( );
        try {
            conn = getConnection( );
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject((i + 1), args[i]);
            }

            rs = ps.executeQuery( );
            while (rs.next( )) {
                target = t.newInstance( );
                for (Field field : fields) {
                    String name = field.getName( );
                    // 因为ORM,所以属性名就是列名
                    Object value = rs.getObject(name);
                    field.setAccessible(true);
                    if (value == null) {
                        continue;
                    }
                    field.set(target, value);
                }
                list.add(target);
            }
        } catch (Exception e) {
            e.printStackTrace( );
        } finally {
            closeAll(conn, ps, rs);
        }
        return list;
    }

    /**
     * 增删改设计成一个方法
     */
    public static int update(String sql,Object... args) {
        Connection conn = null;
        PreparedStatement ps = null;
        int num = 0;
        try {

            conn = getConnection( );
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject((i + 1), args[i]);
            }

            num = ps.executeUpdate( );

        } catch (Exception e) {
            e.printStackTrace( );
        } finally {
            closeAll(conn, ps);
        }
        return num;
    }

    public static void main(String[] args) {
        System.out.println(getConnection());
    }
}

前端页面准备

bootstrap中文网

使用步骤:

  1. 在页面引入资源文件 ,这个资源文件 可以选择下载到本地 ,也可以选择直接引用线上的资源文件

    这里 咱们资源文件的引入 放入 top.jsp 里面,别的页面只需要包含它即可

    top.jsp

    java
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
    
        <!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
        <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
    <%--    <script src="https://cdn.jsdelivr.cn/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>--%>
    
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
        <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    
    <nav class="navbar navbar-inverse">
        <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Brand</a>
            </div>
    
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="${pageContext.request.contextPath}/studentList">学员管理 <span class="sr-only">(current)</span></a></li>
                    <li><a href="#">Link</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </li>
                </ul>
    
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#">
    
                        ${currentUser.name}
    
                    </a></li>
                    <li><a href="${pageContext.request.contextPath}/logout">
    
                        注销
    
                    </a></li>
                </ul>
                <form class="navbar-form navbar-right">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Search">
                    </div>
                    <button type="submit" class="btn btn-default">Submit</button>
                </form>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>

    登录功能

    登录页面

    java
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <jsp:include page="common/top.jsp"></jsp:include>
    </head>
    <body>
    <p style="height: 50px"></p>
    <div class="container">
        <h1 class="text-center"> 登录页面</h1>
    
        <form action="${pageContext.request.contextPath}/login" method="post" class="form-horizontal" role="form">
            <div class="form-group">
                <label for="firstname"  class="col-sm-2 col-sm-offset-1 control-label">用户名</label>
                <div class="col-sm-6">
                    <input name="name" type="text" class="form-control" id="firstname"
                           placeholder="请输入用户名">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 col-sm-offset-1  control-label">密码</label>
                <div class="col-sm-6">
                    <input  name="password" type="password" class="form-control" id="lastname"
                            placeholder="请输入密码">
                </div>
            </div>
            <%--    <div class="form-group">--%>
            <%--        <div class="col-sm-offset-2 col-sm-10">--%>
            <%--            <div class="checkbox">--%>
            <%--                <label>--%>
            <%--                    <input type="checkbox"> 请记住我--%>
            <%--                </label>--%>
            <%--            </div>--%>
            <%--        </div>--%>
            <%--    </div>--%>
    
            <div class="form-group">
                ${error}
                <div class="col-sm-offset-4 col-sm-6">
                    <button type="submit" class="btn btn-default">登录</button>
                    <button type="button" class="btn btn-default">注册</button>
                </div>
            </div>
        </form>
    </div>
    
    </body>
    </html>

    对应后端LoginServlet

    java
    package com.glls.web;
    /**
     * @date 2023/3/29
     * @desc
     */
    
    import com.glls.pojo.Student;
    import com.glls.service.StudentService;
    import com.glls.service.impl.StudentServiceImpl;
    
    import javax.servlet.*;
    import javax.servlet.http.*;
    import javax.servlet.annotation.*;
    import java.io.IOException;
    
    @WebServlet(name = "LoginServlet", value = "/login")
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            request.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=utf-8");
            //获取 用户名 密码
    
            String name = request.getParameter("name");
            String password = request.getParameter("password");
    
            StudentService studentService = new StudentServiceImpl();
    
            Student result = studentService.login(name,password);
    
            if(result!=null){
                //用户名 密码是正确的
                HttpSession session = request.getSession();
                // 把查询出来的用户信息 存到session 域对象中
                session.setAttribute("currentUser",result);
                response.sendRedirect(request.getServletContext().getContextPath() +"/main.jsp");
    
            }else{
                //用户名 密码 错误
                request.setAttribute("error","用户名或密码错误");
                request.getRequestDispatcher("/login.jsp").forward(request,response);
            }
        }
    }

    对应的service 方法

    java
       @Override
        public Student login(String name, String password) {
    
            Student student = studentDao.login(name, password);
    
            return student;
        }

    对应的dao 方法

    java
       @Override
        public Student login(String name, String password) {
    
            String sql = "select * from t_student where name = ? and password = ? ";
    
            Student student = DBUtil.selectOne(sql, Student.class, name, password);
    
            return student;
        }

    登录成功之后 跳转到 main.jsp

    java
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    
    </head>
    <body>
    
        <jsp:include page="common/top.jsp"></jsp:include>
    
        <div class="container-fluid">
            <div class="jumbotron">
                <h1>Hello, JavaWeb!</h1>
                <p>纸上得来终觉浅</p>
                <p>绝知此事要躬行</p>
    
                <p>抬头 看看周围 大家都在努力</p>
                <p></p>
                <p>在干什么?</p>
    
    
                <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
            </div>
        </div>
    
    
    <jsp:include page="common/footer.jsp"></jsp:include>
    </body>
    </html>

    点击导航条上的 学员管理 查看学员列表

    image-20230330171026810

请求后端 StudentListServlet

java
package com.glls.web;

import com.glls.pojo.Student;
import com.glls.service.StudentService;
import com.glls.service.impl.StudentServiceImpl;

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;

/**
 * @date 2023/3/30
 * @desc
 */
@WebServlet("/studentList")
public class StudentListServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        // 准备好学生列表数据

        StudentService studentService = new StudentServiceImpl();
        List<Student> students =  studentService.studentList();
        //放在域对象中
        req.setAttribute("students",students);

        //跳转到页面上展示
        req.getRequestDispatcher("/studentList.jsp").forward(req,resp);
    }
}

对应的service 方法

java
    @Override
    public List<Student> studentList() {

        List<Student>  students = studentDao.studentList();

        return students;
    }

对应的dao 方法

java
    @Override
    public List<Student> studentList() {
        String sql = "select * from t_student ";
        List<Student> students = DBUtil.selectAll(sql, Student.class);
        return students;
    }

查询出来的数据 会在servlet 放入域对象 然后转发到studentList.jsp 使用el表达式和 jstl 标签 取数据

java
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <jsp:include page="common/top.jsp"></jsp:include>
    <div class="page-header">
            <small>
            <a type="button" href="${pageContext.request.contextPath}/studentAdd.jsp" class="btn btn-info">学员添加</a>
        </small>
    </div>

    <table class="table">
        <thead>
        <tr>
            <th>编号</th>
            <th>姓名</th>
            <th>性别</th>
            <th>生日</th>
            <th>电话</th>
            <th>地址</th>
            <th>爱好</th>
            <th>头像</th>
            <th>操作</th>
        </tr>
        </thead>
        <c:forEach items="${students}" var="stu">
            <tr>
                <td>${stu.id}</td>
                <td>${stu.name}</td>
                <td>${stu.sex}</td>
                <td>
                <fmt:formatDate value="${stu.birthday}" pattern="yyyy-MM-dd" ></fmt:formatDate>
                </td>
                <td>${stu.phone}</td>
                <td>${stu.address}</td>
                <td>${stu.hobby}</td>
                <td>
                    <img width="50px" height="50px" src=" ${stu.pic}" alt="">
                       </td>
                <td>
                    <a class="btn btn-primary" href="${pageContext.request.contextPath}/studentUpdate?id=${stu.id}" role="button">编辑</a>
                    <a class="btn btn-warning" href="${pageContext.request.contextPath}/studentDelete?id=${stu.id}" role="button">删除</a>
                </td>
            </tr>
        </c:forEach>
    </table>

    <jsp:include page="/common/footer.jsp"></jsp:include>
</body>
</html>

删除功能

image-20230330172550602

image-20230330172614627

对应的servlet

java
package com.glls.web;

import com.glls.service.StudentService;
import com.glls.service.impl.StudentServiceImpl;

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;


@WebServlet("/studentDelete")
public class StudentyDeleteServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String id = req.getParameter("id");

        //创建service 对象
        StudentService studentService = new StudentServiceImpl();

        int result = studentService.deleteStudentById(Integer.parseInt(id));

        if(result==1){
            //删除成功  刷新下列表  这里咱么请求 列表数据的servlet
            req.getRequestDispatcher("/studentList").forward(req,resp);
        }else{
            System.out.println("删除失败");
        }

    }
}

对应的service 的删除方法

java
   @Override
    public int deleteStudentById(Integer id) {
        int result = studentDao.deleteStudentById(id);
        return result;
    }

对应的dao的删除方法

java
    @Override
    public int deleteStudentById(Integer id) {
        String sql = "delete from t_student where id = ?";
        int result = DBUtil.update(sql, id);
        return result;
    }

编辑功能

点页面上的编辑按钮

image-20230330175021134

对应的servlet

java
package com.glls.web;

import com.glls.pojo.Student;
import com.glls.service.StudentService;
import com.glls.service.impl.StudentServiceImpl;

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;

@WebServlet("/studentUpdate")
public class StudentUpdateServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //接受要修改的记录的id
        String id = req.getParameter("id");

        //根据id 把要修改的记录查出来
        StudentService studentService = new StudentServiceImpl();

        Student stu = studentService.findStudentById(Integer.parseInt(id));
        // 把要修改的数据 展示在页面上
        req.setAttribute("stu",stu);

        req.getRequestDispatcher("/studentUpdate.jsp").forward(req,resp);
    }
}

service层代码

java
 @Override
    public Student findStudentById(int id) {
        Student student = studentDao.findStudentById(id);
        return student;
    }

dao层代码

java
    @Override
    public Student findStudentById(int id) {
        String sql = "select * from t_student where id = ?";
        Student student = DBUtil.selectOne(sql, Student.class, id);
        return student;
    }

查询出来的要修改的记录 回显到表单上面

image-20230330175216731

对应的页面 studentUpdate.jsp

java
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<jsp:include page="common/top.jsp"></jsp:include>
<form class="form-horizontal" method="post" action="${pageContext.request.contextPath}/doUpdate">
    <div class="form-group">
        <label for="id" class="col-sm-2 control-label">编号</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" readonly id="id" placeholder="编号" name="id" value="${stu.id}">
        </div>
    </div>
    <div class="form-group">
        <label for="name" class="col-sm-2 control-label">学生姓名</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" id="name" placeholder="学生姓名" name="name" value="${stu.name}">
        </div>
    </div>

    <div class="form-group">
        <label for="sex" class="col-sm-2 control-label">性别</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" id="sex" placeholder="性别" name="gender" value="${stu.sex}">
        </div>
    </div>
    <div class="form-group">
        <label for="birthday" class="col-sm-2 control-label">生日</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" id="birthday" placeholder="生日" name="birthday" value="${stu.birthday}">
        </div>
    </div>

    <div class="form-group">
        <label for="phone" class="col-sm-2 control-label">电话</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" id="phone" placeholder="电话" name="phone" value="${stu.phone}">
        </div>
    </div>

    <div class="form-group">
        <label for="address" class="col-sm-2 control-label">住址</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" id="address" placeholder="住址" name="address" value="${stu.address}">
        </div>
    </div>

    <div class="form-group">
        <label for="hobby" class="col-sm-2 control-label">爱好</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" id="hobby" placeholder="爱好" name="hobby" value="${stu.hobby}">
        </div>
    </div>

<%--    //头像 先不做--%>



    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default">提交</button>
        </div>
    </div>
</form>


<jsp:include page="/common/footer.jsp"></jsp:include>
</body>
</html>

在这个页面 提交 修改后的数据 到数据库 请求 DoUpdateStudentServlet

java
package com.glls.web;

import com.glls.pojo.Student;
import com.glls.service.StudentService;
import com.glls.service.impl.StudentServiceImpl;
import com.glls.utils.DateUtil;

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.Date;

/**
 * @date 2023/3/30
 * @desc
 */
@WebServlet("/doUpdate")
public class DoUpdateStudentServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        //接受表单数据
        String id = req.getParameter("id");
        String name = req.getParameter("name");
        String gender = req.getParameter("gender");
        String birthday = req.getParameter("birthday");
        String phone = req.getParameter("phone");
        String address = req.getParameter("address");
        String hobby = req.getParameter("hobby");

        //封装到对象中
        Student student = new Student();
        student.setId(Integer.parseInt(id));
        student.setName(name);
        student.setSex(gender);

        //前端传来的日期是一个字符串类型 而实体类中的日期是 Date 类型 所以这里需要转换
        Date date = DateUtil.strToDate(birthday);
        student.setBirthday(date);
        student.setPhone(phone);
        student.setAddress(address);
        student.setHobby(hobby);
        //调用service 去做修改

        StudentService studentService = new StudentServiceImpl();
        int result = studentService.updateStudentById(student);
        // 修改成功 刷新页面列表
        if(result==1){
            req.getRequestDispatcher("/studentList").forward(req,resp);
        }else{
            req.setAttribute("error","编辑失败");
            req.setAttribute("stu",student);
            req.getRequestDispatcher("/studentUpdate.jsp").forward(req,resp);
        }
    }
}

添加功能

image-20230331141051635

studentAdd.jsp

java
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>

</head>
<body>
<jsp:include page="common/top.jsp"></jsp:include>
<h1 class="text-center">添加学生</h1>
<form class="form-horizontal" method="post" action="${pageContext.request.contextPath}/studentAdd">

    <div class="form-group">
        <label for="name" class="col-sm-2  col-sm-offset-1 control-label">学生姓名</label>
        <div class="col-sm-6">
            <input type="text" class="form-control" id="name" placeholder="学生姓名" name="name" >
        </div>
    </div>

    <div class="form-group">
        <label  class="col-sm-2 col-sm-offset-1 control-label">性别</label>
        <div class="col-sm-6">
            <label class="radio-inline">
                <input type="radio" name="gender" id="sex1" value="男">
            </label>
            <label class="radio-inline">
                <input type="radio" name="gender" id="sex2" value="女">
            </label>
        </div>
    </div>
    <div class="form-group">
        <label for="birthday" class="col-sm-2 col-sm-offset-1 control-label">生日</label>
        <div class="col-sm-6">
            <input type="date" class="form-control" id="birthday" placeholder="生日" name="birthday" >
        </div>

    </div>

    <div class="form-group">
        <label for="phone" class="col-sm-2 col-sm-offset-1 control-label">电话</label>
        <div class="col-sm-6">
            <input type="text" class="form-control" id="phone" placeholder="电话" name="phone" >
        </div>
    </div>

    <div class="form-group">
        <label for="address" class="col-sm-2 col-sm-offset-1 control-label">住址</label>
        <div class="col-sm-6">
            <input type="text" class="form-control" id="address" placeholder="住址" name="address" >
        </div>
    </div>

    <div class="form-group">
        <label for="hobby" class="col-sm-2 col-sm-offset-1 control-label">爱好</label>
        <div class="col-sm-6">
            <input type="text" class="form-control" id="hobby" placeholder="爱好" name="hobby" >
        </div>
    </div>

    <%--    //头像 先不做--%>



    <div class="form-group">
        <div class="col-sm-offset-5 col-sm-10">
            <button type="submit" class="btn btn-default">提交</button>
        </div>
    </div>
    ${error}
</form>
<jsp:include page="/common/footer.jsp"></jsp:include>
</body>
</html>

StudentAddServlet

java
// 自己实现添加功能

分页功能

背景: 当列表中的数据比较多的时候,在页面展示时 需要分页查询 ,mysql 的分页语句 要使用 limit 关键字

select 。。。。 from table where ..... limit start ,size; start 指的是从哪里开始取数据 size 指的是取多少条数据。 结合 功能的实现 前端需要传到后端 页码 就是 第几页 start = (页码 -1 ) * pageSize

思路: 还是 把分页数据 放在 域对象 然后跳转到页面 ,这就要求我们 不能再只放一个 集合了 ,需要设计一个数据结构 存放 页面上 分页列表数据 以及 分页的数据 比如 页码 总记录数 总页数等 那这个数据结构就是 pageBean

Page

java
package com.glls.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @date 2023/3/31
 * @desc 封装分页的数据
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Page<T> {
    // 分页列表数据
    private List<T> pageData;
    //页码
    private Integer pageNum;
    //一共多少页
    private Integer totalPage;
    //一共有多少记录
    private Integer totalRecord;
    //页面显示的起始页
    private Integer startPageNum;
    //页面显示的终止页
    private Integer endPageNum;
}

在学生列表页面 咱们请求的就是 分页数据了

首先看 页面 ,需要使用 el + jstl 展示分页数据

java
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <jsp:include page="common/top.jsp"></jsp:include>
    <div class="page-header">
            <small>
            <a type="button" href="${pageContext.request.contextPath}/studentAdd.jsp" class="btn btn-info">学员添加</a>
        </small>
    </div>

    <table class="table">
        <thead>
        <tr>
            <th>编号</th>
            <th>姓名</th>
            <th>性别</th>
            <th>生日</th>
            <th>电话</th>
            <th>地址</th>
            <th>爱好</th>
            <th>头像</th>
            <th>操作</th>
        </tr>
        </thead>
        <c:forEach items="${page.pageData}" var="stu">
            <tr>
                <td>${stu.id}</td>
                <td>${stu.name}</td>
                <td>${stu.sex}</td>
                <td>
                <fmt:formatDate value="${stu.birthday}" pattern="yyyy-MM-dd" ></fmt:formatDate>
                </td>
                <td>${stu.phone}</td>
                <td>${stu.address}</td>
                <td>${stu.hobby}</td>
                <td>
                    <img width="50px" height="50px" src=" ${stu.pic}" alt="">
                       </td>
                <td>
                    <a class="btn btn-primary" href="${pageContext.request.contextPath}/studentUpdate?id=${stu.id}" role="button">编辑</a>
                    <a class="btn btn-warning" href="${pageContext.request.contextPath}/studentDelete?id=${stu.id}" role="button">删除</a>
                </td>
            </tr>
        </c:forEach>
    </table>
    <div align="center">
        <nav aria-label="Page navigation">

            <ul class="pagination">
                <li class="disabled">
                    <a href=""> 当前第${page.pageNum}页</a>
                </li>
                <c:if test="${page.pageNum>1}">
                    <li>
                        <a href="${pageContext.request.contextPath}/studentList?pageNum=${page.pageNum-1}" aria-label="Previous">
                            <span aria-hidden="true">上一页</span>
                        </a>

                    </li>
                </c:if>

                <c:forEach var="num" begin="${page.startPageNum}" end="${page.endPageNum}">
                    <c:choose>
                        <c:when test="${num==page.pageNum}">
                            <li class="disabled"><a  href="#"> ${num}</a></li>
                        </c:when>
                        <c:otherwise>
                            <li><a href="${pageContext.request.contextPath}/studentList?pageNum=${num}"> ${num}</a></li>
                        </c:otherwise>
                    </c:choose>

                </c:forEach>


                <c:if test="${page.pageNum<page.totalPage}">
                    <li>
                        <a href="${pageContext.request.contextPath}/studentList?pageNum=${page.pageNum+1}" aria-label="Next">
                            <span aria-hidden="true">下一页</span>
                        </a>
                    </li>
                </c:if>
                <li class="disabled">
                    <a href="">共${page.totalPage}页</a>
                </li>

            </ul>
        </nav>
    </div>

</body>
</html>

请求的后端servlet

java
package com.glls.web;

import com.glls.pojo.Page;
import com.glls.pojo.Student;
import com.glls.service.StudentService;
import com.glls.service.impl.StudentServiceImpl;
import com.mysql.cj.util.StringUtils;

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;

/**
 * @date 2023/3/30
 * @desc
 */
@WebServlet("/studentList")
public class StudentListServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       this.doPost(req,resp);
    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        //接受分页参数    第几页
        String num = req.getParameter("pageNum");
        Integer pageNum = 1;
        if(!StringUtils.isNullOrEmpty(num)){
            //如果传过来的页码不为空  接受传过来的页码
            pageNum = Integer.parseInt(num);
        }
        //如果 传过来的页码为空  pageNum = 1

        // 准备好分页数据
        StudentService studentService = new StudentServiceImpl();

        Page page = studentService.getPageData(pageNum);
        //把 分页数据 放在域对象中
        req.setAttribute("page",page);

        //跳转到页面上展示
        req.getRequestDispatcher("/studentList.jsp").forward(req,resp);
    }
}

service 实现分页功能

java
@Override
    public Page getPageData(Integer pageNum) {

        Page<Student> studentPage = new Page<>();

        studentPage.setPageNum(pageNum);    //封装页码
        Integer pageSize = 5;   //每页显示的记录数

        List<Student> pageData = studentDao.getPageData(pageNum,pageSize);
        studentPage.setPageData(pageData);  //封装分页的列表数据

        Integer totalRecord = studentDao.getTotalRecord();

        studentPage.setTotalRecord(totalRecord);  // 封装总记录数

        Integer totalPageNum = totalRecord%pageSize==0?(totalRecord/pageSize):(totalRecord/pageSize+1);

        studentPage.setTotalPage(totalPageNum); // 封装总页数


        //起始的页码   终止的页码   假设一共10 页
        /**
         * 1 2 3 4 5    第一页的时候
         *
         * 1 2 3 4 5    2
         *
         * 1 2 3 4 5    3
         *
         * 2 3 4 5 6    4
         *
         * 3 4 5 6 7    5
         *
         *
         * 6 7 8 9 10   8
         *
         * 6 7 8 9 10   9
         *
         * 6 7 8 9 10   10
         *
         * */

        Integer startPageNum = 1;
        Integer endPageNum = 5;

        //当页码 大于3 时  页面显示的 情况
        if(pageNum-2>1){
            startPageNum = pageNum-2;
            endPageNum = pageNum + 2;
        }

        //当页面翻到 最后两页时
        if(pageNum+2>totalPageNum){
            startPageNum = totalPageNum-4;
            endPageNum = totalPageNum;
        }

        //总页数 不到5 页 的情况
        if(totalPageNum<5){
            startPageNum = 1;
            endPageNum = totalPageNum;
        }

        studentPage.setStartPageNum(startPageNum);
        studentPage.setEndPageNum(endPageNum);

        return studentPage;
    }

对应dao方法

java
// 分页 查询 要查询出 分页列表数据
@Override
    public List<Student> getPageData(Integer pageNum, Integer pageSize) {
        //mysql 的分页语句    limit (pageNum-1)*pageSize, pageSize;
        String sql = "select * from t_student limit ?,?";
        Integer start = (pageNum-1) * pageSize;
        List<Student> students = DBUtil.selectAll(sql, Student.class, start, pageSize);
        return students;
    }
//分页查询 也需要查询总记录数
    @Override
    public Integer getTotalRecord() {

        String sql = "select * from t_student";

        List<Student> students = DBUtil.selectAll(sql, Student.class);

        Integer totalRecord = students.size();
        return totalRecord;
    }

模糊查询功能

页面输入查询条件, 点击查询按钮

image-20230331143048615

查询 请求 还是 StudentListServlet , 需要在这servlet 中 接受 查询条件 ,这里 有两种思路

思路1 就是使用表单向后端发送模糊查询的条件

思路2 js 发送模糊查询的条件,这里咱们先试用js 来实现

java
 <a type="button" onclick="findByCon()" class="btn btn-info">查询</a>
java
        function findByCon(){
            var s_name = $("#s_name").val();
            var s_phone = $("#s_phone").val();

            window.location.href="${pageContext.request.contextPath}/studentList?s_name="+s_name+"&s_phone="+s_phone;
        }
    </script>

后端 介绍查询条件,重构前面的分页查询方法 把service 和 dao 的 分页查询方法 加上模糊查询的条件

java
@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");

        //接受分页参数    第几页
        String num = req.getParameter("pageNum");
        Integer pageNum = 1;
        if(!StringUtils.isNullOrEmpty(num)){
            //如果传过来的页码不为空  接受传过来的页码
            pageNum = Integer.parseInt(num);
        }
        //如果 传过来的页码为空  pageNum = 1


        //获取模糊查询的条件
        String s_name = req.getParameter("s_name");
        String s_phone = req.getParameter("s_phone");


        // 准备好分页数据
        StudentService studentService = new StudentServiceImpl();
		// 把模糊查询的条件 加上去
        Page page = studentService.getPageData(pageNum,s_name,s_phone);
        //把 分页数据 放在域对象中
        req.setAttribute("page",page);

        // 把查询条件带回去
        req.setAttribute("s_name",s_name);
        req.setAttribute("s_phone",s_phone);

        //跳转到页面上展示
        req.getRequestDispatcher("/studentList.jsp").forward(req,resp);
    }

对应的service 实现 也是只需加上 模糊查询条件 s_name s_phone

java
  List<Student> pageData = studentDao.getPageData(pageNum,pageSize,s_name,s_phone);
        studentPage.setPageData(pageData);  //封装分页的列表数据

        Integer totalRecord = studentDao.getTotalRecord(s_name,s_phone);

需要注意的是 dao 层 sql 语句 怎么拼接

java
@Override
    public List<Student> getPageData(Integer pageNum, Integer pageSize, String s_name, String s_phone) {
        // 创建sb 对象  因为要拼接字符串
         StringBuffer sb = new StringBuffer("select * from t_student ");
        // s_name 不为空 需要把这个条件拼上去
         if(!StringUtils.isNullOrEmpty(s_name)){
             sb.append(" and name like '%"+s_name+"%' ");
         }
        // s_phone 不为空 需要把这个条件拼上去
        if(!StringUtils.isNullOrEmpty(s_phone)){
            sb.append(" and phone like '%"+s_phone+"%' ");
        }

        //mysql 的分页语句    limit (pageNum-1)*pageSize, pageSize;
        sb.append( " limit ?, ?");

        // 把 and 用 where 替换掉
        String sql = sb.toString().replaceFirst("and" ," where");

        Integer start = (pageNum-1) * pageSize;
        List<Student> students = DBUtil.selectAll(sql, Student.class, start, pageSize);
        return students;
    }

    @Override
    public Integer getTotalRecord(String s_name, String s_phone) {

        StringBuffer sb = new StringBuffer("select * from t_student ");

        if(!StringUtils.isNullOrEmpty(s_name)){
            sb.append(" and name like '%"+s_name+"%' ");
        }

        if(!StringUtils.isNullOrEmpty(s_phone)){
            sb.append(" and phone like '%"+s_phone+"%' ");
        }

        String sql = sb.toString().replaceFirst("and" ," where");

        List<Student> students = DBUtil.selectAll(sql, Student.class);

        Integer totalRecord = students.size();
        return totalRecord;
    }

测试 模糊查询的效果

image-20230331164355893