Servlet学习01

servlet

javaEE实际上包含很多种规范,13种规范,其中servlet就是javaEE规范之一。

关于系统架构

  1. C/S架构
    • 客户端/服务器架构
    • 需要安装特定的客户端软件
  2. B/S架构
    • 浏览器/服务器架构

B/S结构的通信原理

  • WEB系统的访问过程?

    • 打开浏览器
    • 地址栏输入合法的网址
    • 回车
    • 浏览器上会展示响应的内容
  • IP地址是什么?

    • 计算机在网络中的一个身份证号。在同一个网络当中,IP地址是唯一的
  • 端口号是什么?

    • 一个端口代表一个软件
    • 在同一个机器上,端口后具有唯一性
  • 通信步骤:

    • 第一步:用户输入网址(url)
    • 第二步:域名解析器进行域名解析
    • 第三步:浏览器软件在网络中搜索对应ip地址的主机,直到找到这台主机
    • 第四步:根据端口号定位主机上的服务器软件
    • 第五步:服务器软件得知想要的资源名
    • 第六步:服务器软件找到对应资源,并且将资源的内容直接输出响应到浏览器上
    • 第七步:浏览器接受到服务器响应的内容后,进行渲染
  • 什么是url?

    • 统一资源定位符
  • 什么是请求?什么是响应?

    • 请求和响应实际上说的是数据的流向不同
    • 从Browser端发送数据到Server端,我们称为请求(request)
    • 从Server端向浏览器Browser端发送数据,我们称为响应(response)

关于WEB服务器软件

  • web服务器有哪些?

    • tomcat

    • jetty

  • 应用服务器和WEB服务器的关系?

    • 应用服务器实现了javaEE的所有规范(javeEE有13种规范)
    • web服务器只实现了javaEE的Servlet + JSP两个核心的规范。

Tomcat

  • tomcat下载

  • tomcat使用注意

    • 是java语言编写的,运行需要计算机有java环境。
  • tomcat的特点

    • 轻量级web服务器
    • 体积小
    • 运行快
  • Tomcat服务器目录介绍

    • bin:存放Tomcat命令文件
    • conf:配置文件的目录(例如server.xml文件中可以配置端口号,默认为8080)
    • lib:Tomcat核心程序目录
    • logs:Tomcat服务器的日志目录
    • temp:临时目录
    • webapps:存放大量web应用
    • work:存放JSP文件,翻译之后的java文件以及编译之后的class文件。
  • Tomcat环境变量配置

    • JAVA_HOME:jdk的根
    • CATALINA_HOME:tomcat的根
    • Path
  • Tomcat启动和关闭

    • startup.bat
    • shutdown.bat(建议把shutdown.bat文件重命名为stop.bat)【原因:shutdown命令是windows关机命令,避免误操作】
  • 测试Tomcat服务器是否启动成功

    • 浏览器访问:http://localhost:8080/
Tomcat乱码问题处理
  1. 控制台乱码

    找到tomcat目录下的conf文件夹,打开loggin.properties文件

    # 把 java.util.logging.ConsoleHandler.encoding = UTF-8 改为:
    java.util.logging.ConsoleHandler.encoding = GBK
    

web应用

一个web应用的请求和响应过程有哪些角色参与?

  • 浏览器软件开发团队
  • web Server开发团队
  • 数据库开发团队
  • webapp开发团队

角色之间需要遵循哪些规范,哪些协议?

  • webapp团队 和 web Server开发团队 之间有一套规范:javaEE规范之一:Servlet规范【w3c组织指定】
    • Servlet规范的作用是什么?
      • web Server 和 webapp 解耦合
  • 浏览器 和 web Server之间有一套传输协议:HTTP协议(超文本传输协议)【sun公司制定】
  • webapp 和 数据库 之间有一套规范:JDBC规范【sun公司制定】

需要做的哪些工作?

  1. 编写一个类实现Servlet接口

  2. 将编写的类配置到配置文件中,在配置文件中:指定 请求路径 和 类名 的关系。

    注意:

    • 配置文件的文件名不能乱写,固定的
    • 配置文件的存放路径不能错,固定的
    • 文件名、文件路径都是SUN公司制定的Servlet规范中的明细
  3. 严格来说Servlet其实并不单单是简单的一个接口:

    Servlet规范中规定了:

    • 一个合格的webapp应该是一个怎样的目录结构
    • 一个合格的webapp应该有一个怎样的配置文件
    • 一个合格的webapp配置文件路径放在哪里
    • 一个合格的webapp中java程序放在哪里

    Tomcat服务器要遵循Servlet规范,javaWeb程序员也要遵循Servlet规范,这样Tomcat服务器和webapp才能解耦合。

开发一个带有Servlet(java小程序)的webapp

开发步骤

  1. 在webapps目录下新建一个目录,起名为:xxx(这个就是项目名)

    • 注意:项目xxx就是这个webapp的根
  2. 在webapp的根下新建一个目录:WEB-INF

    • 注意:这个目录是必须,这个目录的名字是Servlet规范中规定的,固定的,禁止自定义命名
    • 注意:WEB-INF目录是受保护的。放在这个目录下的资源,浏览器无法通过路径访问。
  3. 在WEB-INF目录下新建一个目录,命名为:classes

    • 注意:这个目录是必须,这个目录的名字必须是全部小写的classes。这个也是Servlet规范中规定的。另外这个目录下一定存放的是java编译后的class文件(字节码文件)
  4. 在WEB-INF目录下新建一个目录:命名为:lib

    • 注意:这个目录不是必须的,但如果一个webapp需要第三方的jar包的话,这个jar包要放到这个目录下,这个目录名也是固定的
  5. 在WEB-INF目录下新建一个文件:命名为:web.xml

    • 注意:这个文件是必须,文件名和存放路径也是固定的。这个是一个配置文件,这个文件中描述了请求路径和Servlet类之间的对照关系。
    • 建议:最好从别的webapp中拷贝过来,不要自己手写

    下面是最简洁的配置

    <?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_5_0.xsd"
      version="5.0"
      metadata-complete="true">
    
        
    </web-app>
    
  6. 编写java程序,这个java小程序也不能随意开发。这个java小程序必须实现Servlet接口。

    • Servlet接口不在jdk中(Servlet不是javaSE的,而是javaEE)
    • Servlet接口是javaEE规范中的一员
  7. 编译java小程序

    • 重点:如果没有用集成工具开发时,需要在环境变量中配置Servlet的jar包路径
  8. 把编译之后的文件目录拷贝到WEB-INF/classes目录下

  9. 在web.xml文件中编写配置信息,让“请求路径”和“Servlet类名”关联到一起

    • 即:在web.xml文件中注册Servlet
    <!-- Servlet 描述信息 -->
    <!-- 任何一个servlet都对应一个servle-mapping -->
    <servlet>
    	<servlet-name></servlet-name>
        <!-- 这个位置必须是带包名的全限定类名 -->
        <servlet-class></servlet-class>
    </servlet>
    
    <!-- Servlet 映射信息 -->
    <servlet-mapping>
        <!-- 这里可以顺便写,不过写的内容要和上面的一致 -->
    	<servlet-name></servlet-name>
        <!-- 这里路径可以顺便写,但是必须以'/'开头 -->
        <url-pattern></url-pattern>
    </servlet-mapping>
    
  10. 启动Tomcat服务器

  11. 浏览器输入url,访问

    • **注意:**浏览器上的请求路径和web.xml文件中的url-pattern一致;但唯一区别在于:浏览器的请求路径带项目名,url-pattern不带项目名
    • 以后不需要我们编写main方法了,Tomcat服务器负责调用main方法,Tomcat服务器启动的时候执行的就是main方法,我们javaWeb程序员只需要编写Servlet接口的实现,然后将其注册到web.xml文件中即可。

合法的webapp目录结构

webapproot
	|---- WEB-INF
			|---- classes(存放字节码)
			|---- lib(存放第三方类库)
			|---- web.xml(注册Servlet)
	|---- html
	|---- css
	|---- javascript
	|---- images
	...

案例

注意:需要引入Servlet.jar包

案例1

com.bz.demo01.UserServlet.java

package com.bz.demo01;

import jakarta.servlet.*;

import java.io.IOException;

public class UserServlet implements Servlet {
	@Override
	public void init(ServletConfig servletConfig) throws ServletException {

	}

	@Override
	public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
		System.out.println("Hello");
	}

	@Override
	public ServletConfig getServletConfig() {
		return null;
	}

	@Override
	public String getServletInfo() {
		return null;
	}

	@Override
	public void destroy() {

	}
}

web.xml

注册Servlet

