Servlet与JSP入门:Jakarta开发实战指南

由于技术的更新迭代,现在主流技术是前后端分离,但是作用初学者来说对于深入理解web尤其是Servet的工作原理和流程(同时也是为了学习web框架的基础)深入掌握Setvlet的原理和工作流程是非常重要的,本文就是基于Jakarta下的(不同于javax)的Servet和Jsp的一个简单的应用,希望能够给初学web和想深入了解Servlet的同学有所帮助。

git地址:https://gitee.com/yangyang1110_admin/web-jsp-test.git

一、开发环境

  JDK 17+

  tomcat10

 mysql8

 idea2022+

maven3.9.+

二、技术栈

1、Servlet+Jsp

2、tomcat10+

3、泛型DAO

4、bootstrap(模态窗)

5、JSTL

三、项目实现

3.1 创建JakartaEE项目

3.2pom.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>student_web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>student_web</name>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
        <junit.version>5.9.1</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>

3.3 测试

3.4 引入JSTL并测试

<dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
    <version>3.0.2</version>
</dependency>

<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>jakarta.servlet.jsp.jstl</artifactId>
    <version>3.0.1</version>
</dependency>

index.jsp:

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<a href="hello-servlet">Hello Servlet</a>
   <c:forEach begin="0" end="10" var="i">
        <font color="blue">${i}</font>&nbsp;&nbsp;&nbsp;
   </c:forEach>
</body>
</html>

3.5 对Servlet的封装

package com.example.student.web;

import com.example.student.service.UserService;
import com.example.student.service.factory.ServiceFactory;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * @author TonySong
 * @date 2025/8/7 0007
 * @time 12:13
 */
public class BaseServlet extends HttpServlet {

    protected static final String PREFIX="/WEB-INF/view/";
    protected static final String  SUFFIX=".jsp";

    protected UserService userService= ServiceFactory.createUserService();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         request.setCharacterEncoding("utf-8");
         response.setContentType("text/html;charset=utf-8");
         response.setCharacterEncoding("utf-8");
         String urlAnnotation=null;
         //获取请求的Servlet对象
        Class<?> servletClass = this.getClass();
        // 直接获取类上的WebServlet注解(用于拼接url)
        WebServlet servletAnnotation = servletClass.getAnnotation(WebServlet.class);
        if(servletAnnotation != null) {
          urlAnnotation =    servletAnnotation.value()[0];
            System.out.println(urlAnnotation);
        }
        /**
         * 1. 获取method参数,它是用户想调用的方法
         */
        String methodName = request.getParameter("action");
        System.out.println("请求的方法:"+methodName);
        Method method=null;

        try {
            //2. 通过反射获取方法
            method = this.getClass().getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("没有找到对应的方法");
        }

        /**
         *
         * 3. 通过method对象来调用它
         */
        try {
            String result = (String)method.invoke(this, request, response);
            System.out.println("方法的返回值是:"+result);
            if(result != null && !result.trim().isEmpty()) {//如果请求处理方法返回不为空
                int index = result.indexOf(":");//获取第一个冒号的位置 f:login.jsp
                if(index == -1) {//如果没有冒号,使用转发
                    request.getRequestDispatcher(result).forward(request, response);
                } else {//如果存在冒号
                    String start = result.substring(0, index);//分割出前缀
                    String path = result.substring(index + 1);//分割出路径
                    System.out.println("start:"+start);
                    System.out.println("path:"+path);
                    if("forward".equals(start)) {//前缀为forward表示转发
                        request.getRequestDispatcher(path).forward(request, response);
                    } else if("redirect".equals(start)) {//前缀为redirect表示重定向
                        String contextPath=request.getContextPath()+urlAnnotation+"?action=";
                        System.out.println(contextPath);
                        System.out.println(path);
                        response.sendRedirect(contextPath + path);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}
3.5.1 项目结构

3.5.2 测试Servlet
@WebServlet("/hello")
public class HelloServlet extends BaseServlet{

    protected String list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("hello....list");
        return "list.jsp";

    }
    protected String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("hello....add");
        return "redirect:list";
    }
}
3.5.2 测试用jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
     <h1>list</h1>
</body>
</html>
 3.5.4 测试效果

控制台输出:

四、用户列表实现

4.1 新增依赖:

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

        <!--logback 日志依赖-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.5.18</version>
        </dependency>

        <!--Mysql 依赖-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>9.3.0</version>
        </dependency>

4.2 日志

在resources下新增logback.xml,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--
        CONSOLE :表示当前的日志信息是可以输出到控制台的。
    -->
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%level] %blue(%d{HH:mm:ss.SSS}) %cyan([%thread]) %boldGreen(%logger{15}) - %msg %n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <logger name="com.example.student" level="DEBUG" additivity="false">
        <appender-ref ref="Console"/>
    </logger>


