当前位置: 首页 > article >正文

实战指南:深度剖析Servlet+JSP+JDBC技术栈下的用户CRUD操作

本博客总结基于MVC(JSP+Servlet+JDBC)操作用户信息的CRUD(增删改查功能)的完整小项目。包括图片上传和回显,模糊查询,过滤器的登录校验和设置全局字符集以及监听器统计在线用户人数等额外功能,因为代码较多,我只解释思路和重点代码分析,其余代码我会放在资源中

完整项目结构分析

 创建一个JavaWeb项目,配置pom.xml和web.xml

pom.xml

需要注意:这里的smartupload组件的依赖包,是我手动导入本地仓库的,在中央仓库时不存在这个jar包的,直接导是导不进来的,可以查看我的smartupload相关的博客,有jar包提供和使用方式(这个组件的目的是为了简化文件上传和下载的操作,虽然已经停止更新,但是依然好用)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>servlet_CRUD_9_18</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>servlet_CRUD_9_18 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <!--junit单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!--jdbc连接mysql数据库-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.21</version>
    </dependency>
    <!--servlet-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!--lombok-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
      <scope>provided</scope>
    </dependency>
    <!--jstl-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <!--smartUpload-->
    <dependency>
      <groupId>smartupload</groupId>
      <artifactId>smartupload</artifactId>
      <version>1.0</version>
      <scope>system</scope>
      <systemPath>D:/maven/maven-3.9.9/repository/smartuplaod/smartupload/1.0/smartupload.jar</systemPath>
    </dependency>


  </dependencies>
  <build>
    <finalName>servlet_crud</finalName>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

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


      <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>9.3.14.v20161028</version>
      </plugin>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.1</version>
        <configuration>
          <port>8080</port>
          <path>/servlet_crud</path>
          <uriEncoding>UTF-8</uriEncoding>
          <server>tomcat7</server>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

web.xml

将web.xml的头声明,更新到3.0以上的目的是为了使用注解的方式映射servlet中的路径,进一步提供开发效率

<?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_3_1.xsd"
         version="3.1">
  <display-name>Archetype Created Web Application</display-name>

</web-app>

第二步:创建数据库表(用户表t_user)和对应的实体类User

用户表t_user

字段代表的含义:

用户id:用户的唯一标识

用户名

用户密码

用户照片:保存的是照片名字+后缀 

 

实体类User

引入了lombok注解,简化开发,省略了getter/setter方法的书写和全参无参构造的书写

package entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.io.Serializable;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class User implements Serializable {
    private Integer userId;
    private String userName;
    private String password;
    private String userPic;

    public User(Integer userId, String userName, String password) {
        this.userId = userId;
        this.userName = userName;
        this.password = password;
    }

    public User(String userName, String password, String userPic) {
        this.userName = userName;
        this.password = password;
        this.userPic = userPic;
    }
}

第三步:导入操作数据库的JDBC工具类DBUtil和分页工具类PageUtil

DBUtil

package dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class DBUtil {
    private final static String DRIVER="com.mysql.cj.jdbc.Driver";
    private final static String URL="jdbc:mysql://localhost:3306/csx_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull";
    private final static String DBNAME="root";
    private final static String DBPASS="root";

    public static Connection getConn(){
        Connection conn=null;
        try {
            Class.forName(DRIVER);
            conn= DriverManager.getConnection(URL,DBNAME,DBPASS);
        }catch (Exception e){
            e.printStackTrace();
        }
        return conn;
    }


    public static void closeAll(Connection conn, Statement st, ResultSet rs){
        try {
            if (rs!=null){
                rs.close();
            }
            if (st!=null){
                st.close();
            }
            if (conn!=null){
                conn.close();
            }

        }catch (Exception e){
            e.printStackTrace();
        }

    }

}

PageUtil

分页工具类的目的是计算出总页数,并且固定了每页显示的条数

package util;

public class PageUtil {
    public final static int PAGE_SIZE=3;   //每页显示的条数

    /**
     * 计算出总页数
     * @param count
     * @param pageSize
     * @return
     */
    public static int getTotalPages(int count,int pageSize){
        return count%pageSize==0?count/pageSize:count/pageSize+1;

    }
}

第四步:分析项目需求的SQL支持,书写DAO

因为需要完成若干需求,因此每个SQL都是有对应的意义的,我将逐个分析

 UserDao

为了实现分页功能(分页查询用户数据),我们需要分页查询用户列表的sql和查询用户总数的sql

对应接口方法:

  /**
     * 查看用户总条数
     * @return
     */
    int selectUsersCount();

    /**
     * 分页查询用户列表
     * @param pageIndex 当前页
     * @param pageSize 每页显示的条数
     * @param keyword 模糊搜索关键字
     * @return
     */
    List<User> selectUserListByPage(int pageIndex, int pageSize, String keyword);

对应的方法实现:我使用的是原生的jdbc实现,这里暂不展示源码,我会提供完整代码

为了实现新增用户功能需求,需要新增sql支持

对应接口方法: 

  /**
     * 新增用户
     * @param user
     * @return
     */
    public int insertUser(User user);

为了实现展示用户数据的需求,需要查询指定用户信息的sql支持

对应的接口方法:

    /**
     * 根据id查询指定用户信息
     * @param userId
     * @return
     */
    public User selectUserByUserId(int userId);

 为了实现删除用户信息的需求,需要删除sql的支持

对应的接口方法:

    /**
     * 根据id删除用户信息
     * @param userId
     * @return
     */
    public int deleteUserByUserId(int userId);

 为了实现更新用户信息的功能需求,需要修改的sql支持