<servlet>
    <servlet-name>userservlet</servlet-name>
    <servlet-class>com.bz.demo01.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>userservlet</servlet-name>
    <url-pattern>/user</url-pattern>
</servlet-mapping>

案例2

注意:把mysql jdbc驱动jar包拷贝到WEB-INF目录的lib(如果不存在需要创建)目录下

com.bz.demo01.UserServlet.java

package com.bz.demo01;

import jakarta.servlet.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

/**
 * 原始的Servlet实现
 */
public class UserServlet implements Servlet {
	@Override
	public void init(ServletConfig servletConfig) throws ServletException {

	}

	@Override
	public ServletConfig getServletConfig() {
		return null;
	}

	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;

		response.setContentType("text/html");


		PrintWriter out = response.getWriter();

		try {
			// 1.注册驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			// 2.获取连接
			conn = DriverManager.getConnection("jdbc:mysql://ip地址/库名", "mysql用户名", "mysql密码");
			// 3.获取预编译数据库操作对象
			String sql = "select loginName, loginPwd, name from t_user";
			ps = conn.prepareStatement(sql);
			// 4.执行sql
			rs = ps.executeQuery();
			// 5.结果集处理
			while(rs.next()) {
				System.out.println(rs.getString("loginName")
						+ "\t" + rs.getString("loginPwd")
						+ "\t" + rs.getString("name"));

				out.print("<h1>" + rs.getString("loginName")
						+ "\t" + rs.getString("loginPwd")
						+ "\t" + rs.getString("name") + "</h1><br>");
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			// 6.释放资源
			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();
				}
			}
		}
	}

	@Override
	public String getServletInfo() {
		return null;
	}

	@Override
	public void destroy() {

	}
}

web.xml

<servlet>
    <servlet-name>userlist</servlet-name>
    <servlet-class>com.bz.demo01.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>userlist</servlet-name>
    <url-pattern>/userlist</url-pattern>
</servlet-mapping>

关于javaEE的版本

  • javaEE目前最高版本为“javaEE8”
  • javaEE被Oracle收购后,捐献给Apache,Apache将“javaEE”改名为"jakarta"。
  • 所以"javaEE9"开始叫做"jakartaEE9"
  • javaEE8时对应的Servlet类名是:javax.servlet.Servlet【Tomcat 9、Tomcat 9-】
  • jakartaEE9开始对应的Servlet类名为:jakarta.servlet.Servlet【Tomcat 10、Tomcat 10+】

IDEA 项目搭建

  1. 创建项目

  2. 选择项
    在这里插入图片描述

  3. 勾选项
    在这里插入图片描述

  4. src目录下创建包、类

  5. 模块设置,可以设置部署路径、添加jar包等操作

在这里插入图片描述
6. 添加jar包

  1. 配置部署路径(非必须)

在这里插入图片描述
8. 配置Tomcat

在这里插入图片描述

  1. Tomcat详细配置

    在这里插入图片描述

项目部署运行报错

1.java: 错误: 无效的源发行版:17

参考

ServletConfig

是什么?

  • Servlet对象的配置信息对象
  • 是一个接口,是Servlet规范的一员
  • ServletConfig对象中封装了web.xml文件中标签中的配置信息
  • 一个Servlet对应一个ServletConfig对象

是谁创建?何时创建?

  • Servlet对象是Tomcat服务器创建,并且ServletConfig对象也是Tomcat服务器创建
  • 默认情况下,在用户第一次请求时创建

常用方法

// 1.通过初始化参数的name获取value
public String getInitParameter(String name);


// 2.获取所有初始化参数的name
public Enumeration<String> getInitParameterNames();


// 3.获取ServletContext对象
public ServletContext getServletContext();


// 4.获取Servlet的name
public String getServletName();

案例

注意:把mysql jdbc驱动jar包拷贝到WEB-INF目录的lib(如果不存在需要创建)目录下

com.bz.demo02.UserServlet.java

package com.bz.demo02;

import jakarta.servlet.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import java.util.Enumeration;

/**
 * 原始的Servlet实现
 *        ServletConfig案例
 */
public class UserServlet implements Servlet {

   private ServletConfig config;

   @Override
   public void init(ServletConfig servletConfig) throws ServletException {
      this.config = servletConfig;
   }

   @Override
   public ServletConfig getServletConfig() {
      return this.config;
   }

   @Override
   public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
      Connection conn = null;
      PreparedStatement ps = null;
      ResultSet rs = null;

      // 设置响应内容类型
      response.setContentType("text/html");
      
      PrintWriter out = response.getWriter();

      // 获取所有初始化参数的name
      Enumeration<String> initParameterNames = this.config.getInitParameterNames();
      while(initParameterNames.hasMoreElements()) {
         String name = initParameterNames.nextElement();
         // 通过初始化参数的name获取value
         String value = this.config.getInitParameter(name);
         out.print(name + " : " + value + "<br>");
      }


      try {
         // 1.注册驱动
         Class.forName("com.mysql.cj.jdbc.Driver");
         // 2.获取连接
         conn = DriverManager.getConnection("jdbc:mysql://ip地址/库名", "mysql用户名", "mysql密码");
         // 3.获取预编译数据库操作对象
         String sql = "select loginName, loginPwd, name from t_user";
         ps = conn.prepareStatement(sql);
         // 4.执行sql
         rs = ps.executeQuery();
         // 5.结果集处理
         while(rs.next()) {
            System.out.println(rs.getString("loginName")
                  + "\t" + rs.getString("loginPwd")
                  + "\t" + rs.getString("name"));

            out.print("<h1>" + rs.getString("loginName")
                  + "\t" + rs.getString("loginPwd")
                  + "\t" + rs.getString("name") + "</h1><br>");
         }
      } catch(Exception e) {
         e.printStackTrace();
      } finally {
         // 6.释放资源
         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();
            }
         }
      }
   }

   @Override
   public String getServletInfo() {
      return null;
   }

   @Override
   public void destroy() {

   }
}

web.xml

<servlet>
    <servlet-name>userlist2</servlet-name>
    <servlet-class>com.bz.demo02.UserServlet</servlet-class>

    <!-- start 初始化字段值 -->
    <init-param>
        <param-name>aaa</param-name>
        <param-value>111</param-value>
    </init-param>
    <init-param>
        <param-name>bbb</param-name>
        <param-value>222</param-value>
    </init-param>
	<!-- end 初始化字段值 -->
</servlet>
<servlet-mapping>
    <servlet-name>userlist2</servlet-name>
    <url-pattern>/userlist2</url-pattern>
</servlet-mapping>

ServletContext

是什么?

  • 是一个接口,是Servlet规范的一员。
  • Servlet对象的环境对象(Servlet对象的上下文对象)
  • ServletContext对象其实对应的就是整个web.xml文件
  • ServletContext对象是应用级对象,也称为:应用域

例子

50个学生,每个学生都是一个Servlet,这50个学生都在同一个教室里,那么这个教室就相当于ServletContext对象。

所以,放在ServletContext对象当中的数据,所有的Servlet一定是共享的。

是谁创建?何时创建?何时销毁?

  • ServletContext对象是WEB服务器创建的
  • ServletContext对象在WEB服务器启动时创建的
  • ServletContext对象在服务器关闭时销毁

注意

  • 对于一个webapp来说,ServletContext对象只有一个。
  • Tomcat是一个容器,一个容器可以放多个webapp,一个webapp对应一个ServletContext对象。

常用方法

// 1.通过初始化参数的name获取value
public String getInitParameter(String name);


// 2.获取所有初始化参数的name
public Enumeration<String> getInitParameterNames();


// 3.获取根路径
public String getContextPath();


// 4.获取绝对路径(真实路径)
public String getRealPath(String path);


// 5.记录日志
// 日志会自动记录到CATALINA_HOME/logs目录下的localhost.2022-07-18.log文件
public void log(String message);


// 6.向ServletContext应用域存数据
public void setAttribute(String name, Object value);


// 7.向ServletContext应用域取数据
public Object getAttribute(String name);


// 8.向ServletContext应用域删除数据
public void removeAttribute(String name);

案例

案例1

com.bz.demo03.UserServlet.java

package com.bz.demo03;

import jakarta.servlet.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import java.util.Enumeration;

/**
 * 原始的Servlet实现
 * 		ServletContext案例
 * 		日志记录
 */
public class UserServlet implements Servlet {

	private ServletConfig config;

	@Override
	public void init(ServletConfig servletConfig) throws ServletException {
		this.config = servletConfig;
	}

	@Override
	public ServletConfig getServletConfig() {
		return this.config;
	}

	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;

		response.setContentType("text/html");