    <!--
      level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
     , 默认debug
      <root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
      -->
    <root level="DEBUG">
        <appender-ref ref="Console"/>
    </root>
</configuration>

4.3 配置文件

resources下新增jdbc.properties,内容如下:

jdbc.username=mysql的账号
jdbc.password=mysql的密码
jdbc.url=jdbc:mysql://localhost:3306/book_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
jdbc.driver=com.mysql.cj.jdbc.Driver

4.4 JDBC的封装

 4.4.1 通用接口
package com.example.student.dao;

import com.example.student.util.Pager;

import java.util.List;

/**
 * 宋伟宁
 * 2020/3/26
 */
public interface IGenericDao<T, PK extends Number> {

    /**
     * 执行聚合函数
     *
     * @param sql
     * @return
     */
    int executeScalre(String sql);

    int executeScalre(String sql, Object object);

    int executeScalre(String sql, Object[] args);

    /**
     * 列表
     *
     * @param select
     * @param args
     * @return
     */
    List<T> findAll(String select, Object[] args);

    List<T> findAll(String select, Object obj);

    List<T> findAll(String select);

    /**
     * 查询对象
     *
     * @param select
     * @param args
     * @return
     */
    T findObject(String select, Object[] args);

    T findObject(String select, Object obj);

    T findObject(String select);


    int save(String insert, Object... args);

    int delete(String delete, Integer id);

    int update(String update, Object... args);

    int getTotal(String sql, Object[] args);

    int getTotal(String sql, Object object);

    int getTotal(String sql);

    /**
     * 分页
     *
     * @param sql
     * @param currentPage
     * @param pagesize
     * @return
     */
    Pager<T> pagelist(String sql, String currentPage, int pagesize);

    Pager<T> pagelist(String sql, String currentPage, int pagesize, Object obj);

    Pager<T> pagelist(String sql, String currentPage, int pagesize, Object[] args);


}
4.4.2 通用数据操作类
package com.example.student.dao.impl;


import com.example.student.util.Pager;
import lombok.extern.slf4j.Slf4j;


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 宋伟宁
 * <p>
 * 2019年10月3日下午10:40:55
 */
@Slf4j
public class BaseDao {

    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
    private static Connection connection;//连接
    private static PreparedStatement pst;//预编译
    private static ResultSet rs;//结果集
    private static CallableStatement cstmt;//执行存储过程对象
    private static Properties properties = new Properties();
    private static String URL, DRIVER, USER, PWD;
    private static int m;
    //private static  String JNDI;


    /**
     * 静态块读取配置文件(获取数据库连接属性)
     * 获取数据库驱动
     */
    static {
        InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties");
        try {
            properties.load(input);
            DRIVER = properties.getProperty("jdbc.driver");
            USER = properties.getProperty("jdbc.username");
            PWD = properties.getProperty("jdbc.password");
            URL = properties.getProperty("jdbc.url");
            Class.forName(DRIVER);
            log.debug("驱动:" + DRIVER + "账号:" + USER + "密码:" + PWD + "URL" + URL);
        } catch (Exception e) {
            log.debug("加载驱动失败。。。" + e.getMessage());
        }

    }

    /**
     * 通用的列表
     *
     * @param sql
     * @param clazz
     * @param args
     * @return 泛型集合
     */
    public static <T> List<T> findAll(String sql, Class<T> clazz, Object... args) {
        log.debug("BaseDao..sql:" + sql);
        List<T> list = new ArrayList<T>(20);
        T t = null;
        try {
            pst = createPreparedStatement(sql, args);
            rs = pst.executeQuery();

            while (rs.next()) {
                t = convert(clazz, rs);
                list.add(t);
            }
        } catch (SQLException e) {
            log.debug("BaseDao...findAll 错误。。。。" + e.getMessage());
        } finally {
            closeAll(rs, pst);
            closeConnection();
        }
        return list;
    }

    /**
     * 通用的分页
     *
     * @param sql
     * @param clazz
     * @param currentPage
     * @param pagesize
     * @param args
     * @return
     */
    public static <T> Pager<T> pageAll(String sql, Class<T> clazz, String currentPage, int pagesize, Object... args) {
        log.debug("page sql:" + sql);
        String total_sql = sql.replace("*", "count(*)").replace("limit ?,?", "").replace("LIMIT ?,?", "");
        log.debug("total_sql: " + total_sql);
        List<T> list = new ArrayList<T>(20);
        T t = null;
        Pager<T> pager = null;
        try {
            int total = executeScalare(total_sql, args);
            pager = new Pager<>(total, currentPage, pagesize);

            String sql_page = sql.replace("?,?", String.valueOf(pager.getOffset()) + "," + String.valueOf(pager.getPagesize()));
            log.debug("BaseDao..sql:" + sql_page);
            pst = createPreparedStatement(sql_page, args);

            rs = pst.executeQuery();

            while (rs.next()) {
                t = convert(clazz, rs);
                list.add(t);
            }
            pager.setDatas(list);
        } catch (SQLException e) {
            log.debug("BaseDao...分页查询 错误。。。。" + e.getMessage());
        } finally {
            closeAll(rs, pst);
            closeConnection();
        }

        return pager;
    }

