使用Servlet做一个单表的CRUD

使用纯Servlet做一个单表的CRUD操作

开发前的准备

第一步:准备一张部门表

sql脚本

  • DOS命令窗口默认编码是GBK , 导入中文会出现乱码 , 需要在执行SQL语句前执行 set names utf-8
  • mysql -uroot -p123456 --default-character-set=utf-8
  • 将SQL脚本保存为 UTF-8的形式
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;

第二步:准备一套HTML页面(项目原型) , 将HTML页面中的链接都能够跑通(实现页面的相互流转)

  • 欢迎页面:index.html
  • 列表页面:list.html(以列表页面为核心,展开其他操作)
  • 新增页面:add.html
  • 修改页面:edit.html
  • 详情页面:detail.html

第三步:分析系统包括哪些功能 , 只要这个操作连接了数据库,就表示一个独立的功能

  • 查看部门列表
  • 新增部门
  • 删除部门
  • 查看部门详细信息
  • 跳转到修改页面(动态的从数据库中获取信息并显示)
  • 修改部门

第四步:在IDEA当中搭建开发环境

  • 创建一个webapp(给这个webapp添加servlet-api.jar和jsp-api.jar到classpath当中)
  • 向webapp中添加连接数据库的jar包(mysql驱动)
    • 必须在WEB-INF目录下新建lib目录,然后将mysql的驱动jar包拷贝到这个lib目录下。这个目录名必须叫做lib,全部小写的
  • 将所有HTML页面拷贝到web目录下。

准备JDBC的工具类

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bjpowernode
user=root
password=root
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();
            }
        }
    }
}

在web应用中完成资源的跳转

在一个web应用中通过两种方式,可以完成资源的跳转

  • 第一种方式:转发
  • 第二种方式:重定向

跳转的下一个资源必须是一个Servlet吗?

  • 不一定,跳转的资源只要是服务器内部合法的资源即可。包括:Servlet、JSP、HTML…

开发准备

一个JavaBean的规范

  • 有无参数的构造方法 , 属性私有化 , 实现java.io.Serializable接口
  • 对外提供setter和getter方法 , 重写toString() , 重写hashCode + equals
public class User implements Serializable {
    private String id;
    private String name;
  
    public User() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) && Objects.equals(name, user.name);
    }
    
    // 对外提供setter和getter方法 , 重写toString() , 重写hashCode + equals
}

AServlet

public class AServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 创建一个用户对象
        User user = new User();
        user.setId("111111");
        user.setName("杰克");

        // 将用户对象存储到请求域当中
        request.setAttribute("userObj", user);

        // 转发(服务器自己完成内部资源的跳转,不需要添加项目名)
        // 浏览器一共发送了一次请求: http://localhost:8080/servlet10/a
        // request.getRequestDispatcher("/b").forward(request, response);

        // 重定向(浏览器需要重新发起请求 , 需要添加项目名)
        // response对象将这个路径:"/servlet10/b"响应给浏览器了。浏览器又自发的向服务器发送了一次全新的请求
        // 所以浏览器一共发送了两次请求:最终浏览器地址栏上显示的地址当然是最后那一次请求的地址。所以重定向会导致浏览器地址栏上的地址发生改变。
        // 第一次请求:http://localhost:8080/servlet10/a
        // 第二次请求:http://localhost:8080/servlet10/b
        response.sendRedirect(request.getContextPath() + "/b");
    }
}

BServlet

public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 从请求域当中取出存储的数据
        Object userObj = request.getAttribute("userObj");

        // 输出到浏览器
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("请求域当中的用户对象:" + userObj);
    }
}

转发(发送了一次请求)

在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终请求结束之后,浏览器地址栏上的地址还是这个

  • AServlet转发到BServlet,再转发到CServlet,再转发到DServlet,不管转发了多少次,都在同一个request当中。这是因为调用forward方法的时候,会将当前的request和response对象传递给下一个Servlet。
// 获取请求转发器对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/dept/list");
// 调用请求转发器对象的forward方法完成转发
dispatcher.forward(request, response);