		PrintWriter out = response.getWriter();

        
		ServletContext servletContext = this.config.getServletContext();
		// 项目根路径
		out.print("项目根路径:" + servletContext.getContextPath() + "<br>");
		// 获取web目录下的index.html文件
		out.print(servletContext.getRealPath("/index.html") + "<br>");
		// 记录日志
        // 日志会自动记录到CATALINA_HOME/logs目录下的localhost.2022-07-18.log文件
		servletContext.log("日志记录");
		servletContext.log("异常日志", new RuntimeException("自定义异常"));

		Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
		while(initParameterNames.hasMoreElements()) {
			String name = initParameterNames.nextElement();
			String value = servletContext.getInitParameter(name);
			out.print(name + " : " + value + "<br>");
		}

		try {
			// 1.注册驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			// 2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://ip地址/库名", "mysql用户名", "mysql密码");
			// 3.获取预编译数据库操作对象
			String sql = "select loginName, loginPwd, name from t_user";
			ps = conn.prepareStatement(sql);
			// 4.执行sql
			rs = ps.executeQuery();
			// 5.结果集处理
			while(rs.next()) {
				System.out.println(rs.getString("loginName")
						+ "\t" + rs.getString("loginPwd")
						+ "\t" + rs.getString("name"));

				out.print("<h1>" + rs.getString("loginName")
						+ "\t" + rs.getString("loginPwd")
						+ "\t" + rs.getString("name") + "</h1><br>");
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			// 6.释放资源
			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();
				}
			}
		}
	}

	@Override
	public String getServletInfo() {
		return null;
	}

	@Override
	public void destroy() {

	}
}

web.xml

<!-- context-param配置信息,所有Servlet都共享 -->
<context-param>
    <param-name>ccc</param-name>
    <param-value>111</param-value>
</context-param>
<context-param>
    <param-name>ddd</param-name>
    <param-value>222</param-value>
</context-param>
<!-- context-param配置信息,所有Servlet都共享 -->

<servlet>
    <servlet-name>userlist3</servlet-name>
    <servlet-class>com.bz.demo03.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>userlist3</servlet-name>
    <url-pattern>/userlist3</url-pattern>
</servlet-mapping>

案例2

com.bz.demo04.UserServlet.java

package com.bz.demo04;

import jakarta.servlet.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

/**
 * 原始的Servlet实现
 * 		ServletContext应用域 存、取、删除数据
 */
public class UserServlet implements Servlet {

	private ServletConfig config;

	@Override
	public void init(ServletConfig servletConfig) throws ServletException {
		this.config = servletConfig;
	}

	@Override
	public ServletConfig getServletConfig() {
		return this.config;
	}

	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;

		response.setContentType("text/html");

		PrintWriter out = response.getWriter();

		ServletContext servletContext = this.config.getServletContext();
		servletContext.setAttribute("name", "bz");
		out.print(servletContext.getAttribute("name") + "<br>");

		servletContext.removeAttribute("name");
		out.print(servletContext.getAttribute("name") + "<br>");

        try {
			// 1.注册驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			// 2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://ip地址/库名", "mysql用户名", "mysql密码");
			// 3.获取预编译数据库操作对象
			String sql = "select loginName, loginPwd, name from t_user";
			ps = conn.prepareStatement(sql);
			// 4.执行sql
			rs = ps.executeQuery();
			// 5.结果集处理
			while(rs.next()) {
				System.out.println(rs.getString("loginName")
						+ "\t" + rs.getString("loginPwd")
						+ "\t" + rs.getString("name"));

				out.print("<h1>" + rs.getString("loginName")
						+ "\t" + rs.getString("loginPwd")
						+ "\t" + rs.getString("name") + "</h1><br>");
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			// 6.释放资源
			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();
				}
			}
		}
	}

	@Override
	public String getServletInfo() {
		return null;
	}

	@Override
	public void destroy() {

	}
}

web.xml

<servlet>
    <servlet-name>userlist4</servlet-name>
    <servlet-class>com.bz.demo04.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>userlist4</servlet-name>
    <url-pattern>/userlist4</url-pattern>
</servlet-mapping>

Tomcat服务器的logs目录下有哪些日志文件?

  • catalina.2022-07-18.log
    • 服务器端的java程序运行的控制台信息
  • localhost.2022-07-18.log
    • ServletContext对象调用log方法记录的日志信息
  • localhost_access_log.2022-07-18.txt
    • 访问日志

设计模式:适配器 - GenericServlet类

作用

  • 简化代码,不需要程序员每次实现类时都实现全部方法

注意