    public static void main(String[] args) {

    }
    /**
     * 根据id或条件查询单个对象
     *
     * @param sql
     * @param clazz
     * @param args
     * @return
     */
    public static <T> T findByObject(String sql, Class<T> clazz, Object... args) {
        T t = null;
        log.debug("BaseDao..findByObject  sql:" + sql);
        try {
            pst = createPreparedStatement(sql, args);
            rs = pst.executeQuery();
            if (rs.next()) {
                t = convert(clazz, rs);
            }
        } catch (Exception e) {
            log.debug("BaseDao findByObject。。。。错误!" + e.getMessage());
        } finally {
            closeAll(rs, pst);
            closeConnection();
        }
        return t;
    }

    public static int executeScalare(String sql, Object... args) {
        log.debug("BaseDao..executeScalar  sql:" + sql);
        try {
            //pst= getConnection().prepareStatement(sql);//1.0.0
            pst = createPreparedStatement(sql, args);// 1.0.1
            rs = pst.executeQuery();
            if (rs.next()) {
                m = rs.getInt(1);
            }
        } catch (Exception e) {
            log.debug("执行聚合函数错误。。。。" + e.getMessage());
        } finally {
            closeAll(rs, pst);
            closeConnection();
        }

        return m;
    }

    private static <T> T convert(Class<T> clazz, ResultSet rs) throws SQLException {
        ResultSetMetaData metaData = rs.getMetaData();
        int count = metaData.getColumnCount();
        T t = null;
        try {
            t = clazz.newInstance();
            for (int i = 1; i <= count; i++) {
                String str = metaData.getColumnLabel(i);
                Field field = clazz.getDeclaredField(str);
                field.setAccessible(true);
                field.set(t, rs.getObject(str));
            }
        } catch (InstantiationException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
            log.debug("类型转换,注入属性值错误:" + e.getMessage());
        }
        return t;
    }


    /**
     * ThreadLocal模式的获取数据库连接
     *
     * @return
     */
    public static Connection getConnection() {
        try {
            connection = threadLocal.get();
            if (connection == null || connection.isClosed()) {
                connection = DriverManager.getConnection(URL, USER, PWD);
                threadLocal.set(connection);
            }
        } catch (SQLException e) {
            log.debug("创建connection 错误:" + e.getMessage());
        }
        return connection;
    }

    /**
     * 释放数据库连接
     */
    public static void closeConnection() {
        connection = threadLocal.get();
        try {
            if (connection != null && !connection.isClosed()) {
                connection.close();
                threadLocal.remove();
            }
        } catch (SQLException e) {
            log.debug("释放connection失败:" + e.getMessage());
        }

    }

    /**
     * 释放所有数据库连接资源
     *
     * @param closeables
     */
    public static void closeAll(AutoCloseable... closeables) {
        for (AutoCloseable closeable : closeables) {
            if (closeable != null) {
                try {
                    closeable.close();
                } catch (Exception e) {
                    log.debug("释放资源失败:" + e.getMessage());
                }
            }
        }
    }

    /**
     * 获取预编译执行对象
     *
     * @param sql
     * @param args
     * @return
     */
    public static PreparedStatement createPreparedStatement(String sql, Object... args) {
        log.debug("创建preparedStatement sql:" + sql);
        try {
            pst = getConnection().prepareStatement(sql);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    pst.setObject(i + 1, args[i]);
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return pst;
    }


    /**
     * 通用的增、删、改
     *
     * @param sql
     * @param args
     * @return 受影响的行数
     */
    public static int executeCommand(String sql, Object... args) {
        log.debug("执行增、删、改的sql:" + sql);
        pst = createPreparedStatement(sql, args);
        try {
            m = pst.executeUpdate();
        } catch (SQLException e) {
            log.debug("执行增、删、改错误:" + e.getMessage());
        } finally {
            closeAll(pst);
            closeConnection();
        }
        return m;
    }

    /**
     * 开启事务
     */
    public static void beginTransaction() {
        Connection conn = getConnection();
        if (conn != null) {
            try {
                conn.setAutoCommit(false);
            } catch (SQLException e) {
                log.debug("事务开启失败!", e);
                throw new RuntimeException(e);
            } finally {
                threadLocal.set(conn);
            }
        }
    }

    /**
     * 提交事务
     */
    public static void commitTransaction() {
        Connection conn = getConnection();
        if (conn != null) {
            try {
                conn.commit();
                conn.close();
            } catch (SQLException e) {
                log.error("commit transaction failure", e);
                throw new RuntimeException(e);
            } finally {
                threadLocal.remove();
            }
        }
    }

    /**
     * 回滚事务
     */
    public static void rollbackTransaction() {
        Connection conn = getConnection();
        if (conn != null) {
            try {
                conn.rollback();
                conn.close();
            } catch (SQLException e) {
                log.error("rollback transaction failure", e);
                throw new RuntimeException(e);
            } finally {
                threadLocal.remove();
            }
        }
    }


    /**
     * 得到执行存储过程对象
     *
     * @param pname
     * @param args
     * @return
     */
    private static CallableStatement createCallableStatement(String pname, Object... args) {
        try {
            pname = pname.startsWith("{") ? pname : "{call " + pname + "}";
            cstmt = getConnection().prepareCall(pname);
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    cstmt.setObject(i + 1, args[i]);
                }
            }
        } catch (SQLException e) {
           log.debug("...........存储过程加载失败...........");
        }
        return cstmt;
    }