// 合并一行代码
request.getRequestDispatcher("/dept/list").forward(request, response);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dq787atl-1673499606725)(D:\笔记\老杜javaweb文档\转发.png)]

重定向(发送了多次请求)

在浏览器地址栏上发送的请求是:http://localhost:8080/servlet10/a ,最终在浏览器地址栏上显示的地址是:http://localhost:8080/servlet10/b

// 以下这一行代码会将请求路径“/oa/dept/list”发送给浏览器 , 然后浏览器会自发的向服务器发送一次全新的请求:/oa/dept/list
response.sendRedirect("/oa/dept/list");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nzzSOxie-1673499606727)(D:\笔记\老杜javaweb文档\重定向.png)]

两种跳转方式的区别

转发的请求路径不需要添加项目名 :因为转发是由WEB服务器内部来控制的。

  • A资源跳转到B资源,这个跳转动作是Tomcat服务器内部完成的。
  • 我没钱了,找张三借钱,其实张三没有钱,但是张三够义气,张三自己找李四借了钱,然后张三把这个钱给了我,我不知道这个钱是李四的,杜老师只求了一个人。我以为这个钱就是张三的。

重定向的请求路径需要添加项目名:因为浏览器会根据服务器响应的路径重新发起一个请求(浏览器是在地址栏上发起的get请求)

  • 我没钱了,找张三借钱,张三没有钱,张三有一个好哥们,叫李四,李四是个富二代,于是张三将李四的家庭住址告诉了杜老师,我按照这个地址去找到李四,然后从李四那里借了钱。在这个过程中,我求了两个人。并且我知道最终这个钱是李四借给俺的。

应用场景

什么时候使用转发,什么时候使用重定向?

  • 如果在上一个Servlet当中向request域当中绑定了数据,希望从下一个Servlet当中把request域里面的数据取出来,使用转发机制。
  • 剩下所有的请求均使用重定向。(重定向使用较多)

转发存在浏览器的刷新问题

Student.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>学生</title>
</head>
<body>

<form action="/servlet10/save" method="get">
    学生编号<input type="text" name="no"><br>
    学生姓名<input type="text" name="name"><br>
    <input type="submit" value="保存">
</form>

</body>
</html>

StudentSaveServlet

  • 当使用转发跳转到 success.html 页面并刷新页面时 , 数据库中也会插入数据 , 因为地址栏上的请求还是之前的那个请求没变
  • 当使用重定向跳转到 success.html 页面并刷新页面时 , 数据库中不会插入数据 , 因为地址栏上的请求变成了最后一次的请求
public class StudentSaveServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 保存学生信息到数据库
        request.setCharacterEncoding("UTF-8");
        String no = request.getParameter("no");
        String name = request.getParameter("name");
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getConnection();
            String sql = "insert into t_student(no,name) values(?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, no);
            ps.setString(2, name);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        // 保存成功之后跳转到成功页面
        if (count == 1) {
            // 转发
            //request.getRequestDispatcher("/success.html").forward(request, response);

            // 重定向
            response.sendRedirect(request.getContextPath() + "/success.html");
        }else{

        }       
    }
}

实现系统功能

我们应该怎么去实现一个功能呢?

  • 你可以从后端往前端一步一步写。也可以从前端一步一步往后端写。都可以。但是千万要记住不要想起来什么写什么。
  • 你写代码的过程最好是程序的执行过程。也就是说:程序执行到哪里,你就写哪里。这样一个顺序流下来之后,基本上不会出现什么错误、意外。

假设从前端开始,那么一定是从用户点击按钮那里开始的。考虑用户点击的是什么?用户点击的东西在哪里?

实现查看部门列表功能

第一:先修改前端页面的超链接,因为用户先点击的就是这个超链接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LcgaiN9n-1673499606727)(C:\Users\meng\AppData\Roaming\Typora\typora-user-images\1673499373292.png)]