以后的开发中我们在编写Servlet类时,实际上是不会去直接继承GenericServlet类的;因为我们采用的是B/S架构,这种系统是基于HTTP超文本传输协议,在Servlet规范当中,提供了一个类:HttpServlet,它是专门为HTTP协议准备的,所以我们编写的Servlet类要继承的是HttpServlet(HttpServlet是HTTP协议专用的

案例

com.bz.demo02.UserServlet.java

package com.bz.demo02;

import jakarta.servlet.GenericServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

/**
 * 使用适配器模式(GenericServlet)实现Servlet
 */
public class UserServlet extends GenericServlet {
	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet res = null;

		response.setContentType("text/html");
		PrintWriter pw = response.getWriter();

		try {
			Class.forName("com.mysql.cj.jdbc.Driver");

			conn = DriverManager.getConnection("jdbc:mysql://ip地址/库名", "mysql用户名", "mysql密码");

			String sql = "select loginName, loginPwd, name from t_user";
			ps = conn.prepareStatement(sql);

			res = ps.executeQuery();

			while(res.next()) {

				String loginName = res.getString("loginName");
				String loginPwd = res.getString("loginPwd");
				String name = res.getString("name");

				System.out.println(loginName + "\t" + loginPwd + "\t" + name);

				pw.print(loginName + "\t\t" + loginPwd + "\t\t" + name);

			}

		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			if (res != null) {
				try {
					res.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.xml

<servlet>
    <servlet-name>userlist2</servlet-name>
    <servlet-class>com.bz.demo02.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>userlist2</servlet-name>
    <url-pattern>/userlist2</url-pattern>
</servlet-mapping>

适配器 - HttpServlet类

继承关系

jakarta.servlet.Servlet(接口)

jakarta.servlet.GenericServlet implements Servlet (抽象类)

jakarta.servlet.http.HttpServlet extends GenericServlet(抽象类)

以后我们写的Servlet类要继承HttpServlet类

HTTP协议

什么是协议?

  • 协议本质就是一套规范,一套标准。

什么是HTTP协议?

  • 是W3C制定的一种超文本传输协议。
  • 这种协议游走在B和S之间;B向S发数据要遵循HTTP协议,S向B发数据同样需要遵循HTTP协议,这样B和S才能解耦合。
    • 什么是解耦合?
      • B不依赖S,S也不依赖B
  • HTTP协议包括:
    • 请求协议
      • 浏览器 向 WEB服务器发送数据
    • 响应协议
      • WEB服务器 向 浏览器发送数据

HTTP的请求协议

HTTP的请求协议包括:4部分

  • 请求行
    • 包括:
      1. 请求方式(7种)
        • get(常用)
        • post(常用)
        • delete
        • put
        • head
        • options
        • trace
      2. URI
        • 什么是URI?
          • 统一资源标识符,代表网络中某个资源的名字,但是通过URI是无法定位资源的。
        • 什么是URL?
          • 统一资源定位符,代表网络中某个资源,同时,通过URL是可以定位到该资源的。
        • URL和URI有什么关系?有什么区别?
          • URL包括URI
          • URL可以定位资源,URI无法定位资源。
      3. HTTP协议版本号
  • 请求头
    • 请求的主机
    • 主机的端口
    • 浏览器信息
    • 平台信息
    • cookie等信息
    • ……
  • 空白行
    • 空白行用来区分“请求头”和“请求体”
  • 请求体
    • 向服务器发送的具体数据
HTTP请求协议的具体报文:GET请求
GET /servlet04/getServlet?loginName=bz&loginPwd=123 HTTP/1.1										请求行
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9																					请求头
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Host: 127.0.0.1:8080
Referer: http://127.0.0.1:8080/servlet04/index.html
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
																									空白行
																									请求体
HTTP请求协议的具体报文:POST请求
POST /servlet04/postServlet HTTP/1.1																请求行
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9																					请求头
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Content-Length: 20
Content-Type: application/x-www-form-urlencoded
Host: 127.0.0.1:8080
Origin: http://127.0.0.1:8080
Referer: http://127.0.0.1:8080/servlet04/index.html
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
																									空白行
loginName=bz&loginPwd=111																			请求体
GET请求和POST请求的区别?
  • get请求发送数据时,数据会挂在URI后面(在“请求行”发送数据)。这样会导致发送的数据回显在浏览器地址栏上
  • get请求只能发送普通字符串,并且发送的字符串长度有限制,不同浏览器限制不同。
  • get请求比较适合从服务器端获取数据,所以是绝对安全的
  • get请求支持缓存
  • post请求发送数据时,在请求体当中发送数据(数据会存储在Form Data)。不会回显到浏览器地址栏上
  • post请求可以发送任何类型的数据
  • post请求可以发送大数据量,理论上没有限制
  • post请求比较适合向服务器端传送数据,所以是危险的
  • post请求不支持缓存
  • get请求和post请求发送的数据格式相同,格式为:name=val&name=val…
GET请求和POST请求如何选择?
  • get请求比较适合从服务器端获取数据
  • post请求比较适合向服务器端传送数据
  • 如果表单中有敏感信息,建议使用post请求,因为get请求会回显敏感信息到地址栏
  • 文件上传,一定是post请求,因为要传的数据不是普通文本

HTTP的响应协议

HTTP的响应协议包括:4部分

  • 状态行
    • 组成:
      1. 协议版本号(HTTP/1.1)
      2. 状态码(HTTP协议中规定的响应状态号,不同的响应结果对应不同的号码)
        • 200:表示请求响应成功,正常结束
        • 404:表示访问的资源不存在,通常要么是路径写错,要么是服务器对应的资源不存在或者没有启动成功
        • 405:表示前端发送的请求方式与后端请求的处理方式不一致
          • 比如:前端是POST请求,后端的处理方式按照get方式进行处理是,发生405
          • 比如:前端是GET请求,后端的处理方式按照post方式进行处理是,发生405
        • 500:表示服务器端的程序发生异常,一般认为是服务器端的错误导致的
        • 以4开头的状态码,一般来说是浏览器端的错误导致的。
        • 以5开头的状态码,一般来说是服务器端的错误导致的。
      3. 状态的描述信息
        • ok:表示正常成功结束
        • not found:表示资源找不到
  • 响应头
  • 空白行
  • 响应体
HTTP响应协议的具体报文
HTTP/1.1 200 ok															状态行
Content-Type: text/html;charset=UTF-8									响应头
Content-Length: 150
Date: Tue, 19 Jul 2022 02:48:11 GMT
Keep-Alive: timeout=20
Connection: keep-alive
																		空白行
<!DOCTYPE html>															响应体
<html>
	<head>
		<meta charset="UTF-8">
		<title>getServlet</title>
	</head>
	<body>
		<h1>getServlet</h1>
	</body>
</html>

模板方法设计模式

什么是设计模式?

  • 某个问题的固定的解决方案

有哪些设计模式?

  • GoF设计模式
    • 通常我们所说的23种设计模式(Gang of Four)
    • 单例模式
    • 工厂模式
    • 代理模式
    • 门面模式
    • 责任链设计模式
    • 观察者模式
  • JavaEE设计模式
    • DAO
    • DTO
    • VO
    • PO
    • pojo

什么是模板方法设计模式?

  • 在模板类的模板方法当中定义核心算法的骨架,具体的实现步骤可以延迟到子类当中实现
  • 模板类通常是一个抽象类,模板类当中的模板方法定义核心算法,这个方法建议用final修饰

案例

没有使用模板方法设计模式

Student类

package com.bz.demo01;

/**
 * Student类和Teacher类存在问题:
 * 	1.算法没有得到重复的使用
 * 	2.代码没有得到复用
 */
public class Student {

	// 学生的一天
	public void day() {
		qiChuan();
		xiShu();
		chiZaoCan();
		doSome();
		chiWanFan();
		shuiJiao();
	}

	public void qiChuan() {
		System.out.println("起床");
	}

	public void xiShu() {
		System.out.println("洗漱");
	}

	public void chiZaoCan() {
		System.out.println("吃早餐");
	}

	public void doSome() {
		System.out.println("上学,学习");
	}

	public void chiWanFan() {
		System.out.println("吃晚饭");
	}

	public void shuiJiao() {
		System.out.println("睡觉");
	}
}

Teacher类

package com.bz.demo01;


/**
 * Student类和Teacher类存在问题:
 * 	1.算法没有得到重复的使用
 * 	2.代码没有得到复用
 */
public class Teacher {

	// 老师的一天
	public void day() {
		qiChuan();
		xiShu();
		chiZaoCan();
		doSome();
		chiWanFan();
		shuiJiao();
	}

	public void qiChuan() {
		System.out.println("起床");
	}

	public void xiShu() {
		System.out.println("洗漱");
	}

	public void chiZaoCan() {
		System.out.println("吃早餐");
	}

	public void doSome() {
		System.out.println("上班,授课");
	}

	public void chiWanFan() {
		System.out.println("吃晚饭");
	}

	public void shuiJiao() {
		System.out.println("睡觉");
	}
}
使用模板方法设计模式

Person类

package com.bz.demo02;

/**
 * Student和Tearcher都是Person
 */
// 抽象方法只能出现在抽象类中
public abstract class Person { // 模板类通常是抽象类

	/*
		模版方法
		这里使用final修饰,这个方法无法被覆盖,这样核心的算法也可以得到保护
		模板方法定义核心的算法骨架,具体的实现步骤可以延迟到子类当中去实现
		核心算法一方面是得到了保护,不能被改变;另一方面就是算法得到了重复使用。
		另外代码也得到了复用,因为算法中某些步骤的代码是固定的,这些固定的代码不会随着子类的变化而变化,这一部分的代码可以写到模板类当中
	 */
	public final void day() {
		qiChuan();
		xiShu();
		chiZaoCan();
		doSome();
		chiWanFan();
		shuiJiao();
	}

	public void qiChuan() {
		System.out.println("起床");
	}

	public void xiShu() {
		System.out.println("洗漱");
	}

	public void chiZaoCan() {
		System.out.println("吃早餐");
	}

	// 这个方法每个子类都不一样,所以定义为抽象方法,子类继承后重写该方法
	public abstract void doSome();

	public void chiWanFan() {
		System.out.println("吃晚饭");
	}

	public void shuiJiao() {
		System.out.println("睡觉");
	}
}

Student类

package com.bz.demo02;

public class Student extends Person {

	@Override
	public void doSome() {
		System.out.println("上学,学习");
	}
}

Teacher类

package com.bz.demo02;


public class Teacher extends Person {
	@Override
	public void doSome() {
		System.out.println("上班,授课");
	}
}

Test类

package com.bz.demo02;

public class Test {
	public static void main(String[] args) {

		Person p1 = new Teacher();
		Person p2 = new Student();
		p1.day();

		System.out.println("\n------------------------------------\n");

		p2.day();
	}
}

HttpServlet源码分析

  • HttpServlet类是专门为Http协议准备的,比GenericServlet类更加适合HTTP协议下的开发
  • HttpServlet类在jakarta.servlet.http.HttpServlet包下
  • 到目前为止接触了Servlet规范中的哪些接口?
    • jakarta.servlet.Servlet:核心接口(接口)
    • jakarta.servlet.ServletConfig:Servlet配置信息接口(接口)
    • jakarta.servlet.ServletContext:Servlet上下文接口(接口)
    • jakarta.servlet.ServletRequest:Servlet请求接口(接口)
    • jakarta.servlet.ServletResponse:Servlet响应接口(接口)
    • jakarta.servlet.ServletException:Servlet异常(类)
    • jakarta.servlet.GenericServlet:标准通用的Servlet类(抽象类)
  • jakarta.servlet.http包下有哪些类和接口?
    • jakarta.servlet.http.HttpServlet:(HTTP协议专用的Servlet类,抽象类)
    • jakarta.servlet.http.HttpServletRequest:(HTTP协议专用的请求对象)
    • jakarta.servlet.http.HttpServletResponse:(HTTP协议专用的响应对象)
  • HttpServletRequest对象中封装了什么信息?
    • HttpServletRequest简称request对象
    • HttpServletRequest中封装了请求协议的全部内容
  • HttpServletResponse对象是专门用来响应HTTP协议到浏览器的。

HttpServletRequest常用方法

  • 获取前端浏览器用户提交的数据

    String getParameter(String name);
    
    Map<String, String[]> getParameterMap();
    
    Enumeration<String> getParameterNames();
    
    String[] getParameterValues(String name);
    
  • 其它常用方法

    // 获取客户端ip地址
    String ip = request.getRemoteAddr();
    
    // Tomcat9之前版本请求含有中文会乱码,可以使用下面语句设置为utf-8
    // 设置请求体的字符集(post请求的数据才是放在请求体)
    request.setCharacterEncoding("UTF-8");
    
    // 设置响应体编码
    response.setContentType("text/html;charset=UTF-8");
    
    // 获取应用的根路径
    String contextPath = request.getContextPath();
    
    // 获取请求方式
    String method = request.getMethod();
    
    // 获取请求的URI
    String requestURI = request.getRequestURI();
    
    // 获取Servlet路径
    String servletPath = request.getServletPath();
    

请求域对象

  • ”请求域“对象要比“应用域”对象范围小很多,生命周期短很多,请求域只在一次请求内有效
  • 一个请求对象(request)对应一个请求域。一次请求结束后,这个请求域就销毁了
  • 请求域对象也有三个方法
    • void setAttribute(String name, Object value); // 6.向域存数据
    • Object getAttribute(String name); // 7.向域取数据
    • void removeAttribute(String name); // 向域删除数据
  • 请求域和应用域的选用原则?
    • 尽量使用小的域对象,因为小的域对象占用的资源较少

Servlet类的开发步骤(最终版):

  1. 编写一个Servlet类,继承HttpServlet类
  2. 重写doGet方法或者doPost方法(具体看实际需求)
  3. 将Servlet类配置到web.xml文件当中(又叫:注册Servlet)
  4. 准备前端页面调用

关于一个Web站点的欢迎页面

什么是一个web站点的欢迎页面?

  • 对于一个webapp来说,我们是可以设置它的欢迎页面的。
  • 设置了欢迎页面之后,当你访问这个webapp的时候,或者访问这个web站点时,没有指定任何“资源路径”,这时会默认访问你的欢迎页面。
  • 注意:一个webapp可以有多个欢迎页,越靠上优先级越高,找不到时继续向下找。

如何设置欢迎页?

  1. 目录结构

    webapp
      |---- WEB-INF
               |---- web.xml
      |---- index.html
    
  2. 在web目录下新建login.html页面

  3. 在web.xml中配置

    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
    
    <!-- 欢迎页可以是一个Servlet -->
    <!-- 取url-pattern的配置,不要开头的“/” -->
    
    <welcome-file-list>
        <welcome-file>loginPage</welcome-file>
    </welcome-file-list>
    
    <servlet>
        <servlet-name>getServlet</servlet-name>
        <servlet-class>com.bz.demo03.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getServlet</servlet-name>
        <url-pattern>/loginPage</url-pattern>
    </servlet-mapping>
    

    注意:

    • 配置欢迎页时,路径不需要以“/”开始;这个路径默认是从webapp的根下开始查找
  4. 启动服务器,浏览器输入地址访问

哪几个位置可以配置欢迎页?

  • 在webapp内部的web.xml文件中配置(属于局部配置)
  • 在CATALINA_HOME(即:Tomcat服务器根目录)/conf/web.xml文件中配置(属于全局配置)
  • 注意原则:局部配置优先(就近原则)

请求转发

  • 注意:
    • 只要是Web容器的合法资源都能进行转发,不单单是Servlet。转发的路径以“/”开始,不要写项目名。

AServlet.java

package com.bz.demo04;

import jakarta.servlet.RequestDispatcher;
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;

public class AServlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String ip = request.getRemoteAddr();

		request.setAttribute("ip", ip);
		Object ip1 = request.getAttribute("ip");

		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.print("<h1>" + ip1 + "</h1>");

        /*
			get请求含有中文数据乱码的修改方案(Tomcat8之前才需要修改):
				Tomcat的server.xml配置文件的Connector标签中,添加URIEncoding="UTF-8"
		 */
        
		// 获取请求转发器对象
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("/b");
		// 调用转发器的forward方法完成跳转/转发
		requestDispatcher.forward(request, response);
	}
    
    @Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// Tomcat9之前版本请求含有中文会乱码,可以使用下面语句设置为utf-8
		// 设置请求体的字符集(post请求的数据才是放在请求体)
		request.setCharacterEncoding("UTF-8");

	}
}

BServlet.java

package com.bz.demo04;

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;

public class BServlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html");
        // response.setContentType("text/html;charset=UTF-8");
		Object ip = request.getAttribute("ip");
		PrintWriter out = response.getWriter();
		out.print("<h1>" + ip + "</h1>");

	}
}

