JavaWeb|使用Servlet完成单表的CRUD



  • 实现步骤
    • 第一步:准备一张数据库表。(sql脚本)
    • 第二步:准备一套HTML页面(项目原型)【前端开发工具使用HBuilder】
    • 第三步:分析我们这个系统包括哪些功能
    • 第四步:在IDEA当中搭建开发环境
    • 第五步:实现第一个功能:查看部门列表
    • 第六步:查看部门详情。
    • 第七步:删除部门
  • 第九步:跳转到修改部门的页面
  • 第十步:修改部门

使用纯粹的Servlet完成单表【对部门的】的增删改查操作。(B/S结构的。)
实现步骤 第一步:准备一张数据库表。(sql脚本) 部门表
drop table if exists dept; create table dept( deptno int primary key, dname varchar(255), loc varchar(255) ); insert into dept(deptno, dname, loc) values(10, 'XiaoShouBu', 'BEIJING'); insert into dept(deptno, dname, loc) values(20, 'YanFaBu', 'SHANGHAI'); insert into dept(deptno, dname, loc) values(30, 'JiShuBu', 'GUANGZHOU'); insert into dept(deptno, dname, loc) values(40, 'MeiTiBu', 'SHENZHEN'); commit; select * from dept; +--------+------------+-----------+ | deptno | dname| loc| +--------+------------+-----------+ |10 | XiaoShouBu | BEIJING| |20 | YanFaBu| SHANGHAI| |30 | JiShuBu| GUANGZHOU | |40 | MeiTiBu| SHENZHEN| +--------+------------+-----------+

第二步:准备一套HTML页面(项目原型)【前端开发工具使用HBuilder】
  • 把HTML页面准备好
  • 然后将HTML页面中的链接都能够跑通。(页面流转没问题。)然后,具体哪一些数据是动态的,哪一些是静态的,到时候再分析
  • 应该设计哪些页面呢?
    • 欢迎页面:index.html
    • 列表页面:list.html(以列表页面为核心,展开其他操作。)
    • 新增页面:add.html
    • 修改页面:edit.html
    • 详情页面:detail.html
欢迎页面:
欢迎使用oa系统 - 锐客网 查看部门列表

JavaWeb|使用Servlet完成单表的CRUD
文章图片

列表页面:
部门列表页面 - 锐客网 部门列表
序号 部门编号 部门名称 操作
1 10 销售部 删除 修改 详情
2 20 研发部 删除 修改 详情
3 30 运营部 删除 修改 详情
新增部门

JavaWeb|使用Servlet完成单表的CRUD
文章图片

目前页面都是写死的,后续的话,需要动态获取数据,比如说,我们在销售部那里点击修改,那么跳出的数据,部门名称就应该是销售部,点击哪一个部门,显示就应该是哪一个部门。这些值都是通过数据库查出来的,动态展示
修改部门的时候,部门编号是不能修改的,因为我们修改数据的时候,是通过部门编号作为筛选条件,来进行修改的
新增页面:
新增部门 - 锐客网
部门编号
部门名称
部门位置


JavaWeb|使用Servlet完成单表的CRUD
文章图片

修改页面:
修改部门 - 锐客网
部门编号
部门名称
部门位置


JavaWeb|使用Servlet完成单表的CRUD
文章图片

详情页面:
部门详情 - 锐客网 部门详情部门编号:20
部门名称:销售部
部门位置:北京

JavaWeb|使用Servlet完成单表的CRUD
文章图片

第三步:分析我们这个系统包括哪些功能
  • 什么叫做一个功能呢?
    • 只要 这个操作连接了数据库,就表示一个独立的功能。
  • 包括哪些功能?
    • 查看部门列表
    • 新增部门
    • 删除部门
    • 查看部门详细信息
    • 跳转到修改页面
    • 修改部门
第四步:在IDEA当中搭建开发环境
  • 创建一个webapp(给这个webapp添加servlet-api.jar和jsp-api.jar到classpath当中。)
  • 向webapp中添加连接数据库的jar包(mysql驱动)
    • 必须在WEB-INF目录下新建lib目录,然后将mysql的驱动jar包拷贝到这个lib目录下。这个目录名必须叫做lib,全部小写的。
  • JDBC的工具类