欢迎页面:index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>欢迎使用OA系统</title>
	</head>
	<body>
	<!--前端超链接发送请求的时候,请求路径以“/”开始,并且要带着项目名-->
		<a href="/oa/dept/list">查看部门列表</a>
	</body>
</html>

第二:编写web.xml文件

<servlet>
    <servlet-name>list</servlet-name>
    <servlet-class>com.bjpowernode.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方法。

  • 在DeptListServlet类的doGet方法中连接数据库,查询所有的部门,动态的展示部门列表页面.
  • 分析list.html页面中哪部分是固定死的,哪部分是需要动态展示的。
  • list.html页面中的内容所有的双引号要替换成单引号,因为out.print(“”)这里有一个双引号,容易冲突。 (可以利用文本工具查找替换)
  • 多行编辑 , 按住Alt键 , 鼠标往下托就行

DeptListServlet

  • 现在写完这个功能之后,你会有一种感觉,感觉开发很繁琐,只使用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 out = response.getWriter();

        // 使用多行编辑功能 , 按住Alt键 , 鼠标往下托就行
        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("        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>");
        /*上面一部分是死的*/

        // 动态的连接数据库,查询所有的部门
        //...................
        
        /*下面一部分是死的*/
        out.print("		</table>");
        out.print("		<hr >");
        out.print("		<a href='"+contextPath+"/add.html'>新增部门</a>");
        out.print("	</body>");
        out.print("</html>");
    }
}

动态的连接数据库,查询所有的部门的代码

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
    // 获取连接
    conn = DBUtil.getConnection();
    // 获取预编译的数据库操作对象
    String sql = "select deptno as a,dname,loc from dept";
    ps = conn.prepareStatement(sql);
    // 执行SQL语句
    rs = ps.executeQuery();
    // 处理结果集
    // i 表示序号
    int i = 0;
    while(rs.next()){
        String deptno = rs.getString("a");
        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)' οnclick='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>");
    }
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    // 释放资源
    DBUtil.close(conn, ps, rs);
}

实现查看部门详情功能

先找到用户点的“详情”的按钮在哪里。在后端的java程序 DeptListServlet 动态的响应的内容中

  • 用户点击详情按钮的超链接后是需要执行一段java代码连接数据库的。

将详情按钮的超链接路径修改一下

  • 这个路径是需要加项目名的。并且需要携带你想要查看的部门编号 , 这样才能连接数据库查询部门信息
  • 向服务器提交数据的格式:uri?name=value&name=value&name=value&name=value , 这里的问号,必须是英文的问号。不能中文的问号。
// i 表示序号
int i = 0;
while(rs.next()){
    String deptno = rs.getString("a");
    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)' οnclick='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>");
}

编写一个类:DeptDetailServlet继承HttpServlet,重写doGet方法。

  • 在doGet方法当中:连接数据库,根据部门编号查询该部门的信息。动态展示部门详情页。

web.xml文件

<servlet>
    <servlet-name>detail</servlet-name>
    <servlet-class>com.bjpowernode.oa.web.action.DeptDetailServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>detail</servlet-name>
    <url-pattern>/dept/detail</url-pattern>
</servlet-mapping>

DeptDetailServlet

  • 第一步:获取部门编号
  • 第二步:根据部门编号查询数据库,获取该部门编号对应的部门信息。
  • 第三步:将部门信息响应到浏览器上。(显示一个详情。)
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>");
        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("		<input type='button' value='后退' οnclick='window.history.back()'/>");
        out.print("	</body>");
        out.print("</html>");
    }
}

连接数据库,根据部门编号查询该部门的信息。动态展示部门详情页的代码。

// 通过请求参数获取部门编号 , /oa/dept/detail?deptno=30
// 虽然是提交的30,但是服务器获取的是"30"这个字符串。Mysql底层自动会把"30"转换成300
String deptno = request.getParameter("fdsafdsas");

// 连接数据库,根据部门编号查询部门信息。
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);
}

实现删除部门功能