web.xml

<servlet>
    <servlet-name>a</servlet-name>
    <servlet-class>com.bz.demo04.AServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>a</servlet-name>
    <url-pattern>/a</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>b</servlet-name>
    <servlet-class>com.bz.demo04.BServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>b</servlet-name>
    <url-pattern>/b</url-pattern>
</servlet-mapping>

实现资源跳转

完成跳转的方式

  1. 转发
  2. 重定向

转发

  • 语法

    // servlet名为:/dept/list
    // 获取请求转发器对象,不需要加项目名
    RequestDispatcher requestDispatcher = request.getRequestDispatcher("/dept/list");
    // 调用请求转发器对象的forward()完成转发
    requestDispatcher.forward(request, response);
    
  • 特点

    • 不管转发多少次,都是一个请求
    • 转发前后的请求(get、post)方式要保持一致
    • 浏览器的地址栏还是转发前的地址

重定向

  • 语法

    String contextPath = request.getContextPath(); // 获取项目名
    
    // servlet名为:/dept/list
    // 使用重定向方式,需要加项目名
    // response对象将这个路径响应给浏览器后,浏览器会自发的请求这个路径
    response.sendRedirect(contextPath + "/dept/list");
    
  • 特点

    • 每重定向一次,就是一个新的请求
    • 转发前后的请求(get、post)方式不受影响
    • 浏览器的地址栏会更新到重定向的地址

转发和重定向的区别

  • 转发是由WEB服务器来控制的,A请求跳转到B请求,整个过程中都是Tomcat完成的。
  • 重定向是浏览器完成的,具体跳转到哪个资源由浏览器决定的。

何时使用转发?何时使用重定向?

  • 如果在上一个Servlet当中向request域当中绑定了数据,希望在下一个Servlet当中把request域里面的数据取出来,使用转发机制
  • 其余情况都用重定向(使用较多)