    /**
     * 通用的存储过程实现增、删、改
     *
     * @param pname
     * @param args
     * @return
     */
    public static int executeProcedure(String pname, Object... args) {
        try {
            cstmt = createCallableStatement(pname, args);
            m = cstmt.executeUpdate();
        } catch (Exception e) {
            log.debug("。。。。。。。。。执行增、删、改的存储过程错误。。。。。。。。" + e.getMessage());

        } finally {
            closeAll(null, null, cstmt, getConnection());
        }
        return m;
    }

    /**
     * 使用存储过程查询所有
     *
     * @param pname
     * @param clazz
     * @param args
     * @return
     */
    public static <T> List<T> procedureQuery(String pname, Class<T> clazz, Object... args) {
        List<T> list = new ArrayList<T>(20);
        T t = null;
        try {
            cstmt = createCallableStatement(pname, args);
            rs = cstmt.executeQuery();
            while (rs.next()) {
                t = convert(clazz, rs);
                list.add(t);
            }
        } catch (Exception e) {
            log.debug("执行列表存储过程错误。。。。。" + e.getMessage());

        } finally {
            closeAll(rs, cstmt);
            closeConnection();
        }
        return list;
    }

    /**
     * 根据条件查询单个对象的存储过程
     *
     * @param pname
     * @param clazz
     * @param args
     * @return
     */
    public static <T> T procedureFindByObject(String pname, Class<T> clazz, Object... args) {
        T t = null;
        try {
            cstmt = createCallableStatement(pname, args);
            rs = cstmt.executeQuery();
            if (rs.next()) {
                t = convert(clazz, rs);
            }
        } catch (Exception e) {
            log.debug("执行查询单个对象存储过程错误。。。。。" + e.getMessage());
        } finally {
            closeAll(rs, cstmt);
            closeConnection();
        }
        return t;
    }
}
4.4.3 通用接口实现类
package com.example.student.dao.impl;


import com.example.student.dao.IGenericDao;
import com.example.student.util.Pager;

import java.util.List;

/**
 * 宋伟宁
 * 2020/3/26
 */
public class GenericDao<T, PK extends Number> implements IGenericDao<T, PK> {
    private Class<T> clazz;