从前端页面开始,用户点击删除按钮的时候,应该提示用户是否删除。因为删除这个动作是比较危险的 , 有可能是用户误操作。

  • 我希望设置给超链接设置一个点击事件 , 点击超链接后会执行事件函数 不进行页面的跳转, 在事件函数中发起请求实现删除部门的功能

  • 将JS代码写到后端的java程序的DeptListServlet类的doGet方法当中,使用out.print()方法,将以上的前端代码输出到浏览器上。

<!--deptno需要连接数据库获取-->
<!--href设置为javascript:void(0)表示仍然保留超链接的样子 , 但是点此超链接后不进行页面的跳转-->
<a href='javascript:void(0)' onclick='del("+deptno+")'>删除</a>")
<script type="text/javascript">
	function del(dno){
        // 弹出确认框 , 用户点击确定会返回true , 点击取消会返回false
		if(window.confirm("亲,删了不可恢复哦!")){
            //document.location = "请求路径"
            //document也可以替换成window
			document.location.href = "/oa/dept/delete?deptno=" + dno;
		}
	}
</script>

编写DeptDelServlet继承HttpServlet,重写doGet方法。根据部门编号,删除部门。

web.xml文件

<servlet>
    <servlet-name>delete</servlet-name>
    <servlet-class>com.bjpowernode.oa.web.action.DeptDelServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>delete</servlet-name>
    <url-pattern>/dept/delete</url-pattern>
</servlet-mapping>

DeptDelServlet

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;
        // count判断判断删除成功了还是失败了
        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);
        }

        // 判断删除成功了还是失败了..........
    }
        
}

删除成功或者失败的时候的一个处理 , 因为不需要共享数据 , 所以我们使用重定向机制。

// 无论删除成功还是失败都需要跳转到部门列表页面 , 但是显示部门列表页面需要执行另一个Servlet。
if (count == 1) {  //删除成功 

    response.sendRedirect(request.getContextPath() + "/dept/list");
}else{  // 删除失败

    response.sendRedirect(request.getContextPath() + "/error.html");
}

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>

实现新增部门功能

DeptListServlet , 跳转到新增部门的HTML页面

public class DeptListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*上面一部分是死的*/

        // 动态的连接数据库,查询所有的部门
        //...................
        
        /*下面一部分是死的*/
        out.print("		</table>");
        out.print("		<hr >");
        out.print("		<a href='"+contextPath+"/add.html'>新增部门</a>");
        out.print("	</body>");
        out.print("</html>");
    }
}

add.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>新增部门</title>
	</head>
	<body>
		<h1>新增部门</h1>
		<hr >
		<form action="/oa/dept/save" 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>

编写DeptSaveServlet继承HttpServlet,重写doPost方法 , 连接数据库保存新增的部门信息

<!--保存部门-->
<servlet>
    <servlet-name>save</servlet-name>
    <servlet-class>com.bjpowernode.oa.web.action.DeptSaveServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>save</servlet-name>
    <url-pattern>/dept/save</url-pattern>
</servlet-mapping>
public class DeptSaveServlet 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);
        }

        // 判断保存成功还是失败 , 保存成功跳转到列表页面.................
    }
}

新增部门添加成功之后的处理

  • 转发到 /dept/list 会出现405错误 , 转发是一次请求,保存新增部门信息用的是form表单发起post请求。后端处理时会执行 DeptListServlet 的 doPost方法
  • 重定向到 /oa/ /dept/list , 浏览器会在地址栏上发起一次全新的请求,这个请求是get请求 , 不需要在DeptListServlet中添加doPost方法
if (count == 1) {
    // 使用转发
    //request.getRequestDispatcher("/dept/list").forward(request, response);

    // 这里最好使用重定向(浏览器会发一次全新的请求)浏览器在地址栏上发送请求,这个请求是get请求。
    response.sendRedirect(request.getContextPath() + "/dept/list");

}else{
    // 保存失败跳转到错误页面
    //request.getRequestDispatcher("/error.html").forward(request, response);

    // 这里也建议使用重定向。
    response.sendRedirect(request.getContextPath() + "/error.html");
}