package com.bjpowernode.oa.utils; import java.sql.*; import java.util.ResourceBundle; /**JDBC工具类 * @author zengyihong * @create 2022--03--10 20:21 */ public class DBUtils { //静态变量,在类加载时执行,自上而下的顺序 //根据属性配置文件的key获取value private static ResourceBundle boundle=ResourceBundle.getBundle("resources.jdbc"); private static String driver=boundle.getString("driver"); private static String url=boundle.getString("url"); private static String user=boundle.getString("user"); private static String password=boundle.getString("password"); static { try { //连接数据库的驱动,不能写死,以后可能连接其他数据库,比如Oracle //OCP开闭原则:对扩展开放,对修改关闭(功能扩展的时候,不需要修改Java源代码) //Class.forName("com.mysql.jdbc.Driver"); Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); }}/** * 注册驱动只需要一次,可以使用静态代码块 */ public staticConnection getConnection() throws SQLException { Connection conn= DriverManager.getConnection(url,user,password); return conn; }/** * 释放资源 * @param conn 连接对象 * @param ps数据库操作对象 * @param rs结果集对象 */ public static void close(Connection conn, Statement ps, ResultSet rs){if (rs !=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } try { if (ps !=null){ ps.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (rs !=null){ rs.close(); } } catch (SQLException e) { e.printStackTrace(); } }}

  • 将所有HTML页面拷贝到web目录下。
第五步:实现第一个功能:查看部门列表
  • 我们应该怎么去实现一个功能呢?
    • 建议:你可以从后端往前端一步一步写。也可以从前端一步一步往后端写。都可以。但是千万要记住不要想起来什么写什么。你写代码的过程最好是程序的执行过程。也就是说:程序执行到哪里,你就写哪里。这样一个顺序流下来之后,基本上不会出现什么错误、意外。
    • 从哪里开始?
      • 假设从前端开始,那么一定是从用户点击按钮那里开始的。
      • 第一:先修改前端页面的超链接,因为用户先点击的就是这个超链接。
      • 因为查看部门列表是要和数据库进行交互的,里面的数据不能是写死的,要实时更新数据,所以需要执行一个Java程序
        查看部门列表
  • 第二:编写web.xml文件
> >list >com.bjpowernode.oa.web.action.DeptListServlet > >list/dept/list

  • 第三:编写DeptListServlet类继承HttpServlet类。然后重写doGet方法。
  • 因为点击超链接是get请求
  • 再来回忆一下通信原理
    JavaWeb|使用Servlet完成单表的CRUD
    文章图片
package com.bjpowernode.oa.web.action; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; public class DeptListServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }

  • 第四:在DeptListServlet类的doGet方法中连接数据库,查询所有的部门,动态的展示部门列表页面.
  • 分析list.html页面中哪部分是固定死的,哪部分是需要动态展示的。
  • list.html页面中的内容所有的双引号要替换成单引号,因为out.print("")这里有一个双引号,容易冲突。
  • 现在写完这个功能之后,你会有一种感觉,感觉开发很繁琐,只使用servlet写代码太繁琐了。
