目的:使用纯粹的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,点击取消返回false
var 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 {
@Override
protected 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 {
@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 = 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 {
@Override
protected 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 {
@Override
protected 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 {
@Override
protected 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 {
@Override
protected 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获取value
private 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法写一个单表的增删改查操作,后续还需要再进行改进!