使用转发时需要在DeptListServlet中添加doPost方法,然后在doPost方法中调用doGet方法

public class DeptListServlet extends HttpServlet {

    // 处理post请求
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 连接数据库 , 动态展示部门列表页面 
    }

实现部门修改功能

将修改按钮的超链接路径修改一下

  • 这个路径是需要加项目名的。并且需要携带你想要查看的部门编号 , 这样才能连接数据库查询部门信息 , 动态的输出部门信息
// i 表示序号
int i = 0;
while(rs.next()){
    String deptno = rs.getString("a");
    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)' οnclick='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>");
}

DeptEditServlet 实现点击每个部门对应的修改按钮后 , 会跳转到当前部门对应的修改页面(部门编号是只读的)

<!--跳转到修改页面-->
<servlet>
    <servlet-name>edit</servlet-name>
    <servlet-class>com.bjpowernode.oa.web.action.DeptEditServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>edit</servlet-name>
    <url-pattern>/dept/edit</url-pattern>
</servlet-mapping>
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='"+contextPath+"/dept/modify' method='post'>");
        //上面一部分是死的

        // 连接数据库,动态输出部门的信息.....//下面一部分是死的
        out.print("			<input type='submit' value='修改'/><br>");
        out.print("		</form>");
        out.print("	</body>");
        out.print("</html>");
    }
}

根据部门编号 , 连接数据库,动态输出部门的信息

// 获取部门编号
String deptno = request.getParameter("deptno");
// 连接数据库,根据部门编号查询部门的信息。
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
    conn = DBUtil.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("                部门编号<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='"+location+"'/><br>");
    }
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtil.close(conn, ps, rs);
}

DeptModifyServlet 实现点击表单中的修改按钮后 , 连接数据库完成部门信息的更新

<!--修改部门-->
<servlet>
    <servlet-name>modify</servlet-name>
    <servlet-class>com.bjpowernode.oa.web.action.DeptModifyServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>modify</servlet-name>
    <url-pattern>/dept/modify</url-pattern>
    <!--<url-pattern>/dept/test/abc</url-pattern>-->
</servlet-mapping>
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");
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个完整的多表的 JavaWeb 项目通常包含以下几个关键步骤: 1. 数据库设计:首先,您需要设计数据库模式,包括多个表之间的关系和字段。确定每个表的主键、外键以及其他必要的字段。 2. 创建数据库连接:在 JavaWeb 项目中,您需要使用 JDBC(Java Database Connectivity)来连接数据库。通过在项目中配置数据库连接信息,可以建立与数据库的连接。 3. 创建实体类:根据数据库表的结构,创建对应的实体类。每个实体类对应数据库中的一张表,包含与表中字段相对应的属性。 4. DAO 层:创建数据访问对象(DAO)层来处理与数据库的交互。在 DAO 层中,您可以定义各种方法来执行 CRUD(创建、读取、更新、删除)操作,并处理多表查询。 5. 业务逻辑层:在业务逻辑层中,您可以定义各种业务逻辑方法,处理多个 DAO 方法的组合操作。这一层负责处理具体的业务需求,并调用相应的 DAO 方法来操作数据。 6. 控制器层:在控制器层中,您可以定义各种 Servlet 或其他控制器类来处理客户端请求。控制器接收请求参数,调用业务逻辑层的方法,并将结果返回给客户端。 7. 视图层:视图层负责展示数据给用户。您可以使用 JSP 或其他前端模板引擎来渲染动态页面,并将数据呈现给用户。 8. 配置文件和静态资源:在项目中,您需要进行一些配置,比如数据库连接配置、Web.xml 配置等。此外,还需要处理静态资源(如 CSS、JavaScript 文件)的引入和管理。 9. 测试和调试:完成项目的开发后,进行测试和调试是非常重要的。确保每个功能都能正常工作,并处理可能出现的异常情况。 10. 部署和发布:最后,将项目部署到服务器上,并发布给用户使用。 以上是一个大致的步骤,具体开发过程中还会涉及到其他细节和技术选择。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值