Javaweb实操(一)—Servlet实现单表的CRUD操作
目的:使用纯粹的Servlet完成单表对部门信息的增删改查操作。(B/S结构)
实现步骤:
step1:准备一张数据库表。(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,'销售部','北京');
insert into dept(deptno,dname,loc) values(20,'技术部','上海');
insert into dept(deptno,dname,loc) values(30,'开发部','广州');
insert into dept(deptno,dname,loc) values(40,'宣传部','深圳');
insert into dept(deptno,dname,loc) values(50,'管培生','河南');
commit;
select * from dept;
step2:准备一套HTML页面(项目原型)【前端开发工具使用HBuilder】
- 把HTML页面准备好
- 然后将HTML页面中的连接都能跑通,页面流转没有问题。
- 应该设计哪些页面呢?
- (1)欢迎页面:index.html
- (2)列表页面:list.html(以列表页面为核心,展开其他操作)
- (3)新增页面:add.html
- (4)修改页面:edit.html
- (5)详情页面:detail.html
欢迎页面
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>欢迎使用OA系统</title></head><body><a href="list.html">查看部门列表</a></body>
</html>
部门列表
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>部门列表页面</title></head><body><script type="text/javascript">function del(dno){// 弹出确认框,用户点击确定,返回true,点击取消返回falsevar ok = window.confirm("亲,删了不可恢复!");if(ok){// 在发送请求进行删除数据的操作。// 在JS代码当中如何发送请求给服务器?// alert("正在删除数据,请稍后...");document.location.href="请求路径";document.location="请求路径";window.location.href="请求路径";window.location="请求路径";document.location.href="/oa/dept/delete?deptno="+dno;}}</script><h1 align="center">部门列表</h1><hr ><table border="1px" align="center" width="50%"><tr><th>序号</th><th>部门编号</th><th>部门名称</th><th>具体操作</th></tr><tr><td>1</td><td>10</td><td>销售部</td><td><!-- href后面设置为javascript:void(0)表示仍然保留住超链接的样子 --><!-- 点击此超链接之后,不进行页面的跳转 --><!-- 我只是希望用户点击该超链接的时候执行一段JS代码,不进行页面的跳转 --><a href="javascript:void(0)" onclick="del(10)">删除</a><a href="edit.html">修改</a><a href="detail.html">详情</a></td></tr><tr><td>2</td><td>20</td><td>技术部</td><td><a href="javascript:void(0)" onclick="del(20)">删除</a><a href="edit.html">修改</a><a href="detail.html">详情</a></td></tr><tr><td>3</td><td>30</td><td>开发部</td><td><a href="javascript:void(0)" onclick="del(30)">删除</a><a href="edit.html">修改</a><a href="detail.html">详情</a></td></tr><tr><td>4</td><td>40</td><td>宣传部</td><td><a href="javascript:void(0)" onclick="del(40)">删除</a><a href="edit.html">修改</a><a href="detail.html">详情</a></td></tr><tr><td>5</td><td>50</td><td>管培生</td><td><a href="javascript:void(0)" onclick="del(50)">删除</a><a href="edit.html">修改</a><a href="detail.html">详情</a></td></tr></table><hr ><a href="add.html">新增部门</a></body>
</html>
新增部门
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>新增部门</title></head><body><h1>新增部门</h1><hr ><form action="dept/add" method="post">部门编号<input type="text" name="deptno"/><br>部门名称<input type="text" name="dname"/><br>部门位置<input type="text" name="loc"/><br><input type="submit" value="保存"/><br></form></body>
</html>
修改部门信息
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>修改部门</title></head><body><h1>修改部门</h1><hr ><form action="list.html" method="get">部门编号<input type="text" name="deptno" value="20" readonly/><br>部门名称<input type="text" name="dname" value="开发部"></br>部门位置<input type="text" name="loc" value="上海"></br><input type="submit" value="修改"/><br></form></body>
</html>
部门详情页
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>部门详情</title></head><body><h1>部门详情</h1><hr >部门编号:20<br>部门名称:技术部<br>部门位置:上海<br><input type="button" value="后退" onclick="window.history.back()"/></body>
</html>
打开浏览器,查看效果,基本的效果有了,就需要进行数据的交互。
step3:分析我们这个系统包括哪些功能?
什么叫做一个功能呢?只要这个操作连接了数据库,就表示一个独立的功能。
包括哪些功能?
- 查看部门列表
- 新增部门
- 删除部门
- 查看部门详细信息
- 跳转到修改页面
- 修改部门
step4:在idea工具中搭建开发环境
- 创建一个webapp
- 向webapp中添加连接数据库jar包
- JDBC的工具类
- 将所有HTML页面拷贝到web目录下
step5:实现第一个功能:查看部门列表
我们应该怎么实现一个功能呢?
建议:可以从后端往前端一步步写,也可以从前端往后端一步步写。写代码的过程最好是程序执行的过程,程序执行到哪,就写到哪。
- 假设从前端开始,那么一定是从用户点击按钮开始。
1. 先修改前端页面的超链接,因为用户先点击的就是这个超链接。
-
<a href="/oa/dept/list">查看部门列表</a>
2. 编写web.xml文件(配置正确的路径)
只有配置好路径,才能正确的跳转,不然你写的Servlet文件就失效了,因为你点击的时候根本不会跳转。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"version="6.0"><!--部门列表页面--><servlet><servlet-name>list</servlet-name><servlet-class>com.bjpowernode.javaweb.oa.web.action.DeptListServlet</servlet-class></servlet><servlet-mapping><servlet-name>list</servlet-name><url-pattern>/dept/list</url-pattern></servlet-mapping><!--删除部门信息--><servlet><servlet-name>delete</servlet-name><servlet-class>com.bjpowernode.javaweb.oa.web.action.DeptDeleteServlet</servlet-class></servlet><servlet-mapping><servlet-name>delete</servlet-name><url-pattern>/dept/delete</url-pattern></servlet-mapping><!--修改部门信息--><servlet><servlet-name>edit</servlet-name><servlet-class>com.bjpowernode.javaweb.oa.web.action.DeptEditServlet</servlet-class></servlet><servlet-mapping><servlet-name>edit</servlet-name><url-pattern>/dept/edit</url-pattern></servlet-mapping><servlet><servlet-name>modify</servlet-name><servlet-class>com.bjpowernode.javaweb.oa.web.action.DeptModifyServlet</servlet-class></servlet><servlet-mapping><servlet-name>modify</servlet-name><url-pattern>/dept/modify</url-pattern></servlet-mapping><!--部门详情页--><servlet><servlet-name>detail</servlet-name><servlet-class>com.bjpowernode.javaweb.oa.web.action.DeptDetailServlet</servlet-class></servlet><servlet-mapping><servlet-name>detail</servlet-name><url-pattern>/dept/detail</url-pattern></servlet-mapping><!--新增部门--><servlet><servlet-name>add</servlet-name><servlet-class>com.bjpowernode.javaweb.oa.web.action.DeptAddServlet</servlet-class></servlet><servlet-mapping><servlet-name>add</servlet-name><url-pattern>/dept/add</url-pattern></servlet-mapping>
</web-app>
3. 编写部门列表页(这个是我们操作的核心页面)
- 在编写这部分代码的时候,需要注意前端页面上的东西,哪些是固定不变的,哪些是需要动态变化的,最需要注意的就是有路径的地方,路径对了,才能正确地完成跳转。
package com.bjpowernode.javaweb.oa.web.action;
import com.bjpowernode.javaweb.oa.utils.DbUtil;
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 DeptListServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取应用的根路径String contextPath = request.getContextPath();System.out.println("当前路径是" + contextPath);// 设置响应的内容类型以及字符集。防止中文乱码问题。response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();out.print("<!DOCTYPE html>");out.print("<html>");out.print(" <head>");out.print(" <meta charset='utf-8'>");out.print(" <title>部门列表页面</title>");out.print(" <script type='text/javascript'>");out.print(" function del(dno){");out.print(" var ok = window.confirm('亲,删了不可恢复!');");out.print(" if(ok){");out.print(" document.location.href='"+contextPath+"/dept/delete?deptno='+dno");out.print(" }");out.print(" }");out.print(" </script>");out.print(" </head>");out.print(" <body>");out.print(" <h1 align='center'>部门列表</h1>");out.print(" <hr >");out.print(" <table border='1px' align='center' width='50%'>");out.print(" <tr>");out.print(" <th>序号</th>");out.print(" <th>部门编号</th>");out.print(" <th>部门名称</th>");out.print(" <th>具体操作</th>");out.print(" </tr>");
// 上面一部分是死的Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {// 获取连接conn = DbUtil.getConnection();// 获取预编译的数据库操作对象String sql = "select deptno,dname,loc from dept";ps = conn.prepareStatement(sql);// 执行SQL语句rs = ps.executeQuery();// 处理结果集int i = 1;while (rs.next()) {String deptno = rs.getString("deptno");String dname = rs.getString("dname");String loc = rs.getString("loc");out.print("<tr>");out.print(" <td>"+(i++)+"</td>");out.print(" <td>"+deptno+"</td>");out.print(" <td>"+dname+"</td>");out.print(" <td>");out.print(" <a href='javascript:void(0)' onclick='del("+deptno+")'>删除</a>");out.print(" <a href='"+contextPath+"/dept/edit?deptno="+deptno+"'>修改</a>");out.print(" <a href='"+contextPath+"/dept/detail?deptno="+deptno+"'>详情</a>");out.print(" </td>");out.print(" </tr>");out.print("");}} catch (SQLException e) {throw new RuntimeException(e);}finally{DbUtil.close(conn,ps,rs);}// 下面一部分是死的out.print(" </table>");out.print(" <hr >");out.print(" <a href='"+contextPath+"/add.html'>新增部门</a>");out.print(" </body>");out.print("</html>");}
}
4. 核心页面编写完之后,可以有这样的效果,下面就是实现删除,修改,详情和新增功能了。
5. 实现删除功能。
用户点击删除按钮的时候,应该提示用户是否删除,因为删除这个动作是比较危险的。任何系统在进行删除操作之前,是必须要提示用户的,因为这个删除的动作有可能是用户误操作。
package com.bjpowernode.javaweb.oa.web.action;
import com.bjpowernode.javaweb.oa.utils.DbUtil;
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;
public class DeptDeleteServlet extends HttpServlet {@Overrideprotected 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 = DbUtil.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) {e.printStackTrace();}finally{DbUtil.close(conn,ps,null);}// 判断删除成功了还是失败了if(count == 1){// 删除成功,仍然跳转到部门列表页面// 部门列表页面的显示需要执行另一个Servlet。可以用转发,也可以用重定向的方式// (转发)request.getRequestDispatcher(request.getContextPath() + "/dept/list").forward(request,response);// 重定向response.sendRedirect(request.getContextPath()+"/dept/list");}else{//删除失败
// (转发)request.getRequestDispatcher("error.html").forward(request,response);// 重定向response.sendRedirect(request.getContextPath()+"/error.html");}}
}
删除成功
6. 实现修改功能
- 用户点击修改,出来以下页面,进行部门名称和部门位置的改变,其中部门编号是不变的(因为我们设置了只读方式)。在没有编辑部门信息之前,页面保持原来部门信息。
package com.bjpowernode.javaweb.oa.web.action;import com.bjpowernode.javaweb.oa.utils.DbUtil;
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 {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取应用的根路径System.out.println("跳进去了");String contextPath = request.getContextPath();response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();out.print("<!DOCTYPE html>");out.print("<html>");out.print(" <head>");out.print(" <meta charset='utf-8'>");out.print(" <title>修改部门</title>");out.print(" </head>");out.print(" <body>");out.print(" <h1>修改部门</h1>");out.print(" <hr >");out.print(" <form action='"+contextPath+"/dept/modify' method='post'>");// 获取部门编号String deptno = request.getParameter("deptno");// 连接数据库,根据部门编号查询部门的信息Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = DbUtil.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");// 输出动态网页out.print("部门编号<input type='text' name='deptno' value='"+deptno+"' readonly/><br>");out.print(" 部门名称<input type='text' name='dname' value='"+dname+"'></br>");out.print(" 部门位置<input type='text' name='loc' value='"+loc+"'></br>");}} catch (SQLException e) {e.printStackTrace();}finally{DbUtil.close(conn,ps,rs);}out.print(" <input type='submit' value='修改'/><br>");out.print(" </form>");out.print(" </body>");out.print("</html>");}
}
- 修改完信息之后,点击提交,需要又一次进行sql语句
package com.bjpowernode.javaweb.oa.web.action;import com.bjpowernode.javaweb.oa.utils.DbUtil;
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;public class DeptModifyServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 解决请求体的中文乱码问题request.setCharacterEncoding("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 = DbUtil.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{DbUtil.close(conn,ps,null);}if(count == 1){// 更新成功// 跳转到部门列表页面(部门列表页面是通过java程序动态生成的,所以还需要再执行另一个Servlet)
// request.getRequestDispatcher("/dept/list").forward(request,response);response.sendRedirect(request.getContextPath()+"/dept/list");}else{// 更新失败
// request.getRequestDispatcher("/error.html").forward(request,response);response.sendRedirect(request.getContextPath()+"/error.html");}}
}
修改成功
7. 实现详情功能,点开详情页,用户可以看见部门的详细信息
package com.bjpowernode.javaweb.oa.web.action;
import com.bjpowernode.javaweb.oa.utils.DbUtil;
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 DeptDetailServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();String deptno = request.getParameter("deptno");out.print("<!DOCTYPE html>");out.print("<html>");out.print(" <head>");out.print(" <meta charset='utf-8'>");out.print(" <title>部门详情</title>");out.print(" </head>");out.print(" <body>");out.print(" <h1>部门详情</h1>");out.print(" <hr >");Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try {conn = DbUtil.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");out.print("部门编号:"+deptno+"<br>");out.print(" 部门名称:"+dname+"<br>");out.print(" 部门位置:"+loc+"<br>");}} catch (SQLException e) {e.printStackTrace();}finally{DbUtil.close(conn,ps,rs);}out.print(" <input type='button' value='后退' onclick='window.history.back()'/>");out.print(" </body>");out.print("</html>");}
}
8. 实现新增功能,输入部门编号,部门名称和部门位置,并保存,可以实现部门信息的增加。
package com.bjpowernode.javaweb.oa.web.action;
import com.bjpowernode.javaweb.oa.utils.DbUtil;
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;public class DeptAddServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获取部门的信息// 解决乱码问题(Tomcat10不会出现这个问题)request.setCharacterEncoding("UTF-8");String deptno = request.getParameter("deptno");String dname = request.getParameter("dname");String loc = request.getParameter("loc");// 连接数据库执行insert语句Connection conn = null;PreparedStatement ps = null;int count = 0;try {conn = DbUtil.getConnection();String sql = "insert into dept(deptno,dname,loc) values(?,?,?)";ps = conn.prepareStatement(sql);ps.setString(1,deptno);ps.setString(2,dname);ps.setString(3,loc);count = ps.executeUpdate();} catch (SQLException e) {e.printStackTrace();}finally {DbUtil.close(conn,ps,null);}if(count == 1){//新增成功response.sendRedirect(request.getContextPath()+"/dept/list");}else{// 新增失败response.sendRedirect(request.getContextPath()+"/error.html");}}
}
9. 当新增、修改、删除失败时候,error.html具体内容是:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>error</title>
</head>
<body>
<h1>操作失败,<a href="javascript:void(0)"onclick="window.history.back()">返回</a></h1>
</body>
</html>
10 在使用jdbc连接数据库的时候,需要做的前提准备:
配置一个属性配置文件,实现OCP原则!
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/bjpowernode
username=root
password=1234
再用DbUtil类进行封装
package com.bjpowernode.javaweb.oa.utils;import java.sql.*;
import java.util.ResourceBundle;public class DbUtil {// 属性资源文件绑定private static ResourceBundle bundle = ResourceBundle.getBundle("resources.jdbc");// 如果properties文件在src目录下,直接写文件名;如果在子文件夹,比如resources,则写resources.jdbc// 根据属性配置文件key获取valueprivate static String driver = bundle.getString("driver");private static String url = bundle.getString("url");private static String username = bundle.getString("username");private static String password = bundle.getString("password");// 静态代码块:在类加载时执行,通常用于初始化操作static {// 注册驱动try {Class.forName(driver);} catch (ClassNotFoundException e) {e.printStackTrace();}}// 获取数据库连接public static Connection getConnection() throws SQLException {Connection conn = DriverManager.getConnection(url, username, password);return conn;}// 释放资源public static void close(Connection conn, Statement ps, ResultSet rs){if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (ps != null) {try {ps.close();} catch (SQLException e) {e.printStackTrace();}}if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}}
}
这就是用纯Servlet法写一个单表的增删改查操作,后续还需要再进行改进!