使用纯Servlet做一个单表的CRUD操作
- 实现步骤
- 第一步:准备一张数据库表(sql脚本/可视化工具)
- 第二步:准备一套HTML页面(页面原型)【前端开发工具使用vscode / IDEA】
- 第三步:分析我们这个系统包括哪些功能?
- 第四步:在IDEA当中搭建开发环境以及数据库配置
- 第五步:动态实现每个功能
- 查看部门列表
- 查看部门详情
- 删除部门
- 新增部门
- 跳转到修改部门的页面
- 修改部门
- 将oa项目中的资源跳转修改为合适的跳转方式(优化)
使用纯粹的Servlet完成单表【对部门的】的增删改查操作。(B/S结构)
该操作方法的问题所在:
- 若使用jsp简化代码
- 若使用重定向,优势更大
实现步骤
第一步:准备一张数据库表(sql脚本/可视化工具)
drop table if exists dept;
# 部门表
create table dept(
deptno int primary key,
dename varchar(255),
loc varchar(255)
);
# 添加数据
insert into dept(deptno, dename, loc) values(10, 'XiaoShouBu', 'BEIJING');
insert into dept(deptno, dename, loc) values(20, 'YanFaBu', 'SHANGHAI');
insert into dept(deptno, dename, loc) values(30, 'JiShuBu', 'GUANGZHOU');
insert into dept(deptno, dename, loc) values(40, 'MeiTiBu', 'SHENZHEN');
select *from dept;
第二步:准备一套HTML页面(页面原型)【前端开发工具使用vscode / IDEA】
- 把HTML页面准备好,然后将HTML页面中的链接都能够跑通。(保证每个页面流转没问题)
- 应该设计哪些页面呢?
- 欢迎页面:index.html
- 列表页面:list.html(以列表页面为核心,展开其他操作:增删改查。)
- 新增页面:add.html
- 修改页面:edit.html
- 详情页面:detail.html
以下目前代码为各页面:
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎使用OA系统</title>
</head>
<body>
<a href="list.html">查看部门列表</a>
</body>
</html>
- list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>部门列表页面</title>
</head>
<body>
<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>
<a href="javascript:void(0)" οnclick=window.confirm("您好!是否确认删除呢?")>删除</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)" οnclick=window.confirm("您好!是否确认删除呢?")>删除</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)" οnclick=window.confirm("您好!是否确认删除呢?")>删除</a>
<a href="edit.html">修改</a>
<a href="detail.html">详情</a>
</td>
</tr>
</table>
<hr>
<a href="add.html">新增部门</a>
</body>
</html>
- add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新增部门</title>
</head>
<body>
<h1>新增部门</h1>
<hr >
<form action="list.html" method="post">
部门编号<input type="text" name="deptno"/><br>
部门名称<input type="text" name="dename"/><br>
部门位置<input type="text" name="loc"/><br>
<input type="submit" value="保存"/><br>
</form>
</body>
</html>
- edit.html
<!DOCTYPE html>
<html lang="en">
<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="dename" value="销售部"/><br>
部门位置<input type="text" name="loc" value="北京"/><br>
<input type="submit" value="修改"/><br>
</form>
</body>
</html>
- detail.html
<!DOCTYPE html>
<html lang="en">
<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>
第三步:分析我们这个系统包括哪些功能?
什么叫做一个功能呢?
- 只要 这个操作(以上的增删改查)连接了数据库,就表示一个独立的功能。
包括哪些功能?
- 查看部门列表
- 新增部门
- 删除部门
- 查看部门详细信息
- 跳转到修改页面
- 修改部门
第四步:在IDEA当中搭建开发环境以及数据库配置
- 创建一个webapp(给这个webapp添加servlet-api.jar和jsp-api.jar到classpath当中。)【操作和以前部署一样】
- 向webapp中添加连接数据库的jar包(mysql驱动)
○ 必须在WEB-INF目录下新建lib目录,然后将mysql的驱动jar包拷贝到这个lib目录下。这个目录名必须叫做lib,全部小写的。
- JDBC的工具类(自己配)【具体解析在阶段一的第三阶段JDBC详解】
为了满足“OCP开闭原则:对扩展开放,对修改关闭”,就是更加灵活,不把代码写死。故新建一个专门存放jdbc配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/zxt_javaweb
user=root
password=13686644128zxt
接着就是编写JDBC的工具类:DBUtil类【复制即可】
import java.sql.*;
import java.util.ResourceBundle;
/**
* @Author: 爱摸鱼的TT~
* @Description: JDBC的工具类
* @Date Created in 2022-11-21 20:29
* @Modified By:
*/
public class DBUtil {
// 静态变量:在类加载时执行。
// 并且是有顺序的。自上而下的顺序。
// 属性资源文件绑定
private static ResourceBundle bundle = ResourceBundle.getBundle("resources.jdbc");
// 根据属性配置文件key获取value
private static String driver = bundle.getString("driver");
private static String url = bundle.getString("url");
private static String user = bundle.getString("user");
private static String password = bundle.getString("password");
static {
// 注册驱动(注册驱动只需要注册一次,放在静态代码块当中。DBUtil类加载的时候执行。)
try {
// "com.mysql.jdbc.Driver" 是连接数据库的驱动,不能写死。因为以后可能还会连接Oracle数据库。
// 如果连接oracle数据库的时候,还需要修改java代码,显然违背了OCP开闭原则。
// OCP开闭原则:对扩展开放,对修改关闭。(什么是符合OCP呢?在进行功能扩展的时候,不需要修改java源代码。)
//Class.forName("com.mysql.jdbc.Driver");
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接对象
* @return conn 连接对象
* @throws SQLException
*/
public static Connection 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();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
将所有HTML页面拷贝到web目录下。
第五步:动态实现每个功能
我们应该怎么去实现一个功能呢?
- 建议:你可以从后端往前端一步一步写。也可以从前端一步一步往后端写。都可以。但是千万要记住不要想起来什么写什么。你写代码的过程最好是程序的执行过程。也就是说:程序执行到哪里,你就写哪里。这样一个顺序流下来之后,基本上不会出现什么错误、意外。
那我们从哪里开始?
- 假设从前端开始,那么一定是从用户点击按钮那里开始的。
查看部门列表
-
第一:先修改前端页面的超链接,因为用户先点击的就是这个超链接。该超链接是要与数据库连接
-
第二:编写web.xml文件
<servlet>
<servlet-name>list</servlet-name>
<servlet-class>com.aimoyudett.oa.web.action.DeptListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>list</servlet-name>
<!--web.xml文件中的这个路径也是以“/”开始的,但是不需要加项目名-->
<url-pattern>/dept/list</url-pattern>
</servlet-mapping>
- 第三:编写DeptListServlet类继承HttpServlet类。然后重写doGet方法。
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-21 21:22
* @Modified By:
*/
public class DeptListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
- 第四:在DeptListServlet类的doGet方法中连接数据库,查询所有的部门,动态的展示部门列表页面
以下是目前DeptListServlet类中的初始代码,接下来根据具体业务步骤来添加代码
连接数据库,查询所有的部门:
// 第一步:功能实现:连接数据库,查询所有的部门【分为:1,2,3,4,5】
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 1.获取连接
conn = DBUtil.getConnection();
// 2.获取预编译的数据库操作对象
String sql = "select deptno as a, dename, loc from dept";
ps = conn.prepareStatement(sql);
// 3.执行SQL查询语句
rs = ps.executeQuery();
// 4.处理结果集
while(rs.next()){
String deptno = rs.getString("a");
String dename = rs.getString("dename");
String loc = rs.getString("loc");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 5.释放资源
DBUtil.close(conn, ps, rs);
}
动态获取数据:
// 第二步:要动态获取数据,而不能写死在前端界面
// 设置响应的内容类型以及字符集,防止中文乱码问题
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
a. 分析list.html页面中哪部分是固定死的,哪部分是需要动态展示的。【目的是便于在DeptListServlet类中编写代码,实现动态展示】
注意:由于list.html页面属于动态获取数据,所以全部代码写进DeptListServlet类,从而可以把该部分前端文件删除
b. list.html页面中的内容所有的双引号要替换成单引号,因为java类【DeptListServlet类】中out.print(“”)这里有一个双引号,容易冲突。
c. 接下来在DeptListServlet类中将list.html copy进去,并将前端固定代码和动态代码分类写进该类中。
更新DeptListServlet类:
public class DeptListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 第二步:要动态获取数据,而不能写死在前端界面
// 设置响应的内容类型以及字符集,防止中文乱码问题
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("<!DOCTYPE html>");
out.print("<html lang='en'>");
out.print("<head>");
out.print(" <meta charset='UTF-8'>");
out.print(" <title>部门列表页面</title>");
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>");
/*上面一部分是死的*/
// 第一步:功能实现:连接数据库,查询所有的部门【分为:1,2,3,4,5】
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 1.获取连接
conn = DBUtil.getConnection();
// 2.获取预编译的数据库操作对象
String sql = "select deptno as a, dename, loc from dept";
ps = conn.prepareStatement(sql);
// 3.执行SQL查询语句
rs = ps.executeQuery();
// 4.处理结果集
int i = 0;// 序号
while(rs.next()){
String deptno = rs.getString("a");
String dename = rs.getString("dename");
String loc = rs.getString("loc");
/*这部分是动态的*/
out.print(" <tr>");
out.print(" <td>"+(++i)+"</td>");
out.print(" <td>"+ deptno +"</td>");
out.print(" <td>"+ dename +"</td>");
out.print(" <td>");
out.print(" <a href=''>删除</a>");
out.print(" <a href='edit.html'>修改</a>");
out.print(" <a href='detail.html'>详情</a>");
out.print(" </td>");
out.print(" </tr>");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 5.释放资源
DBUtil.close(conn, ps, rs);
}
/*下面一部分是死的*/
out.print(" </table>");
out.print(" <hr>");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" <a href='add.html'>新增部门</a>");
out.print("</body>");
out.print("</html>");
}
}
d. 现在写完这个功能之后,你会有一种感觉,感觉开发很繁琐,因为还没学jsp技术或者其他技术,目前只使用servlet写代码,故太繁琐了。
运行结果:
查看部门详情
建议:从前端往后端一步一步实现。首先要考虑的是,用户点击的是什么?用户点击的东西在哪里?
- 一定要先找到用户点的“详情”在哪里。在后端的java程序中找到了
<a href='写一个路径'>详情</a>
-
详情 是需要连接数据库的,所以这个超链接点击之后也是需要执行一段java代码的。所以要将这个超链接的路径修改一下。
注意:修改路径之后,这个路径是需要加项目名的。【在这里即为 “/oa/dept/detail”】 -
问题来了:
a. 上面的项目名路径在Java类中是可以动态获取,没必要按照上面这样静态写死;
b. 还有个问题就是在点击详情时,跳转的详情页要对应点击的具体部门编号,而不是全部部门都显示出来,故也得在超链接路径后动态获取编号。
运行结果:【点哪个部门编号,就显示哪个部门详情】
● 重点:向服务器提交数据的格式:uri?name=value&name=value&name=value&name=value
● 这里的问号,必须是英文的问号。不能中文的问号。 -
解决404的问题。写web.xml文件。
<servlet>
<servlet-name>detail</servlet-name>
<servlet-class>com.aimoyudett.oa.web.action.DeptDetailServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>detail</servlet-name>
<!--web.xml文件中的这个路径也是以“/”开始的,但是不需要加项目名-->
<url-pattern>/dept/detail</url-pattern>
</servlet-mapping>
- 编写一个类:DeptDetailServlet继承HttpServlet,重写doGet方法。
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 DeptDetailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//中文思路(思路来源于:你要做什么?目标:查看部门详细信息。)
// 第一步:获取部门编号
// 第二步:根据部门编号查询数据库,获取该部门编号对应的部门信息。
// 第三步:将部门信息响应到浏览器上。(显示一个详情。)
}
}
- 在doGet方法当中:连接数据库,根据部门编号查询该部门的信息。动态展示部门详情页。
package com.aimoyudett.oa.web.action;
import com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-21 23:03
* @Modified By:
*/
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();
out.print("<!DOCTYPE html>");
out.print("<html lang='en'>");
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 >");
//中文思路(思路来源于:你要做什么?目标:查看部门详细信息。)
// 第一步:获取部门编号
// /oa/dept/detail?deptno=30
// 虽然是提交的30,但是服务器获取的是“30”这个字符串
String deptno = request.getParameter("deptno");
// 第二步:连接数据库,根据部门编号查询数据库,获取该部门编号对应的部门信息。
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "select dename,loc from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1,deptno);
rs = ps.executeQuery();
// 这个结果集一定只有一条记录
if(rs.next()){
String dename = rs.getString("dename");
String loc = rs.getString("loc");
out.print("部门编号:"+ deptno +"<br>");
out.print("部门名称:"+ dename +"<br>");
out.print("部门位置:"+ loc +"<br>");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(conn, ps, rs);
}
// 第三步:将部门信息响应到浏览器上。(显示一个详情。)
out.print(" <input type='button' value='返回部门列表' οnclick='window.history.back()'/>");
out.print("</body>");
out.print("</html>");
}
}
删除部门
- 怎么开始?从哪里开始?从前端页面开始,用户点击删除按钮的时候,应该提示用户是否删除。因为删除这个动作是比较危险的。任何系统在进行删除操作之前,是必须要提示用户的,因为这个删除的动作有可能是用户误操作。(在前端页面上写JS代码,来提示用户是否删除。)
<!--href后面设置为 javascript:void(0) 表示:仍然保留住超链接的样子-->
<!--点击此超链接之后,不进行页面的跳转。-->
<!--我只是希望用户点击该超链接的时候执行一段JS代码,不进行页面的跳转。-->
<a href="javascript:void(0)" onclick="del(30)" >删除</a>
<script type="text/javascript">
function del(dno){
// 弹出确认框,用户点击确定,返回true,点击取消返回false
var ok = window.confirm("亲,删了不可恢复哦!");
if(ok){
// 发送请求进行删除数据的操作。
// 在JS代码当中如何发送请求给服务器?
//alert("正在删除数据,请稍后...")
//写法1:document.location.href = "请求路径"
//写法2:document.location = "请求路径"
//写法3:window.location.href = "请求路径"
//写法4:window.location = "请求路径"
document.location.href = "/oa/dept/delete?deptno=" + dno;
}
}
</script>
- 以上的前端程序要写到后端的java代码当中:
a. DeptListServlet类的doGet方法当中,使用out.print()方法,将以上的前端代码输出到浏览器上。
b. 下面两张图是新增/修改的代码
更进DeptListServlet类:
package com.aimoyudett.oa.web.action;
import com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-21 21:22
* @Modified By:
*/
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 out = response.getWriter();
out.print("<!DOCTYPE html>");
out.print("<html lang='en'>");
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(" if(window.confirm('亲,删了不可恢复哦!')){");
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>");
/*上面一部分是死的*/
// 第一步:功能实现:连接数据库,查询所有的部门【分为:1,2,3,4,5】
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 1.获取连接
conn = DBUtil.getConnection();
// 2.获取预编译的数据库操作对象
String sql = "select deptno as a, dename, loc from dept";
ps = conn.prepareStatement(sql);
// 3.执行SQL查询语句
rs = ps.executeQuery();
// 4.处理结果集
int i = 0;// 序号
while(rs.next()){
String deptno = rs.getString("a");
String dename = rs.getString("dename");
String loc = rs.getString("loc");
/*这部分是动态的*/
out.print(" <tr>");
out.print(" <td>"+(++i)+"</td>");
out.print(" <td>"+ deptno +"</td>");
out.print(" <td>"+ dename +"</td>");
out.print(" <td>");
out.print(" <a href='javascript:void(0)' οnclick='del("+ deptno +")'>删除</a>");
out.print(" <a href='"+ contextPath +"/dept/edit?deptno="+ deptno +"'>修改</a>");
out.print(" <a href='"+ contextPath +"/dept/detail?fdsafdsas="+ deptno +"'>详情</a>");
out.print(" </td>");
out.print(" </tr>");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 5.释放资源
DBUtil.close(conn, ps, rs);
}
/*下面一部分是死的*/
out.print(" </table>");
out.print(" <hr>");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" ");
out.print(" <a href='add.html'>新增部门</a>");
out.print("</body>");
out.print("</html>");
}
}
- 解决404的问题
从上面结果可以看出,在点击确认删除后,会进行页面跳转。由于没有在web.html文件 和 新建一个关于该删除的类相关操作,导致出现404问题
a. 写web.xml文件
<servlet>
<servlet-name>delete</servlet-name>
<servlet-class>com.aimoyudett.oa.web.action.DeptDelServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>delete</servlet-name>
<url-pattern>/dept/delete</url-pattern>
</servlet-mapping>
b. 编写DeptDelServlet继承HttpServlet,重写doGet方法。
package com.aimoyudett.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 DeptDelServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 根据部门编号,删除部门。
}
}
c. 删除成功或者失败的时候的一个处理(这里我们选择了转发,并没有使用重定向机制。)
(1)在判断失删除失败后,需要新建一个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>
(2) 接着就是处理删除成功或失败的操作
// 判断删除成功了还是失败了。
if (count == 1) {
//删除成功
//仍然跳转到部门列表页面
//部门列表页面的显示需要执行另一个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");
}
总体DeptDelServlet类的代码:
package com.aimoyudett.oa.web.action;
import com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-22 1:00
* @Modified By:
*/
public class DeptDelServlet 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) {
// 遇到异常要回滚
if (conn != null) {
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, null);
}
// 判断删除成功了还是失败了。
if (count == 1) {
//删除成功
//仍然跳转到部门列表页面
//部门列表页面的显示需要执行另一个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");
}
}
}
新增部门
- 先修改DeptListServlet类中的最后html代码,使保存操作处于动态保存
- 写web.xml文件
<!--保存部门-->
<servlet>
<servlet-name>save</servlet-name>
<servlet-class>com.aimoyudett.oa.web.action.DeptSaveServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>save</servlet-name>
<url-pattern>/dept/save</url-pattern>
</servlet-mapping>
- 编写DeptSaveServlet继承HttpServlet,重写doGet方法。
package com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-22 1:34
* @Modified By:
*/
public class DeptSaveServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取部门的信息
// 连接数据库执行insert语句
// 保存成功跳转到列表页面
// 保存失败跳转到错误页面
}
}
总体DeptDelServlet类的代码:
package com.aimoyudett.oa.web.action;
import com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-22 1:34
* @Modified By:
*/
public class DeptSaveServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 获取部门的信息
// 注意乱码问题(Tomcat10不会出现这个问题)
request.setCharacterEncoding("UTF-8");
String deptno = request.getParameter("deptno");
String dename = request.getParameter("dename");
String loc = request.getParameter("loc");
// 2. 连接数据库执行insert语句
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
try {
conn = DBUtil.getConnection();
String sql = "insert into dept(deptno, dename, loc) values(?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
ps.setString(2, dename);
ps.setString(3, loc);
count = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, null);
}
if (count == 1) {
// 3. 保存成功跳转到列表页面
// 转发是一次请求。
request.getRequestDispatcher("/dept/list").forward(request, response);
// 这里最好使用重定向(浏览器会发一次全新的请求。)
// 浏览器在地址栏上发送请求,这个请求是get请求。
//response.sendRedirect(request.getContextPath() + "/dept/list");
}else{
// 4. 保存失败跳转到错误页面
request.getRequestDispatcher("/error.html").forward(request, response);
// 这里也建议使用重定向。
//response.sendRedirect(request.getContextPath() + "/error.html");
}
}
}
注意:最后保存成功之后,转发到 /dept/list 的时候,会出现405,为什么?问题所在
● 第一:保存用的是post请求。底层要执行doPost方法。
● 第二:转发是一次请求,之前是post,之后还是post,因为它是一次请求。
● 第三:/dept/list Servlet当中只有一个doGet方法。
怎么解决?两种解决方案
- 第一种:在/dept/list Servlet中添加doPost方法,然后在doPost方法中调用doGet。
DeptListServlet类:
// 处理post请求
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
- 第二种:重定向。【下节讲解】
跳转到修改部门的页面
还是从前端往后端写。以下步骤是进行跳转到修改部门的页面,而不是点击“修改”按钮 真正的修改成功!
- 修改DeptListServlet类中的前端“修改”超链接的路径代码
- 编写web.xml文件
<!--跳转到修改页面-->
<servlet>
<servlet-name>edit</servlet-name>
<servlet-class>com.aimoyudett.oa.web.action.DeptEditServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>edit</servlet-name>
<url-pattern>/dept/edit</url-pattern>
</servlet-mapping>
- 编写DeptEditServlet类继承HttpServlet类。然后重写doGet方法。
package com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-22 1:34
* @Modified By:
*/
public class DeptEditServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取部门的信息
// 连接数据库,根据部门编号查询部门的信息
// 输出动态网页
}
}
总体代码:
package com.aimoyudett.oa.web.action;
import com.aimoyudett.utils.DBUtil;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.ServletException;
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: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-22 10:44
* @Modified By:
*/
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("<!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='list.html' method='post'>");
// 获取部门编号
String deptno = request.getParameter("deptno");
// 连接数据库,根据部门编号查询部门的信息。
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "select dename, loc as location from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
rs = ps.executeQuery();
// 这个结果集中只有一条记录。
if(rs.next()){
String dename = rs.getString("dename");
String location = rs.getString("location"); // 参数"location"是sql语句查询结果列的列名。
// 输出动态网页。
out.print(" 部门编号<input type='text' name='deptno' value='"+deptno+"' readonly /><br>");
out.print(" 部门名称<input type='text' name='dename' value='"+dename+"'/><br>");
out.print(" 部门位置<input type='text' name='loc' value='"+location+"'/><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>");
}
}
修改部门
这步是完全实现修改成功的功能!
-
从原有基础上的DeptEditServlet类中的动态网页代码form表单跳转目标页action 写成动态的路径。
-
编写DeptModifyServlet类继承HttpServlet类。然后重写doGet方法。
package com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-22 1:34
* @Modified By:
*/
public class DeptEditServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决请求体的中文乱码问题。
// 获取表单中的数据
// 连接数据库执行更新语句
// 更新成功与否判断
}
}
总体代码:
package com.aimoyudett.oa.web.action;
import com.aimoyudett.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;
/**
* @Author: 爱摸鱼的TT~
* @Description:
* @Date Created in 2022-11-22 11:09
* @Modified By:
*/
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 dename = request.getParameter("dename");
String loc = request.getParameter("loc");
// 连接数据库执行更新语句
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
try {
conn = DBUtil.getConnection();
String sql = "update dept set dename = ?, loc = ? where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, dename);
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");
}
}
}
将oa项目中的资源跳转修改为合适的跳转方式(优化)
- 删除之后,重定向
- 修改之后,重定向
- 保存之后,重定向
- 重定向:
○ 成功
○ 失败