1.使用纯Servlet实现的案例(只使用转发机制)

  • 创建数据表(dept)

    drop table if exists t_dept;
    
    -- 部门表
    create table t_dept(
    	deptno int primary key, -- 主键
    	dname varchar(200),
    	address varchar(200)
    );
    
    -- 插入测试数据
    insert into t_dept (deptno, dname, address) values (1, '开发部', '广州');
    insert into t_dept (deptno, dname, address) values (2, '销售部', '深圳');
    insert into t_dept (deptno, dname, address) values (3, '人事部', '上海');
    commit;
    
    -- 查询数据
    select * from t_dept;
    
  • WEB-INF下的lib目录引入mysql jdbc包

  • 目录结构

    src
     |------com.bz.oa
     			|------utils
     					|------DBUtil.java
     			|------web.action
     					|------AddServlet.java
     					|------DelServlet.java
     					|------DeptListServlet.java
     					|------DetailServlet.java
     					|------EditDeptServlet.java
     					|------UpdateDeptServlet.java
     |------resources
     			|------jdbc.properties
    web
     |------WEB-INF
     		   |------lib
     		   			|------mysql-connector-java-8.0.29.jar
     		   |------web.xml
     |------addDept.html
     |------error.html
     |------index.html
    
  • DBUtil.java

    package com.bz.oa.utils;
    
    import java.sql.*;
    import java.util.ResourceBundle;
    
    /**
     * JDBC工具类
     */
    public class DBUtil {
    
    	// 静态变量,在类加载时执行
    	// 并且是有顺序的,自上而下的顺序
    	// 注意:这里的resources目录是在src下的
    	private static ResourceBundle bundle = ResourceBundle.getBundle("resources.jdbc");
    	private static String driver = bundle.getString("driver");
    	private static String url = bundle.getString("url");
    	private static String user = bundle.getString("user");
    	private static String pwd = bundle.getString("pwd");
    
    
    	static {
    		try {
    			// 注册驱动
    			Class.forName(driver);
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    
    	/**
    	 * 获取数据库连接对象
    	 * @return connection 数据库连接对象
    	 * @throws SQLException
    	 */
    	public static Connection getConnection() throws SQLException {
    		return DriverManager.getConnection(url, user, pwd);
    	}
    
    
    	/**
    	 * 释放资源
    	 * @param conn 数据库连接对象
    	 * @param stat 数据库操作对象
    	 * @param res 结果集对象
    	 */
    	public static void close(Connection conn, Statement stat, ResultSet res) {
    		if (res != null) {
    			try {
    				res.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    
    		if (stat != null) {
    			try {
    				stat.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    
    		if (conn != null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    }
    
  • AddServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.oa.utils.DBUtil;
    import jakarta.servlet.RequestDispatcher;
    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 AddServlet 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 address = request.getParameter("address");
    
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		int count = 0;
    
    		try {
    			conn = DBUtil.getConnection();
    			// 开启事务
    			conn.setAutoCommit(false);
    
    			String sql = "insert into t_dept (deptno, dname, address) values (?, ?, ?)";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, deptno);
    			ps.setString(2, dname);
    			ps.setString(3, address);
    
    			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 > 0) {
    			// 新增成功
    			// 这里应该用重定向,现阶段没学到,所以先用转发
    			// 转发的Servlet不是post方法,会报405错误,所以需要在DeptListServle类添加doPost方法
    			RequestDispatcher requestDispatcher = request.getRequestDispatcher("/dept/list");
    			requestDispatcher.forward(request, response);
    		} else {
    			// 新增失败
    			RequestDispatcher requestDispatcher = request.getRequestDispatcher("/error.html");
    			requestDispatcher.forward(request, response);
    		}
    	}
    }
    
  • DelServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.oa.utils.DBUtil;
    import jakarta.servlet.RequestDispatcher;
    import jakarta.servlet.Servlet;
    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.SQLException;
    
    public class DelServlet extends HttpServlet {
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		String deptno = request.getParameter("deptno");
    		String contextPath = request.getContextPath();
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		int count = 0;
    
    		try {
    			conn = DBUtil.getConnection();
    			// 开启事务(自动提交机制关闭)
    			conn.setAutoCommit(false);
    			String sql = "delete from t_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 > 0) {
    			// 删除成功
    			// 这里应该用重定向,现阶段没学到,所以先用转发
    			RequestDispatcher requestDispatcher = request.getRequestDispatcher("/dept/list");
    			requestDispatcher.forward(request, response);
    		} else {
    			// 删除失败
    			// 新增失败
    			RequestDispatcher requestDispatcher = request.getRequestDispatcher("/error.html");
    			requestDispatcher.forward(request, response);
    		}
    	}
    }
    
  • DeptListServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.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.*;
    
    public class DeptListServle extends HttpServlet{
    	// 暂时解决新增数据后转发报405错误
    	@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 {
    
    		// 获取应用的根路径
    		String contextPath = request.getContextPath();
    
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    
    
    
    
    
    		out.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("	<meta charset='utf-8' />");
    		out.println("	<title>部门列表</title>");
    
    		out.println("<script type='text/javascript'>");
    		out.println("	function del(deptno) {");
    		out.println("		if (window.confirm('删除后无法 恢复,是否确定删除?')) {");
    //		document.location.href = '';
    //		document.location = '';
    //		window.location.href = '';
    //		window.location = '';
    		out.println("			document.location.href = '" + contextPath + "/dept/delete?deptno='+deptno");
    		out.println("		}");
    		out.println("	}");
    
    		out.println("</script>");
    
    		out.println("</head>");
    		out.println("<body>");
    		out.println("	<h1>部门列表</h1>");
    		out.println("	<hr>");
    		out.println("	<table border='1' align='center' width='50%'>");
    		out.println("		<tr>");
    		out.println("			<th>部门编号</th>");
    		out.println("			<th>部门名称</th>");
    		out.println("			<th>操作</th>");
    		out.println("		</tr>");
    
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet res = null;
    
    		try {
    			conn = DBUtil.getConnection();
    
    			String sql = "select deptno, dname, address from t_dept";
    			ps = conn.prepareStatement(sql);
    
    			res = ps.executeQuery();
    
    			while(res.next()) {
    				int deptno = res.getInt("deptno");
    				String dname = res.getString("dname");
    				String address = res.getString("address");
    				System.out.println(deptno + ", " + dname + ", " + address);
    				out.println("<tr>");
    				out.println("	<td>" + deptno + "</td>");
    				out.println("	<td>" + dname + "</td>");
    				out.println("	<td>");
    				out.println("		<a href='javascript:void(0);' onClick='del(" + deptno + ")'>删除</a>");
    				out.println("		<a href='" + contextPath + "/dept/edit?deptno=" + deptno + "'>编辑</a>");
    				out.println("		<a href='" + contextPath + "/dept/detail?deptno=" + deptno + "'>详情</a>");
    				out.println("	</td>");
    				out.println("</tr>");
    			}
    
    		}catch(SQLException e) {
    			e.printStackTrace();
    		} finally {
    			DBUtil.close(conn, ps, res);
    			out.println("	</table>");
    			out.println("	<hr/>");
    			out.println("<a href='" + contextPath + "/addDept.html'>新增部门</a>");
    			out.println("</body>");
    			out.println("</html>");
    		}
    
    	}
    }
    
  • DetailServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.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 DetailServlet extends HttpServlet {
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		String deptno = request.getParameter("deptno");
    
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out = response.getWriter();
    
    		out.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("	<meta charset='utf-8' />");
    		out.println("	<title>部门列表</title>");
    		out.println("</head>");
    		out.println("<body>");
    		out.println("<h1>部门详情</h1>");
    		out.println("<hr>");
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet res = null;
    		try {
    			conn = DBUtil.getConnection();
    			String sql = "select dname, address from t_dept where deptno = ?";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, deptno);
    			res = ps.executeQuery();
    			if(res.next()) {
    				out.println("<p>部门编号:" + deptno + "</p>");
    				out.println("<p>部门名称:" + res.getString("dname") + "</p>");
    				out.println("<p>部门地址:" + res.getString("address") + "</p>");
    			}
    		}catch(SQLException e) {
    			e.printStackTrace();
    		} finally {
    			DBUtil.close(conn, ps, res);
    		}
    
    		out.println("		<input type='button' value='返回' onClick='window.history.back()' />");
    		out.println("	</table>");
    		out.println("</body>");
    		out.println("</html>");
    	}
    }
    
  • EditDeptServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.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 EditDeptServlet extends HttpServlet {
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		String contextPath = request.getContextPath();
    
    
    		// 获取部门编号
    		String deptno = request.getParameter("deptno");
    
    
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out = response.getWriter();
    		out.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("<meta charset='UTF-8'>");
    		out.println("<title>修改部门</title>");
    		out.println("</head>");
    		out.println("<body>");
    		out.println("<h1>修改部门</h1>");
    		out.println("<hr/>");
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet res = null;
    
    		try {
    			conn = DBUtil.getConnection();
    
    			String sql = "select deptno, dname, address from t_dept where deptno = ?";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, deptno);
    
    			res = ps.executeQuery();
    			if(res.next()) {
    				String dname = res.getString("dname");
    				String address = res.getString("address");
    
    //				?deptno=" + deptno + "&dname=" + dname + "&address=" + address + "
    
    				out.println("<form action='" + contextPath + "/dept/update' method='post'>");
    				out.println("部门编号<input type='number' name='deptno' value='" + deptno + "' readonly /><br/>");
    				out.println("部门名称<input type='text' name='dname' value='" + dname + "' /><br/>");
    				out.println("部门位置<input type='text' name='address' value='" + address + "' /><br/>");
    				out.println("<input type='submit' value='保存' />");
    				out.println("</form>");
    			}
    
    
    		} catch (SQLException e) {
    			e.printStackTrace();
    		} finally {
    			DBUtil.close(conn, ps, res);
    		}
    		out.println("</body>");
    		out.println("</html>");
    	}
    }
    
  • UpdateDeptServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.oa.utils.DBUtil;
    import jakarta.servlet.RequestDispatcher;
    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 UpdateDeptServlet extends HttpServlet {
    	@Override
    	protected void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		// 获取表单的数据
    		String deptno = request.getParameter("deptno");
    		String dname = request.getParameter("dname");
    		String address = request.getParameter("address");
    
    		// 解决请求体的中文乱码问题
    		request.setCharacterEncoding("UTF-8");
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		int count = 0;
    
    		try {
    			conn = DBUtil.getConnection();
    			conn.setAutoCommit(false);
    			String sql = "update t_dept set dname=?, address=? where deptno=?";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, dname);
    			ps.setString(2, address);
    			ps.setString(3, 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 > 0) {
    			// 修改成功
    			RequestDispatcher requestDispatcher = request.getRequestDispatcher("/dept/list");
    			requestDispatcher.forward(request, response);
    		} else {
    			// 修改失败
    			RequestDispatcher requestDispatcher = request.getRequestDispatcher("/error.html");
    			requestDispatcher.forward(request, response);
    		}
    
    	}
    }
    
  • jdbc.properties

    # 驱动品牌
    driver=com.mysql.cj.jdbc.Driver
    # 地址
    url=jdbc:mysql://ip地址:3306/数据库
    # 用户
    user=root
    # 密码
    pwd=root.5354
    
  • web.xml

    <?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_5_0.xsd"
             version="5.0">
    
        <!-- 欢迎页 -->
        <welcome-file-list>
            <welcome-file>dept/list</welcome-file>
        </welcome-file-list>
    
        <!-- start 列表 -->
        <servlet>
            <servlet-name>deptList</servlet-name>
            <servlet-class>com.bz.oa.web.action.DeptListServle</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>deptList</servlet-name>
            <url-pattern>/dept/list</url-pattern>
        </servlet-mapping>
        <!-- end 列表 -->
    
        <!-- start 详情 -->
        <servlet>
            <servlet-name>detail</servlet-name>
            <servlet-class>com.bz.oa.web.action.DetailServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>detail</servlet-name>
            <url-pattern>/dept/detail</url-pattern>
        </servlet-mapping>
        <!-- end 详情 -->
    
        <!-- start 删除部门 -->
        <servlet>
            <servlet-name>delete</servlet-name>
            <servlet-class>com.bz.oa.web.action.DelServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>delete</servlet-name>
            <url-pattern>/dept/delete</url-pattern>
        </servlet-mapping>
        <!-- end 删除部门 -->
    
        <!-- start 新增部门 -->
        /dept/add
        <servlet>
            <servlet-name>add</servlet-name>
            <servlet-class>com.bz.oa.web.action.AddServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>add</servlet-name>
            <url-pattern>/dept/add</url-pattern>
        </servlet-mapping>
        <!-- end 新增部门 -->
    
        <!-- start 跳转到部门编辑页面 -->
        <servlet>
            <servlet-name>editDept</servlet-name>
            <servlet-class>com.bz.oa.web.action.EditDeptServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>editDept</servlet-name>
            <url-pattern>/dept/edit</url-pattern>
        </servlet-mapping>
        <!-- end 跳转到部门编辑页面 -->
    
        <!-- start 部门编辑 -->
        <servlet>
            <servlet-name>updateDept</servlet-name>
            <servlet-class>com.bz.oa.web.action.UpdateDeptServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>updateDept</servlet-name>
            <url-pattern>/dept/update</url-pattern>
        </servlet-mapping>
        <!-- end 部门编辑 -->
    
    </web-app>
    
  • addDept.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>新增部门</title>
    </head>
    <body>
        <h1>新增部门</h1>
        <hr/>
        <!-- 项目名为/servlet07 -->
        <form action="/servlet07/dept/add" method="post">
            部门编号<input type="number" name="deptno" /><br/>
            部门名称<input type="text" name="dname" /><br/>
            部门位置<input type="text" name="address" /><br/>
            <input type="submit" value="保存" />
        </form>
    </body>
    </html>
    
  • error.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>error</title>
    </head>
    <body>
        <h1>操作失败</h1>
        <a href="javascript:void(0);" onClick="window.history.back();">返回</a>
    </body>
    </html>
    
  • index.html

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