    protected GenericDao() {
        //利用反射将传递T类型转换为具体的类型 Book.class User.class NewsDto.class
        this.clazz = (Class<T>) ((java.lang.reflect.ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }


    @Override
    public int save(String insert, Object... args) {

        return BaseDao.executeCommand(insert, args);
    }

    @Override
    public int delete(String delete, Integer id) {

        return BaseDao.executeCommand(delete, id);
    }

    @Override
    public int update(String udpate, Object... args) {

        return BaseDao.executeCommand(udpate, args);
    }

    @Override
    public List<T> findAll(String select, Object[] args) {

        return BaseDao.findAll(select, clazz, args);
    }

    @Override
    public List<T> findAll(String select, Object obj) {

        return this.findAll(select, new Object[]{obj});
    }

    @Override
    public List<T> findAll(String sql) {

        return this.findAll(sql, null);
    }

    @Override
    public T findObject(String select, Object[] args) {
        // TODO Auto-generated method stub
        return BaseDao.findByObject(select, clazz, args);
    }

    @Override
    public T findObject(String select, Object obj) {
        // TODO Auto-generated method stub
        return this.findObject(select, new Object[]{obj});
    }

    @Override
    public T findObject(String select) {
        // TODO Auto-generated method stub
        return this.findObject(select, null);
    }


    @Override
    public Pager<T> pagelist(String sql, String currentPage, int pagesize, Object[] args) {

        return BaseDao.pageAll(sql, clazz, currentPage, pagesize, args);
    }


    @Override
    public Pager<T> pagelist(String sql, String currentPage, int pagesize) {

        return this.pagelist(sql, currentPage, pagesize, null);
    }


    @Override
    public Pager<T> pagelist(String sql, String currentPage, int pagesize, Object obj) {

        return this.pagelist(sql, currentPage, pagesize, new Object[]{obj});
    }


    @Override
    public int getTotal(String sql, Object[] args) {

        return BaseDao.executeScalare(sql, args);
    }


    @Override
    public int getTotal(String sql, Object object) {
        // TODO Auto-generated method stub
        return this.getTotal(sql, new Object[]{object});
    }


    @Override
    public int getTotal(String sql) {
        // TODO Auto-generated method stub
        return this.getTotal(sql, null);
    }


    @Override
    public int executeScalre(String sql) {
        return this.executeScalre(sql, null);
    }


    @Override
    public int executeScalre(String sql, Object object) {
        return this.executeScalre(sql, new Object[]{object});
    }


    @Override
    public int executeScalre(String sql, Object[] args) {
        return BaseDao.executeScalare(sql, args);
    }


}

4.5 用户实体类

@Data
public class User implements Serializable {
    private Integer id;
    private String username;
    private String password;
    private LocalDateTime create_time;
    private LocalDateTime update_time;
    private Integer is_del;
}

4.6 用户DAO

public interface UserDao extends  IGenericDao<User,Integer>{
    String FIND_USERS="SELECT * FROM t_user";
    String PAGE_USERS = "SELECT * FROM t_user ORDER BY id DESC LIMIT ?,? ";

    String DELETE_USER="UPDATE t_user SET is_del=1 WHERE id=?";
    String FIND_USER ="SELECT * FROM t_user WHERE id=?";
    String INSERT_USER ="INSERT INTO t_user(username,password,create_time,update_time,is_del) VALUES(?,?,now(),now(),0)" ;
    String UPDATE_USER = "UPDATE t_user SET username=?,password=?,update_time=now() WHERE id=?";
}
 UserDaoImpl
public class UserDaoImpl extends GenericDao<User,Integer> implements UserDao {
}

4.7业务

public interface UserService {

    /**
     * 用户列表
     * @return
     */
    List<User> findAll();
}

public class UserServiceImpl implements UserService {
    private UserDao userDao =new UserDaoImpl();
    @Override
    public List<User> findAll() {
        return userDao.findAll(UserDao.FIND_USERS);
    }
}

4.8 测试用户列表

@Test
public void testList(){
    UserService userService =new UserServiceImpl();
    userService.findAll().forEach(System.out::println);
}

4.9 用户Servlet

@WebServlet("/user")
public class UserServlet extends BaseServlet {


    public String userList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<User> users = this.userService.findAll();
        request.setAttribute("users",users);
        return PREFIX+"user_list"+SUFFIX;
    }
}

4.10 jsp页面

在WEB-INF下新增view目录,新建user_list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<html>
<head>
    <title>用户列表</title>
</head>
<body>
    <div>
        <table style="width: 80%;border: 1px;align-content: center" border="1">
            <thead>
               <tr>
                  <th>序号</th>
                  <th>账号</th>
                  <th>密码</th>
                  <th>创建时间</th>
                  <th>是否删除</th>
               </tr>
            </thead>
            <tbody>
            <c:forEach items="${users}" var="user">
            <tr>
                <td>${user.id}</td>
                <td>${user.username}</td>
                <td>${user.password}</td>
                <td>
                    ${user.create_time}
<%--                  <fmt:formatDate value="${user.create_time}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>--%>
                </td>
                <td>${user.is_del}</td>
            </tr>
            </c:forEach>
            </tbody>
        </table>
    </div>
</body>
</html>

4.11 添加bootstrap样式

 在WEB-INF/view下新建include.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <link rel="shortcut icon" href="#"/>
    <link rel="stylesheet" href="https://cdn.staticfile.net/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.net/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.net/bootstrap/3.3.7/js/bootstrap.min.js"></script>


</head>

user_list.jsp 页面head部分新增如下代码:

 <jsp:include page="include.jsp"/>

4.12 分页

4.12.1 新增分页业务
public class UserServiceImpl implements UserService {
    private UserDao userDao =new UserDaoImpl();
    @Override
    public List<User> findAll() {
        return userDao.findAll(UserDao.FIND_USERS);
    }

    @Override
    public Pager<User> pageUsers(String currentPage,Integer pagesize) {
        return this.userDao.pagelist(UserDao.PAGE_USERS,currentPage,pagesize);
    }
}
4.12.2 Servlet
@WebServlet("/user")
public class UserServlet extends BaseServlet {


    public String userList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String currentPage=request.getParameter("currentPage");
        Pager<User> pager= this.userService.pageUsers(currentPage,5);
        //注意:必须要设置url
        pager.setUrl("user?action=userList");
        request.setAttribute("pager",pager);
        return PREFIX+"user_list"+SUFFIX;
    }
}
4.12.3 jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<html>
<head>
    <title>用户列表</title>
     <jsp:include page="include.jsp"/>