对应的接口方法:

 /**
     * 修改用户数据
     * @param user
     * @return
     */
    public int updateUser(User user);

 想要完成在线用户统计的功能需求,需要根据用户名和密码查看指定用户是否存在的sql支持

对应的接口方法:

 /**
     * 根据用户名和密码查看指定用户是否存在
     * @param username
     * @param password
     * @return
     */
    public int selectUserByuserNameAndpassword(String username,String password);

 注意:这里都没有展示对应的接口方法的实现类中的方法。因为实现类中使用的连接数据库的技术可以随意替换,但是完成需求需要的sql支持是不变的,所以在实现功能时,优先考虑需求,然后才考虑用什么技术实现,本项目我使用的是原生的jdbc+封装的工具类实现sql,还可以使用JDBCTemplate和Mybats

 第五步:分析项目需求,书写前端页面

在webapp目录下,存放着当前项目所需要的html,jsp和图片资源等。

基本思路

  • 创建upfiles文件夹存放我们上传的图片资源
  • 创建front文件夹,里面存放的html,和jsp需要登录后才能查看(需要过滤器支持)
  • 在根目录下的login.jsp和onLineUser.jsp分别是登录首页和统计在线用户人数的页面,它们是不需要拦截的

 第六步:创建servlet接收前端发送的请求,并进行处理

整个项目的实现思路是:

  1. 拆分各个功能,一一进行实现
  2. 分析各个功能所需的sql支持,书写DAO
  3. 书写前端页面,展示数据发送请求
  4. 书写对应的servlet类处理请求,完成逻辑(转发请求或页面跳转)

 第七步:创建过滤器,完成字符集统一和登录校验

EncodingFilter

统一字符集为UTF-8

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*")
public class EncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request =(HttpServletRequest) servletRequest;
        HttpServletResponse response =(HttpServletResponse) servletResponse;
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }

}

LoginFilter

package filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter(urlPatterns = {"/front/*","/userPage"})
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取session
        HttpServletRequest request =(HttpServletRequest) servletRequest;
        HttpSession session = request.getSession();
        //从session中取出登录的时候存的登录信息
        String username = (String)session.getAttribute("username");
        //如果不为空,就放行
        if (username!=null){
            filterChain.doFilter(servletRequest,servletResponse);
        }else {
            request.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
        }
    }

    @Override
    public void destroy() {

    }
}

第八步:创建监听器,监听session,目的是为了统计在线用户数

OnLineUserListener

package listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.*;
import java.util.ArrayList;
import java.util.List;

@WebListener
public class OnLineUserListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {
    ServletContext application;
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        List<String> onLineUsers =new ArrayList<>();
        application = servletContextEvent.getServletContext();
        application.setAttribute("onLineUsers",onLineUsers);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }

    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        HttpSession session =httpSessionBindingEvent.getSession();
        String username =(String) session.getAttribute("username");
        List<String> onLineUsers=(List<String>) application.getAttribute("onLineUsers");
        onLineUsers.add(username);
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {

    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {

    }

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {

    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession session= httpSessionEvent.getSession();
        String username= (String) session.getAttribute("username");
        List<String> onLineUsers= (List<String>) application.getAttribute("onLineUsers");
        onLineUsers.remove(username);
    }
}

 项目演示

整个项目的逻辑就是,先写sql,然后写页面,最后在写servlet将sql和页面联系在一起

 登录

用户信息展示页面

包含了以下功能:

  • 顶部的模糊搜索功能
  • 新增用户功能
  • 点击用户信息展示用户详细信息的功能
  • 修改用户功能
  • 删除用户功能
  • 以及底部的分页查看功能

 项目源码已上传,个人原创资源共享,感谢支持,有问题可以问我!

资源名称(我的资源查看):基于Servlet+JSP+JDBC的完整的用户信息操作-CRUD项目总结


http://www.kler.cn/news/314544.html

相关文章:

  • 探秘 Web Bluetooth API:连接蓝牙设备的新利器
  • 828华为云征文|Flexus X实例GitLab部署构建流水线-私人一体化代码仓库~
  • AWS账号可以共用吗?
  • vue 中互相不关联的两个组件怎么进行通信(数据传输)
  • MFC获取网页的html文本
  • 视频V4改进
  • 锐捷 睿易路由器存在RCE漏洞
  • 会声会影2025视频剪辑教学
  • 开源集成开发环境搭建之VSCode安装部署教程
  • MySQL:基本查询操作
  • java计算机毕设课设—土地档案管理系统(附源码、文章、相关截图、部署视频)
  • 基于Java的SSM(Spring、Spring MVC、MyBatis)框架构建的远程诊断系统
  • 论文阅读 - MDFEND: Multi-domain Fake News Detection
  • 探索iPhone一键删除重复照片的方法
  • Kafka 为什么这么快?
  • 某乐指数爬虫逆向分析
  • Qemu开发ARM篇-2、uboot交叉编译
  • Android14 手机蓝牙配对后阻塞问题解决
  • python 自动化测试接口
  • 递归快速获取机构树型图
  • 【赵渝强老师】基于ZooKeeper实现Hadoop HA
  • DELPHI编译软件时带上当前IDE的版本号
  • 2024/9/21 leetcode 21.合并两个有序链表 2.两数相加
  • Hive企业级调优[5]—— HQL语法优化之数据倾斜
  • [Vue] 从零开始使用 Vite 创建 Vue 项目
  • webrtc gclient sync报错问题解决
  • 独孤思维:图书电商,又精进了
  • SwiftUI里的ForEach使用的注意事项
  • 某建筑市场爬虫数据采集逆向分析
  • Cartographer源码理解