public class DeptListServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取应用的根路径 String contextPath = request.getContextPath(); response.setContentType("text/html; charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.println(" "); writer.println(""); writer.println(""); writer.println(" "); writer.println(" 部门列表页面 - 锐客网"); writer.println(""); writer.println(""); writer.println("部门列表"); writer.println(""); writer.println(""); writer.println(""); writer.println(" "); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println(" "); /** * 要分析页面哪些部分是静态的,哪些部分是动态的 */ //连接数据库,查询所有数据 Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { //获取连接 conn= DBUtils.getConnection(); //获取预编译的数据库操作对象 String sql="select deptno,dname,loc from dept"; ps = conn.prepareStatement(sql); //执行sql语句 rs=ps.executeQuery(); //处理结果集 int i=0; while (rs.next()){ String deptno=rs.getString("deptno"); String dname = rs.getString("dname"); String loc = rs.getString("loc"); writer.println(" "); writer.println(""); writer.println(""); writer.println(""); writer.println(""); writer.println(" "); }} catch (SQLException e) { e.printStackTrace(); }finally { //释放资源 DBUtils.close(conn,ps,rs); } // writer.println("
序号部门编号部门名称操作
"+(++i)+""+deptno+""+dname+"删除"); writer.println("修改"); /** * 点击详情的时候,我们点击哪一个部门,就应该显示相应部门的信息 */ writer.println("详情
"); writer.println("新增部门"); writer.println(""); writer.println(""); writer.println(""); writer.println(""); }}

先来回顾一下,之前准备数据库中的表的数据
+--------+------------+-----------+ | deptno | dname| loc| +--------+------------+-----------+ |10 | XiaoShouBu | BEIJING| |20 | YanFaBu| SHANGHAI| |30 | JiShuBu| GUANGZHOU | |40 | MeiTiBu| SHENZHEN| +--------+------------+-----------+

JavaWeb|使用Servlet完成单表的CRUD
文章图片

JavaWeb|使用Servlet完成单表的CRUD
文章图片

写这个小功能的体会:我们可以先写出静态页面,然后根据这个页面来分析,哪些部分是需要动态展示的,也就是要和数据库连接的,哪些部分是固定死的,再根据我们的分析去操作,这样思路会比较清晰,不然的话,可能东写一个,西写一个,最后自己都乱了。
第六步:查看部门详情。
  • 建议:从前端往后端一步一步实现。首先要考虑的是,用户点击的是什么?用户点击的东西在哪里?
    • 一定要先找到用户点的“详情”在哪里。找了半天,终于在后端的java程序中找到了
详情

    • 详情 是需要连接数据库的,所以这个超链接点击之后也是需要执行一段java代码的。所以要将这个超链接的路径修改一下。
    • 注意:修改路径之后,这个路径是需要加项目名的。"/oa/dept/detail"
  • 技巧:
  • out.print("详情");
  • 重点:向服务器提交数据的格式:uri?name=value&name=value&name=value&name=value
    • 这里的问号,必须是英文的问号。不能中文的问号。
  • 解决404的问题。写web.xml文件。
> >detail >com.bjpowernode.oa.web.action.DeptDetailServlet > >detail /dept/detail

编写一个类:DeptDetailServlet继承HttpServlet,重写doGet方法。
中文思路(思路来源于:你要做什么?目标:查看部门详细信息。) 第一步:获取部门编号 第二步:根据部门编号查询数据库,获取该部门编号对应的部门信息。 第三步:将部门信息响应到浏览器上。(显示一个详情。)

package com.bjpowernode.oa.web.action; import com.bjpowernode.oa.utils.DBUtils; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * @author zengyihong * @create 2022--03--11 19:14 */ public class DeptDetailServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.println(""); writer.println(""); writer.println(" "); writer.println(""); writer.println("部门详情 - 锐客网"); writer.println(" "); writer.println(" "); writer.println("部门详情"); writer.println(""); //获取部门编号 // /oa/dept/detail?deptno=30 //显然提交的是30,但是服务器获取的是30这个字符串 String deptno = request.getParameter("deptno"); //连接数据库,根据相关部门来查询部门信息 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; //部门编号是主键,所以查询出来的记录最多就一条 try { conn = DBUtils.getConnection(); String sql = "select dname,loc from dept where deptno=?"; ps = conn.prepareStatement(sql); ps.setString(1, deptno); rs = ps.executeQuery(); if (rs.next()) { String dname = rs.getString("dname"); String loc = rs.getString("loc"); writer.println("部门编号:" + deptno + "
"); writer.println("部门名称:" + dname + "
"); writer.println("部门位置:" + loc + "
"); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtils.close(conn, ps, rs); } writer.println(""); writer.println(" "); writer.println(""); }}

接下来,看看效果
JavaWeb|使用Servlet完成单表的CRUD
文章图片

JavaWeb|使用Servlet完成单表的CRUD
文章图片

点击后退
JavaWeb|使用Servlet完成单表的CRUD
文章图片

JavaWeb|使用Servlet完成单表的CRUD
文章图片

可以看出,点击不同部门的详情,就会对应相应的信息
如果程序出现错误,显示4开头的错误代码,一般是前端代码问题,如果是5开头的错误代码,一般是Java程序出现问题
第七步:删除部门
  • 怎么开始?从哪里开始?从前端页面开始,用户点击删除按钮的时候,应该提示用户是否删除。因为删除这个动作是比较危险的。任何系统在进行删除操作之前,是必须要提示用户的,因为这个删除的动作有可能是用户误操作。(在前端页面上写JS代码,来提示用户是否删除。)
删除 type="text/javascript"> function del(dno){ //弹出确认框,用户点击确定,返回true,点击取消,返回false var ok=window.confirm("亲,删了不可恢复哦"); //在JS代码中如何发送请求给服务器 //四种写法都可以 //document.location.href="https://www.it610.com/article/请求路径"; // document.location="请求路径"; //window.location.href="https://www.it610.com/article/请求路径"; //window.location="请求路径"; //我们在点击删除的时候,要把删除哪一个部门的编号传进去 document.location.href="https://www.it610.com/oa/dept/delete?deptno="+dno; }

  • 以上的前端程序要写到后端的java代码当中:
    • DeptListServlet类的doGet方法当中,使用out.print()方法,将以上的前端代码输出到浏览器上。
  • 解决404的问题:
    • http://localhost:8080/oa/dept/delete?deptno=30
    • web.xml文件
> >delete >com.bjpowernode.oa.web.action.DeptDelServlet > >delete /dept/delete

编写DeptDelServlet继承HttpServlet,重写doGet方法。
package com.bjpowernode.oa.web.action; import com.bjpowernode.oa.utils.DBUtils; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * @author zengyihong * @create 2022--03--12 11:33 */ public class DeptDeleteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //根据部门编号,删除部门 //获取部门编号 String deptno = request.getParameter("deptno"); //连接数据库删除数据 Connection conn=null; PreparedStatement ps=null; int count=0; try { conn= DBUtils.getConnection(); //关闭自动提交,就是开启事务 conn.setAutoCommit(false); String sql="delete from dept where deptno =?"; ps=conn.prepareStatement(sql); ps.setString(1,deptno); //返回的是影响数据库表中多少条记录 count = ps.executeUpdate(); conn.commit(); } catch (SQLException e) { //遇到异常要回滚 if (conn !=null){ try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); }finally { DBUtils.close(conn,ps,null); }if (count == 1){ //删除成功 //仍然跳转到部门列表页面 //部门列表页面的显示需要执行另外一个Servlet,怎么办?转发 request.getRequestDispatcher("/dept/list").forward(request,response); }else { request.getRequestDispatcher("/error.html").forward(request,response); }} }

删除成功或者失败的时候的一个处理(这里我们选择了转发,并没有使用重定向机制。)
// 判断删除成功了还是失败了。 if (count == 1) { //删除成功 //仍然跳转到部门列表页面 //部门列表页面的显示需要执行另一个Servlet。怎么办?转发。 request.getRequestDispatcher("/dept/list").forward(request, response); }else{ // 删除失败 request.getRequestDispatcher("/error.html").forward(request, response); }

  • 第八步:新增部门
    • 注意:最后保存成功之后,转发到 /dept/list 的时候,会出现405,为什么?
      • 第一:保存用的是post请求。底层要执行doPost方法。
      • 第二:转发是一次请求,之前是post,之后还是post,因为它是一次请求。
      • 第三:/dept/list Servlet当中只有一个doGet方法。
      • 怎么解决?两种方案
        • 第一种:在/dept/list Servlet中添加doPost方法,然后在doPost方法中调用doGet。
        • 第二种:重定向。
        • JavaWeb|使用Servlet完成单表的CRUD
          文章图片

          JavaWeb|使用Servlet完成单表的CRUD
          文章图片

          JavaWeb|使用Servlet完成单表的CRUD
          文章图片
第九步:跳转到修改部门的页面
package com.bjpowernode.oa.web.action; import com.bjpowernode.oa.utils.DBUtils; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class DeptEditServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 获取应用的根路径。 String contextPath = request.getContextPath(); response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.print(""); out.print(""); out.print(" "); out.print(""); out.print("修改部门 - 锐客网"); out.print(" "); out.print(" "); out.print("修改部门"); out.print(""); out.print("
"); // 获取部门编号 String deptno = request.getParameter("deptno"); // 连接数据库,根据部门编号查询部门的信息。 Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtils.getConnection(); String sql = "select dname, loc as location from dept where deptno = ?"; ps = conn.prepareStatement(sql); ps.setString(1, deptno); rs = ps.executeQuery(); // 这个结果集中只有一条记录。 if(rs.next()){ String dname = rs.getString("dname"); String location = rs.getString("location"); // 参数"location"是sql语句查询结果列的列名。 // 输出动态网页。 out.print("部门编号
"); out.print("部门名称
"); out.print("部门位置
"); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtils.close(conn, ps, rs); }out.print("
"); out.print("
"); out.print(" "); out.print(""); }@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }

第十步:修改部门
package com.bjpowernode.oa.web.action; import com.bjpowernode.oa.utils.DBUtils; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * @author zengyihong * @create 2022--03--13 8:35 */ public class DeptModifyServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//解决请求体的乱码问题 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8"); //获取表单数据 String deptno = request.getParameter("deptno"); String dname = request.getParameter("dname"); String loc = request.getParameter("loc"); //连接数据库,执行更新语句 Connection conn = null; PreparedStatement ps = null; int count=0; try { conn = DBUtils.getConnection(); String sql = "update dept set dname=?,loc=? where deptno=? "; ps = conn.prepareStatement(sql); ps.setString(1, dname); ps.setString(2, loc); ps.setString(3, deptno); count = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtils.close(conn, ps, null); }if (count==1){ //更新成功 //跳到列表页面 部门列表页面是通过Java程序动态生成的,需要请求转发,所以需要执行另外一个servlet request.getRequestDispatcher("/dept/list").forward(request,response); }else{ request.getRequestDispatcher("/error.html").forward(request,response); }}}

JavaWeb|使用Servlet完成单表的CRUD
文章图片

JavaWeb|使用Servlet完成单表的CRUD
文章图片

JavaWeb|使用Servlet完成单表的CRUD
文章图片

JavaWeb|使用Servlet完成单表的CRUD
文章图片

JavaWeb|使用Servlet完成单表的CRUD
文章图片

【JavaWeb|使用Servlet完成单表的CRUD】大家还是需要自己动手练习
这里使用的是纯粹的Servlet技术,比较麻烦,后续还会改造一下这个小项目

    推荐阅读