</head>
<body>
    <div class="container">
        <table class="table table-hover table-bordered">
            <thead>
               <tr>
                  <th>序号</th>
                  <th>账号</th>
                  <th>密码</th>
                  <th>创建时间</th>
                  <th>是否删除</th>
                   <th>
                       <button class="btn btn-info">新增用户</button>
                   </th>
               </tr>
            </thead>
            <tbody>
            <c:forEach items="${pager.datas}" var="user">
            <tr>
                <td>${user.id}</td>
                <td>${user.username}</td>
                <td>${user.password}</td>
                <td>
                    ${user.create_time}
<%--                  <fmt:formatDate value="${user.create_time}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>--%>
                </td>
                <td>${user.is_del}</td>
                <td>
                    <button class="btn btn-warning">删除</button>
                    <button class="btn btn-primary">修改</button>
                </td>
            </tr>
            </c:forEach>
            <tr>
                <td colspan="10" align="center">
                    每页<select id="sel">
                    <c:forEach begin="5" end="20" step="5" var="i">
                        <option value="${i}" ${size==i ? 'selected':''}>${i}</option>
                    </c:forEach>
                </select>条。
                    ${pager.getItems()}
                    <input type="text" name="currentPage" size="2"> <input type="button" class="go" value="go">
                </td>
            </tr>

            </tbody>
        </table>
    </div>
</body>
</html>

五、删除用户

5.1 DAO

public interface UserDao extends  IGenericDao<User,Integer>{
    String DELETE_USER="UPDATE t_user SET is_del=1 WHERE id=?";
}

5.2 Service

public class UserServiceImpl implements UserService {
   
    @Override
    public boolean delete(int parseInt) {
        return this.userDao.delete(UserDao.DELETE_USER,parseInt) > 0;
    }
}

5.3 Servlet

   public void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String id=request.getParameter("id");
         boolean flag=this.userService.delete(Integer.parseInt(id));
        PrintWriter printWriter = response.getWriter();
        printWriter.print(flag);

    }

5.4 jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<html>
<head>
    <title>用户列表</title>
     //....
    <script>
       $(function(){

           //删除
           $(".btn-warning").click(function (){
               let id=$(this).val();
               alert(id);
               if(confirm("确认要删除编号是"+id+"的用户吗?")){
                   $.getJSON(
                       "user?action=delete",
                       {"id": id},
                       function (obj){
                           alert(typeof(obj));
                           if(obj){
                               alert("删除成功");
                               location.reload();
                           }else{
                               alert("删除失败!");
                           }
                       }
                   )
               }
           })
           $(".go").click(function (){
               let page=$("[name=currentPage]").val();
               $.get(
                   location.href="user?action=userList&currentPage="+page
               )
           })
       })
    </script>
</head>
<body>
    <div class="container">
        <table class="table table-hover table-bordered">
            <thead>
                ......

                    <button class="btn btn-warning" value="${user.id}">删除</button>
                   
               .......
</html>

六、新增

6.1 新增依赖

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.11.0</version>
</dependency>

6.2 对BeanUtils的封装

public class MyBeanUtil {

    public  static void copyProperties(User user, Map<String,String[]> map){
        try {
            BeanUtils.populate(user,map);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
}

6.3 DAO

public interface UserDao extends  IGenericDao<User,Integer>{
   
    String INSERT_USER ="INSERT INTO t_user(username,password,create_time,update_time,is_del) VALUES(?,?,now(),now(),0)" ;
}

6.4 Servlet

public String toAdd(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    return PREFIX+"add_user"+SUFFIX;
}

public String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Map<String, String[]> map = request.getParameterMap();
        User user=new User();
        MyBeanUtil.copyProperties(user,map);
        if(this.userService.add(user)) {
            return "redirect:userList";
        }else {
            request.setAttribute("msg","新增失败");
            return PREFIX+"add_user"+SUFFIX;
        }
}

6.5jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>新增用户</title>
  <jsp:include page="include.jsp"/>
    <script>
        $(function (){
            $(".btn-success").click(function (){
                $.getJSON(
                    "user?action=add",
                    $("form").serialize(),
                    function (obj){
                        alert(typeof(obj));
                        if(obj){
                            alert("新增成功!");
                            location="user?action=userList";
                        }else{
                            alert("新增失败!");
                        }
                    }
                )
            })


        })
    </script>
</head>
<body>
     <div class="container">
         <font color="red">${msg}</font>
          <br>
             <form>
              用户账号:<input name="username" type="text"><br>
              用户密码:<input type="password" name="password"><br>
              密码确认:<input type="password" name="password1"><br>
             </form>
         <button class="btn btn-success">注册</button>
         <button class="btn btn-primary">重置</button>
     </div>
</body>
</html>

七、修改

7.1 修改页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>修改用户</title>
  <jsp:include page="include.jsp"/>
    <script>
        $(function (){
            $(".btn-success").click(function (){
                $.getJSON(
                    "user?action=save",
                    $("form").serialize(),
                    function (obj){
                        if(obj){
                            alert("保存成功!");
                            location="user?action=userList";
                        }else{
                            alert("保存失败!");
                        }
                    }
                )
            })

        })
    </script>
</head>
<body>
     <div class="container">
         <font color="red">${msg}</font>
          <br>
             <form>
                 <input type="hidden" name="id" value="${user.id}">
              用户账号:<input name="username" type="text" value="${user.username}"><br>
              用户密码:<input type="text" name="password" value="${user.password}"><br>
             </form>
         <button class="btn btn-success">注册</button>
         <button class="btn btn-primary">重置</button>
     </div>
</body>
</html>

7.2 DAO

public interface UserDao extends  IGenericDao<User,Integer>{
    String FIND_USER ="SELECT * FROM t_user WHERE id=?";
    String UPDATE_USER = "UPDATE t_user SET username=?,password=?,update_time=now() WHERE id=?";
}

7.3 业务层