2.使用纯Servlet实现的案例(使用重定向机制)

  • 创建数据表(dept)

    drop table if exists t_dept;
    
    -- 部门表
    create table t_dept(
    	deptno int primary key, -- 主键
    	dname varchar(200),
    	address varchar(200)
    );
    
    -- 插入测试数据
    insert into t_dept (deptno, dname, address) values (1, '开发部', '广州');
    insert into t_dept (deptno, dname, address) values (2, '销售部', '深圳');
    insert into t_dept (deptno, dname, address) values (3, '人事部', '上海');
    commit;
    
    -- 查询数据
    select * from t_dept;
    
  • WEB-INF下的lib目录引入mysql jdbc包

  • 目录结构

    src
     |------com.bz.oa
     			|------utils
     					|------DBUtil.java
     			|------web.action
     					|------AddServlet.java
     					|------DelServlet.java
     					|------DeptListServlet.java
     					|------DetailServlet.java
     					|------EditDeptServlet.java
     					|------UpdateDeptServlet.java
     |------resources
     			|------jdbc.properties
    web
     |------WEB-INF
     		   |------lib
     		   			|------mysql-connector-java-8.0.29.jar
     		   |------web.xml
     |------addDept.html
     |------error.html
     |------index.html
    
  • DBUtil.java

    package com.bz.oa.utils;
    
    import java.sql.*;
    import java.util.ResourceBundle;
    
    /**
     * JDBC工具类
     */
    public class DBUtil {
    
    	// 静态变量,在类加载时执行
    	// 并且是有顺序的,自上而下的顺序
    	// 注意:这里的resources目录是在src下的
    	private static ResourceBundle bundle = ResourceBundle.getBundle("resources.jdbc");
    	private static String driver = bundle.getString("driver");
    	private static String url = bundle.getString("url");
    	private static String user = bundle.getString("user");
    	private static String pwd = bundle.getString("pwd");
    
    
    	static {
    		try {
    			// 注册驱动
    			Class.forName(driver);
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    
    	/**
    	 * 获取数据库连接对象
    	 * @return connection 数据库连接对象
    	 * @throws SQLException
    	 */
    	public static Connection getConnection() throws SQLException {
    		return DriverManager.getConnection(url, user, pwd);
    	}
    
    
    	/**
    	 * 释放资源
    	 * @param conn 数据库连接对象
    	 * @param stat 数据库操作对象
    	 * @param res 结果集对象
    	 */
    	public static void close(Connection conn, Statement stat, ResultSet res) {
    		if (res != null) {
    			try {
    				res.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    
    		if (stat != null) {
    			try {
    				stat.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    
    		if (conn != null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    }
    
  • AddServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.oa.utils.DBUtil;
    import jakarta.servlet.RequestDispatcher;
    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 AddServlet extends HttpServlet {
    	@Override
    	protected void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
            String contextPath = request.getContextPath();
    		request.setCharacterEncoding("UTF-8");
    
    		String deptno = request.getParameter("deptno");
    		String dname = request.getParameter("dname");
    		String address = request.getParameter("address");
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		int count = 0;
    
    		try {
    			conn = DBUtil.getConnection();
    			// 开启事务
    			conn.setAutoCommit(false);
    
    			String sql = "insert into t_dept (deptno, dname, address) values (?, ?, ?)";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, deptno);
    			ps.setString(2, dname);
    			ps.setString(3, address);
    
    			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 > 0) {
    			// 新增成功            
                // 使用重定向方式,需要加项目名
    			response.sendRedirect(contextPath + "/dept/list");
    		} else {
    			// 新增失败
    			response.sendRedirect(contextPath + "/error.html");
    		}
    	}
    }
    
  • DelServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.oa.utils.DBUtil;
    import jakarta.servlet.RequestDispatcher;
    import jakarta.servlet.Servlet;
    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.SQLException;
    
    public class DelServlet extends HttpServlet {
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		String deptno = request.getParameter("deptno");
    		String contextPath = request.getContextPath();
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		int count = 0;
    
    		try {
    			conn = DBUtil.getConnection();
    			// 开启事务(自动提交机制关闭)
    			conn.setAutoCommit(false);
    			String sql = "delete from t_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 > 0) {
    			// 删除成功
    			// 使用重定向方式,需要加项目名
    			response.sendRedirect(contextPath + "/dept/list");
    		} else {
    			// 删除失败
    			// 新增失败
    			response.sendRedirect(contextPath + "/error.html");
    		}
    	}
    }
    
  • DeptListServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.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.*;
    
    public class DeptListServle 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.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("	<meta charset='utf-8' />");
    		out.println("	<title>部门列表</title>");
    
    		out.println("<script type='text/javascript'>");
    		out.println("	function del(deptno) {");
    		out.println("		if (window.confirm('删除后无法 恢复,是否确定删除?')) {");
    //		document.location.href = '';
    //		document.location = '';
    //		window.location.href = '';
    //		window.location = '';
    		out.println("			document.location.href = '" + contextPath + "/dept/delete?deptno='+deptno");
    		out.println("		}");
    		out.println("	}");
    
    		out.println("</script>");
    
    		out.println("</head>");
    		out.println("<body>");
    		out.println("	<h1>部门列表</h1>");
    		out.println("	<hr>");
    		out.println("	<table border='1' align='center' width='50%'>");
    		out.println("		<tr>");
    		out.println("			<th>部门编号</th>");
    		out.println("			<th>部门名称</th>");
    		out.println("			<th>操作</th>");
    		out.println("		</tr>");
    
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet res = null;
    
    		try {
    			conn = DBUtil.getConnection();
    
    			String sql = "select deptno, dname, address from t_dept";
    			ps = conn.prepareStatement(sql);
    
    			res = ps.executeQuery();
    
    			while(res.next()) {
    				int deptno = res.getInt("deptno");
    				String dname = res.getString("dname");
    				String address = res.getString("address");
    				System.out.println(deptno + ", " + dname + ", " + address);
    				out.println("<tr>");
    				out.println("	<td>" + deptno + "</td>");
    				out.println("	<td>" + dname + "</td>");
    				out.println("	<td>");
    				out.println("		<a href='javascript:void(0);' onClick='del(" + deptno + ")'>删除</a>");
    				out.println("		<a href='" + contextPath + "/dept/edit?deptno=" + deptno + "'>编辑</a>");
    				out.println("		<a href='" + contextPath + "/dept/detail?deptno=" + deptno + "'>详情</a>");
    				out.println("	</td>");
    				out.println("</tr>");
    			}
    
    		}catch(SQLException e) {
    			e.printStackTrace();
    		} finally {
    			DBUtil.close(conn, ps, res);
    			out.println("	</table>");
    			out.println("	<hr/>");
    			out.println("<a href='" + contextPath + "/addDept.html'>新增部门</a>");
    			out.println("</body>");
    			out.println("</html>");
    		}
    
    	}
    }
    
  • DetailServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.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 DetailServlet extends HttpServlet {
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		String deptno = request.getParameter("deptno");
    
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out = response.getWriter();
    
    		out.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("	<meta charset='utf-8' />");
    		out.println("	<title>部门列表</title>");
    		out.println("</head>");
    		out.println("<body>");
    		out.println("<h1>部门详情</h1>");
    		out.println("<hr>");
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet res = null;
    		try {
    			conn = DBUtil.getConnection();
    			String sql = "select dname, address from t_dept where deptno = ?";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, deptno);
    			res = ps.executeQuery();
    			if(res.next()) {
    				out.println("<p>部门编号:" + deptno + "</p>");
    				out.println("<p>部门名称:" + res.getString("dname") + "</p>");
    				out.println("<p>部门地址:" + res.getString("address") + "</p>");
    			}
    		}catch(SQLException e) {
    			e.printStackTrace();
    		} finally {
    			DBUtil.close(conn, ps, res);
    		}
    
    		out.println("		<input type='button' value='返回' onClick='window.history.back()' />");
    		out.println("	</table>");
    		out.println("</body>");
    		out.println("</html>");
    	}
    }
    
  • EditDeptServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.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 EditDeptServlet extends HttpServlet {
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    
    		String contextPath = request.getContextPath();
    
    
    		// 获取部门编号
    		String deptno = request.getParameter("deptno");
    
    
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out = response.getWriter();
    		out.println("<!DOCTYPE html>");
    		out.println("<html>");
    		out.println("<head>");
    		out.println("<meta charset='UTF-8'>");
    		out.println("<title>修改部门</title>");
    		out.println("</head>");
    		out.println("<body>");
    		out.println("<h1>修改部门</h1>");
    		out.println("<hr/>");
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		ResultSet res = null;
    
    		try {
    			conn = DBUtil.getConnection();
    
    			String sql = "select deptno, dname, address from t_dept where deptno = ?";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, deptno);
    
    			res = ps.executeQuery();
    			if(res.next()) {
    				String dname = res.getString("dname");
    				String address = res.getString("address");
    
    //				?deptno=" + deptno + "&dname=" + dname + "&address=" + address + "
    
    				out.println("<form action='" + contextPath + "/dept/update' method='post'>");
    				out.println("部门编号<input type='number' name='deptno' value='" + deptno + "' readonly /><br/>");
    				out.println("部门名称<input type='text' name='dname' value='" + dname + "' /><br/>");
    				out.println("部门位置<input type='text' name='address' value='" + address + "' /><br/>");
    				out.println("<input type='submit' value='保存' />");
    				out.println("</form>");
    			}
    
    
    		} catch (SQLException e) {
    			e.printStackTrace();
    		} finally {
    			DBUtil.close(conn, ps, res);
    		}
    		out.println("</body>");
    		out.println("</html>");
    	}
    }
    
  • UpdateDeptServlet.java

    package com.bz.oa.web.action;
    
    import com.bz.oa.utils.DBUtil;
    import jakarta.servlet.RequestDispatcher;
    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 UpdateDeptServlet extends HttpServlet {
    	@Override
    	protected void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
            
            // 获取应用的根路径
    		String contextPath = request.getContextPath();
            
    		// 获取表单的数据
    		String deptno = request.getParameter("deptno");
    		String dname = request.getParameter("dname");
    		String address = request.getParameter("address");
    
    		// 解决请求体的中文乱码问题
    		request.setCharacterEncoding("UTF-8");
    
    		Connection conn = null;
    		PreparedStatement ps = null;
    		int count = 0;
    
    		try {
    			conn = DBUtil.getConnection();
    			conn.setAutoCommit(false);
    			String sql = "update t_dept set dname=?, address=? where deptno=?";
    			ps = conn.prepareStatement(sql);
    			ps.setString(1, dname);
    			ps.setString(2, address);
    			ps.setString(3, 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 > 0) {
    			// 修改成功
                // 使用重定向方式,需要加项目名
    			response.sendRedirect(contextPath + "/dept/list");
    		} else {
    			// 修改失败
                response.sendRedirect(contextPath + "/error.html");
    		}
    
    	}
    }
    
  • jdbc.properties

    # 驱动品牌
    driver=com.mysql.cj.jdbc.Driver
    # 地址
    url=jdbc:mysql://ip地址:3306/数据库
    # 用户
    user=root
    # 密码
    pwd=root.5354
    
  • web.xml

    <?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_5_0.xsd"
             version="5.0">
    
        <!-- 欢迎页 -->
        <welcome-file-list>
            <welcome-file>dept/list</welcome-file>
        </welcome-file-list>
    
        <!-- start 列表 -->
        <servlet>
            <servlet-name>deptList</servlet-name>
            <servlet-class>com.bz.oa.web.action.DeptListServle</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>deptList</servlet-name>
            <url-pattern>/dept/list</url-pattern>
        </servlet-mapping>
        <!-- end 列表 -->
    
        <!-- start 详情 -->
        <servlet>
            <servlet-name>detail</servlet-name>
            <servlet-class>com.bz.oa.web.action.DetailServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>detail</servlet-name>
            <url-pattern>/dept/detail</url-pattern>
        </servlet-mapping>
        <!-- end 详情 -->
    
        <!-- start 删除部门 -->
        <servlet>
            <servlet-name>delete</servlet-name>
            <servlet-class>com.bz.oa.web.action.DelServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>delete</servlet-name>
            <url-pattern>/dept/delete</url-pattern>
        </servlet-mapping>
        <!-- end 删除部门 -->
    
        <!-- start 新增部门 -->
        /dept/add
        <servlet>
            <servlet-name>add</servlet-name>
            <servlet-class>com.bz.oa.web.action.AddServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>add</servlet-name>
            <url-pattern>/dept/add</url-pattern>
        </servlet-mapping>
        <!-- end 新增部门 -->
    
        <!-- start 跳转到部门编辑页面 -->
        <servlet>
            <servlet-name>editDept</servlet-name>
            <servlet-class>com.bz.oa.web.action.EditDeptServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>editDept</servlet-name>
            <url-pattern>/dept/edit</url-pattern>
        </servlet-mapping>
        <!-- end 跳转到部门编辑页面 -->
    
        <!-- start 部门编辑 -->
        <servlet>
            <servlet-name>updateDept</servlet-name>
            <servlet-class>com.bz.oa.web.action.UpdateDeptServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>updateDept</servlet-name>
            <url-pattern>/dept/update</url-pattern>
        </servlet-mapping>
        <!-- end 部门编辑 -->
    
    </web-app>
    
  • addDept.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>新增部门</title>
    </head>
    <body>
        <h1>新增部门</h1>
        <hr/>
        <!-- 项目名为/servlet07 -->
        <form action="/servlet07/dept/add" method="post">
            部门编号<input type="number" name="deptno" /><br/>
            部门名称<input type="text" name="dname" /><br/>
            部门位置<input type="text" name="address" /><br/>
            <input type="submit" value="保存" />
        </form>
    </body>
    </html>
    
  • error.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>error</title>
    </head>
    <body>
        <h1>操作失败</h1>
        <!-- href="/项目名/Servlet" -->
        <a href="/servlet07/dept/list">返回</a>
    </body>
    </html>
    
  • index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>oa</title>
    </head>
    <body>
    
    </body>
    </html>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值