 @Override
    public User findUserById(int id) {
        return this.userDao.findObject(UserDao.FIND_USER,id);
    }

@Override
public boolean update(User user) {
    return this.userDao.update(UserDao.UPDATE_USER,user.getUsername(),user.getPassword(),user.getId()) > 0;
}

7.4 Servlet

public void save(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Map<String, String[]> map = request.getParameterMap();
    User user=new User();
    MyBeanUtil.copyProperties(user,map);
    boolean flag=false;
    if(Objects.isNull(user.getId())){
        //如果不存在id则执行新增
        flag=this.userService.add(user);
    }else{
        //如果id存在则还行保存
        flag=this.userService.update(user);
    }
    PrintWriter printWriter = response.getWriter();
    printWriter.print(flag);
    printWriter.close();
}
public String toUpdate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String sid = request.getParameter("id");
    int id =Integer.parseInt(sid);
    User user= this.userService.findUserById(id);
    if(Objects.nonNull(user)){
        request.setAttribute("user",user);
        return PREFIX+"update_user"+SUFFIX;
    }else{
        request.setAttribute("msg","未查询到用户");
        return  PREFIX+"userList"+SUFFIX;
    }
}

八、模态窗的使用

8.1 模块窗的使用

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP - Hello World</title>
    <link rel="shortcut icon" href="#"/>
    <link rel="stylesheet" href="https://cdn.staticfile.net/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.net/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.net/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<a href="hello-servlet">Hello Servlet</a>

<h2>创建模态框(Modal)</h2>
<!-- 按钮触发模态框 -->
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">开始演示模态框</button>
<!-- 模态框(Modal) -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title" id="myModalLabel">模态框(Modal)标题</h4>
            </div>
            <div class="modal-body">在这里添加一些文本</div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                <button type="button" class="btn btn-primary">提交更改</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal -->
</div>
</body>
</html>

8.2 新增和修改

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<html>
<head>
    <title>用户列表</title>
    <jsp:include page="include.jsp"/>
    <script src="${pageContext.request.contextPath}/js/user.js"></script>
</head>
<body>
    <div class="container">
        <table class="table table-hover table-bordered">
            <thead>
               <tr>
                  <th>序号</th>
                  <th>账号</th>
                  <th>密码</th>
                  <th>创建时间</th>
                  <th>是否删除</th>
                   <th>
                       <button class="btn btn-success" data-toggle="modal" data-target="#myModal">
                           添加
                       </button>

                       <button class="btn btn-info" onclick="location='user?action=export'">导出</button>
                   </th>
               </tr>
            </thead>
            <tbody>
            <c:forEach items="${pager.datas}" var="user">
            <tr>
                <td>${user.id}</td>
                <td>${user.username}</td>
                <td>${user.password}</td>
                <td>
                    ${user.create_time}
<%--                  <fmt:formatDate value="${user.create_time}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>--%>
                </td>
                <td>${user.is_del==0 ? '活动': '禁用'}</td>
                <td>

                    <button class="btn btn-warning" value="${user.id}">删除</button>
                    <button class="btn btn-info" data-toggle="modal" data-target="#myModal${user.id}">
                        修改
                    </button>
                </td>
                <div class="modal fade" id="myModal${user.id}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
                    <div class="modal-dialog">
                        <div class="modal-content">
                            <div class="modal-header">
                                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                                <h4 class="modal-title" id="myModalLabel">编辑用户</h4>
                            </div>
                            <form action="user?action=save" method="post">
                                <div class="modal-body">

                                    <input type="hidden" name="id" value="${user.id}">
                                        <%--                                         <input type="hidden" name="token" value="<%=System.currentTimeMillis()%>">--%>
                                    账号:<input type="text" name="username" value="${user.username}"><br>
                                    密码:<input type="text" name="password" value="${user.password}"><br>

                                </div>
                                <div class="modal-footer">
                                    <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                                    <button class="btn-success">提交</button>
                                </div>
                            </form>
                        </div><!-- /.modal-content -->
                    </div><!-- /.modal-dialog -->
                </div><!-- /.modal -->

            </tr>
            </c:forEach>
            <tr>
                <td colspan="10" align="center">
                    每页<select id="sel" name="pagesize">
                    <c:forEach begin="5" end="20" step="5" var="i">
                        <option value="${i}" ${pager.getPagesize() ==i ? 'selected':''}>${i}</option>
                    </c:forEach>
                </select>条。
                    ${pager.getItems()}
                    <input type="text" name="currentPage" size="2"> <input type="button" class="go" value="go">
                </td>
            </tr>

            </tbody>
        </table>
        <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                        <h4 class="modal-title" id="addModalLabel">新增用户</h4>
                    </div>
                    <form action="user?action=save" method="post">
                        <div class="modal-body">
                            账号:<input type="text" name="username" value="${user.username}"><br>
                            密码:<input type="text" name="password" value="${user.password}"><br>

                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                            <button class="btn-success">提交</button>
                        </div>
                    </form>
                </div><!-- /.modal-content -->
            </div><!-- /.modal-dialog -->
        </div><!-- /.modal -->
    </div>
</body>
</html>
8.3 修改Serlvet
package com.example.student.web.user;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.example.student.entity.User;
import com.example.student.util.MyBeanUtil;
import com.example.student.util.Pager;
import com.example.student.web.BaseServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author TonySong
 * @date 2025/8/7 0007
 * @time 19:57
 */
@WebServlet("/user")
public class UserServlet extends BaseServlet {


    public String userList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String size=request.getParameter("pagesize");
        size = size == null ? "5": size;
        Integer pagesize= Integer.parseInt(size);
        String currentPage=request.getParameter("currentPage");
        Pager<User> pager= this.userService.pageUsers(currentPage,pagesize);
        pager.setPagesize(pagesize);
        pager.setUrl("user?action=userList");
        request.setAttribute("pager",pager);
        return PREFIX+"user_list"+SUFFIX;
    }

    public void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String id=request.getParameter("id");
         boolean flag=this.userService.delete(Integer.parseInt(id));
        PrintWriter printWriter = response.getWriter();
        printWriter.print(flag);

    }

   
    public String save(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Map<String, String[]> map = request.getParameterMap();
        User user=new User();
        MyBeanUtil.copyProperties(user,map);
        boolean flag=false;
        if(Objects.isNull(user.getId())){
            //如果不存在id则执行新增
            flag=this.userService.add(user);
        }else{
            //如果id存在则还行保存
            flag=this.userService.update(user);
        }
        return flag ?  "redirect:userList" : "redirect:toAdd";
    }



}

九、数据导出

9.1 新增依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.18.0</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.4.1</version>
</dependency>

9.2 Servlet

public void export(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   //获取所有
    List<User> users = this.userService.findAll();
    ExcelWriter excelWriter = ExcelUtil.getWriter();
    excelWriter.write(users,true);
    response.setContentType("application/vnd.ms-excel;charset=utf-8");
    String fileName = null;
    try {
        fileName = URLEncoder.encode("员工信息", "UTF-8");
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e);
    }
    response.setHeader("Content-Disposition","attachment;filename="+fileName+".xlsx");
    ServletOutputStream out= null;
    try {
        out = response.getOutputStream();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    excelWriter.flush(out,true);
    excelWriter.close();
}

十、文件上传

10.1 Servlet

package com.example.student.web.user;

import cn.hutool.core.lang.UUID;
import com.example.student.web.BaseServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;

import java.io.IOException;

/**
 * @author TonySong
 * @date 2025/8/11 0011
 * @time 10:28
 */
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends BaseServlet {


    public String upload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Part part = request.getPart("pic");
        String fileName = UUID.fastUUID().toString(true);
        String name =part.getSubmittedFileName().substring(part.getSubmittedFileName().lastIndexOf(".")+1);
        fileName = fileName+"."+name;
        System.out.println(fileName);
        String realPath = request.getServletContext().getRealPath("/");
        System.out.println("服务器的路径是:"+realPath);
        part.write(realPath+"/upload/"+fileName);
        return fileName;
    }
}

10.1 jsp页面

<form action="upload?action=upload" enctype="multipart/form-data" method="post">
       <input type="file" name="pic">
       <input type="submit" value="上传">
   </form>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值