Servlet

一、概述

1、背景

动态Web资源的开发越来越重要

常见的技术有:ASP,PHP,JSP,Servlet

2、什么是Servlet

Servlet是使用Java语言编写的运行在服务器端的程序。Servlet主要用于处理客户端传来的Http请求,并返回一个响应,它能够处理的请求有**doGet()和doPost()**等方法。

3、servlet容器

Servlet由Servlet容器提供,所谓的Servlet容器是指提供了Servlet功能的服务器(这里指Tomcat),Servlet容器将Servlet动态的加载到服务器上。

Servlet应用程序的体系结构如下图:

image-20210416183436093

 Servlet的请求首先会被HTTP服务器接收,HTTP服务器只负责处理静态的HTML文件,对于Servlet的请求会转交给Servlet容器,Servlet容器会根据web.xml文件中的映射关系,调用对应的Servlet,Servlet将处理的结果返回给Servlet容器,并通过HTTP服务器将响应传输给客户端

4、Servlet技术的特点

(1)方便:Servlet提供了大量的实用工具例程。如处理HTML表单数据,读取和设置HTTP头部,处理Cookie和跟踪会话

(2)跨平台:因为java是跨平台的

(3)灵活可扩展:Java类的继承性和构造函数等特点

(4)可以在各个程序之间共享数据

5、互联网应用数据流程图

image-20210419155255174
二、Servlet开发入门

1、Servlet接口的五个抽象方法

(1)void init(ServletConfig config) 

容器在创建好Servlet对象后,就会调用此方法,参数config用来初始化Servlet

(2)ServletConfig getServletConfig()

获取Servlet对象的配置信息,返回ServletConfig对象

(3)String getServletInfo()

返回一个包含Servlet的字符串信息,包含作者,版权等信息

(4)void service(ServletRequest request,ServletResponse response)

负责处理和响应用户的请求

(5)void destroy()

释放Servlet占用的资源

2、Servlet实现类

(1)GenericServlet

这是一个抽象类,实现了Servlet的部分。没有实现HTTP请求的处理

(2)HttpServlet

这个是GenericServlet的子类,继承了GenericServlet的所有方法,并且为HTTP的POST和GET等类型提供了具体的操作方法,通常编写的Servlet类都继承自HttpServlet

3、HttpServlet类中的方法

(1)protected void doGet(HttpServletRequest req,HttpServletResponse resp)

处理GET类型的http请求

(2)protected void doPost(HttpServletRequest req,HttpServletResponse resp)

处理POST类型的http请求

(3)protected void doPut(HttpServletRequest req,HttpServletResponse resp)

处理PUT类型的http请求

4、项目创建与运行

(1)创建项目

选择java Enterprise -->勾选Web Application

(2)导入servlet-api包

File->Project->Libaries->加号->到tomcat的lib目录下可以找到这个包

(3)目录结构

image-20210419085958320
这里的src是编写java程序的地方,web是放静态页面和配置文件的地方,其中web-inf是放置配置文件的地方 

(4)配置tomcat

image-20210419090320653image-20210419090417454
(5)src编写 

package com.fjh;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class P1Servlet extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        PrintWriter out = servletResponse.getWriter();
        out.println("hello world,你好,世界");
    }
}

(6)web.xml编写

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <!--    servlet的名称    -->
        <servlet-name>test01</servlet-name>
        <!--    对应类的名称    -->
        <servlet-class>com.fjh.P1Servlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <!--    servlet名称    -->
        <servlet-name>test01</servlet-name>
        <!--    页面访问的路径(记得加/)    -->
        <url-pattern>/test</url-pattern>
    </servlet-mapping>
</web-app>

配置一个类的xml分为两个部分:

1、servlet标签

2、servlet-mapping标签

(7)访问

浏览器地址栏输入

http://127.0.0.1:8080/test

这里说明一下为什么是/testimage-20210419091212316

 因为我这里的项目路径配置的就是/

所以访问的时候直接/test就行

默认的话会有一个项目名称,例如/p01_war

那么访问的时候就输入http://127.0.0.1:8080/p01_war/test

协议://地址:端口/项目名称/接口(如果端口是80的话就不用写:80)

5、Servlet生命周期

1、初始化阶段

2、运行阶段

3、销毁阶段

测试:

import javax.servlet.ServletResponse;
import java.io.IOException;

public class SmzqServlet extends GenericServlet {
    @Override
    public void destroy() {
        System.out.println("destroy is called");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("init is called");
    }

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

访问http://localhost:8080/test02image-20210419094254609

 再次访问image-20210419094317688

 结束项目image-20210419094342007

6、自动加载Servlet程序

<servlet>
        <!--    servlet的名称    -->
        <servlet-name>test01</servlet-name>
        <!--    对应类的名称    -->
        <servlet-class>com.fjh.P1Servlet</servlet-class>
        <!--    设置一个整数    -->
        <load-on-stratup>1</load-on-stratup>
    </servlet>

load-on-startup是servlet的一个子元素,用于指定Servlet被加载的时机和顺序,如果设置成负数或者没有设置,那么Servlet会在客户端首次请求的时候加载它,如果值为0或正整数,将会在web应用启动的时候加载Servlet,值越小优先级越高

7、HttpServlet

它是GenericServlet的子类,专门用于处理http请求

java

package com.fjh;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HttpServletTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet is called");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost is called");
    }
}

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test03</title>
    <link href="css/style.css" type="text/css" rel="stylesheet">
</head>
<body>
    <div class="main">
        <form action="/test03" method="post">
            <p><label for="user">用户名</label><input type="text" id="user" placeholder="请输入用户名"></p>
            <p><label for="pwd">密码</label><input type="password" id="pwd" placeholder="请输入密码"></p>
            <P><input type="submit" value="提交"></P>
        </form>
    </div>
</body>
</html>

当点击提交的时候会调用doPost方法

image-20210419103223305

三、HttpServletResponse接口

1.介绍:

HttpServletResponse接口来自于servlet规范中,在Tomcat中 存在servlet-api . jar
HttpServletResponse接口实现类由Http服务器负责提供
HttpServletResponse接口负责将doGet/doPost方法执行结果写入到[ 响应体]交给浏览器
4)开发人员习惯于将HttpServletResponse接口修饰的对象称为[响应对象]γ

2.主要功能:

1)将执行结果以二进制形式写入到[啊应体

//首先获取输出流
PrintWriter out = response.getWriter();
//然后将信息以二进制形式(不要使用write,它会把数字当成二进制来输出)
out.print("这里可以任何形式的数据");

2)设置响应头中[content-type]属性值,从而控制浏览器使用对应编译器将响应体二进制数据编译为[文字,图片,视频,命令]

//一定要在获取输出流之前就设置响应头
response.setContentType("text/html")

3.设置响应头中[location]属性,将-一个请求地址赋值给location,从而控制浏览器向指定服务器发送请求

//如果响应头中有location属性值,那么就会自动跳转到对应的地址,这也叫重定向
response.sendRedirect("https://antgcode.cn");

四、HttpsServletRequest接口

1.介绍:

HttpServletRequest接口来自于servlet规范中,在Tomcat中存 在servlet-api.jar

HttpservletRequest接口实现类由http服务器负责提供

HttpServletRequest接口负责在doGet/doPost方法运行时读取Http请求协议包中信息

4)开发人员习惯于将HttpServletRequest接口修饰的对象称为[ 请求对象]

2.作用:

1)可以读取Http请求协议包中[请求行]信息

        

String url = request.getRequestURL().toString();//获取url
        String uri = request.getRequestURI();//获取uri
        /*
        * uri:同一资源标识符 格式:/网站/动态资源名称
        * */
        String method = request.getMethod();//获取请求的方法

2)可以读取保存在Http请求协议包中[ 请求头或则[请求体]中请求参数信息

//获取请求名称
  Enumeration parameterNames = request.getParameterNames();
  while (parameterNames.hasMoreElements()){
      String paramName = (String) parameterNames.nextElement();
      //通过请求对象读取请求参数的值
      String value = request.getParameter(paramName);
      System.out.println(paramName+"-->"+value);
  }

浏览器以GET方式发送请求,请求参数保存在[请求头] , 在Http请求协议包到达Http服务器之后,第一件事就是进行解码请求头二进制内容由Tomcat负责解码,Tomcat9 .0默认使用[utf-8]字符集,可以解释一切国家文字
浏览器以POST方式发送请求,请求参数保存在[请求体],在Http请求协议包到达Http服务器之后,第一件事就是进行解码请求体二进制内容由当前请求对象(request)负责解码。request默认使用 [IS0-8859-1]字符集,一个东欧语系字符集
此时如果请求体参数内容是中文,将无法解码只能得到乱码

解决方法:

//post请求方式下,在读取请求体之前,应该通知请求体用utf-8解码
request.setCharacterEncoding("utf-8");

3)可以代替浏览器向Http服务器申请资源文件调用

五、请求对象与响应对象的生命周期

image-20210419153052020

image-20210419153144516

 六、默认欢迎资源文件的设置

在访问网站的时候,通常不会去记它的资源文件名 

例如:

正常请求:http://localhost:8080/myWeb/index.html

默认请求:http://localhost:8080/myWeb/

1、tomcat对于默认欢迎资源文件的配置

位置:tomcat安装位置/conf/web.xml

配置:

  

 <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

从上到下找,如果没有找到就返回404页面

1、设置当前网站的默认欢迎资源文件

位置:网站/web/WEB-INF/web.xml

配置:

    <we

lcome-file-list>
        <welcome-file>login.html</welcome-file>
        <welcome-file>user/finduser</welcome-file>
        <!--如果写动态资源的的话前面不要加/-->
    </welcome-file-list>

如果配置了当前网站的默认欢迎资源文件,那么tomcat中的就会失效

七、HTTP状态码

1、介绍:

​ 1)是由三位数字组成的一个符号

​ 2)Http服务器在推送响应包之前,根据本次的处理情况,将对应的状态码写入到响应包中

​ 3)通知浏览器如何处理这个响应结果,如果无法返回对应的文件,告诉浏览器原因

2、分类:

​ 1)组成:100-599 ;分为5大类

​ 2)1xx:

​ 最有特征的100:告诉浏览器本次返回的资源文件不是一个独立的资源文件,需要浏览器在接收到响应包之后,继续向http服务器索要依赖的其他资源文件

​ 3)2xx:

​ 最有特征的200:通知浏览器本次返回的资源文件是一个独立完整的资源文件,之后不需要再想服务器索要其他资源文件

​ 4)3xx:

​ 最有特征的302:通知浏览器本次返回的不是资源文件的内容,而是地址,需要浏览器根据这个地址自动发起请求索要这个资源文件

​ response.sendRedirect(“资源文件的地址”)就会返回一个状态码302

5)4xx:

​ 404:通知浏览器,由于在服务端没有定位到对应的资源文件

​ 405:通知浏览器,在服务端中,已经定位到了被访问的资源文件(Servlet)

​ 但是这个servlet对于浏览器采用的请求方式不能处理

​ 6)5xx:

​ 500:通知浏览器,资源已经定位到,但是servlet在处理请求期间,由于java异常导致处 理失败

八、多个Servlet之间的调用

1、前提条件

某些浏览器的请求,需要多个servlet协同处理,但是浏览器每次只能访问一个servlet,需要发起多吃请求才能得到服务,增加了用户获取服务的难度

2、提高用户使用感受

无论本次请求涉及到多少个servlet,用户只需要发一次请求即可

3、多个servlet之间调用的规则:

​ 1)重定向方案

​ 2)请求转发方案

4、重定向解决方案

1、原理:用户第一次手动请求访问one后,one工作完成后会将tow的地址写入到响应头的location属性中,然后tomcat将302状态码写入到状体行,浏览器接受到响应包后会自动的根据location的地址发起第二次请求,完成剩余任务

2、实现命令:response.senRedirect(“请求地址”);

3、特征

​ 1)请求地址:

​ 本网站资源:/网站名/资源文件名

​ 其他网站资源文件名:全路径

​ 2)请求的次数:最少发两次,只有第一次是用户手动发送的

​ 3)请求方式:GET

4、缺点

​ 服务器和浏览器需要进行多次往返,大量的实践浪费在了往返的次数上,浪费时间

5、请求转发解决方案

1、原理:用户调用one,one工作完毕后,通过当前的请求对象代替浏览器向tomcat发送请求,调用two,tomcat接受到这个请求后,自动调用tow来完成剩余工作

2、实现:请求对象代替浏览器向tomcat发送请求

//1.通过当前请求对象生成资源文件申请报告对象
RequsetDispatcher report = request.getRequestDispatcher("/资源文件名");//记得加/
//2.将报告的对象发送tomcat
report.forward(当前的请求对象,当前的响应对象)

3、优点:

​ 只发一次请求

​ 节省了服务端和浏览器的往返次数,增加了处理服务的速度

4、特点:

​ 只发送一次请求

​ 只能访问当前网站的资源request.getRequsetDispatcher("/资源文件名");

​ 请求方式:根据客户端的发起方式来决定,在请求转发的过程中,浏览器只发送了一个http请求包,参与本次的所有Servlet共享一个请求协议包

6、多个servlet实现数据共享

1、数据共享:one处理完成后,将产生的数据交给two来使用

2、servlet提供了四种数据共享方案

1)ServletContext接口

2)Cookie类

3)HttpSession接口

4)HttpServletRequest接口

九、ServletContext接口

1.介绍:

​ 1)来自于Servlet规范中的一个接口,在tomcat的servlet-api.jar中,在tomcat负责提供这个接口的实现类

​ 2)如果来给你个Servlet来自于同一个网站,彼此之间可以通过ServletContext实例来实现数据共享

​ 3)开发人员习惯于将ServletContext对象叫做“全局作用域对象”

2.工作原理

image-20210425111204951

 这个全局作用域对象相当于一个map

3.生命周期

1)Http服务器启动过程中,自动在内存中创建一个全局作用域对象

2)在Http服务器运行期间,一个网站只有一个全局作用域对象

3)在http服务器运行期间,全局作用域一直存活

4)在Http服务器准备关闭时,负责将全局作用域对象销毁

4.命令实现:

//获取全局作用对象
ServletContext application = request.getServletContext();
//存值
application.setAttribute("key",value);
//取值
Object key = application.getAttribute("key");

注意:初级程序员只能取数据,没资格向全局作用对象添加数据(一般这里只放关键数据)

十、Cookie

1.介绍

1)Cookie时Servlet规范中的一个工具类存在于tomcat提供的servlet-api中

2)Cookie存放当前用户的私人数据,在共享数据中提供服务质量

3)在现实生活中,Cookie相当于会员卡

2.原理

用户第一次向服务器端发起请求的时候,对应的Servlet会创建一个Cookie来存储当前用户的相关数据,工作完毕之后,将Cookie写入到响应头中交还给浏览器

浏览器接收到请求头之后,将Cookie存储在浏览器中,当浏览器第二次请求的时候会无添加的将该网站推送的Cookie写入到请求头中发送过去,然后服务器端就可以读取到这个共享数据

3.命令实现

OneServlet{
    public voie doGet(HttpServletRequset req,HttpServletResponse resp){
        //1.创建一个cookie对象,保存共享数据(当前用户数据)
        Cookie card1  =  new Cookie("key1","abc");
        Cookie card2  =  new Cookie("key2","bcd");
        //cookie也相当于一个map,一个cookie对象只能存储一个键值对,这个键值对的value只能是String,key不可以是中文
       //2.发卡:将cookie写入到响应头中,交给浏览器
        resp.addCookie(card1);
        resp.addCookie(card2);
    }
}
TwoServlet{
    public void doGet(HttpServletRequset req,HttpServletReponse resp){
        //1.调用请求对象从请求头中获取cookie
        Cookie cookieArray[] = req.getCookies();
        //2.循环遍历数组得到每一个cookie
        for(Cookie cookie:cookieArray){
            String key = cookie.getName();//获取key “key1”
            String value = cookie.getValue();//获取value “abc”
        }
    }
}

4.cookie的销毁时机

1.在默认的情况下,cookie对象保存在浏览器的缓存中,当浏览器关闭的时候就会销毁

2.在手动的设置情况下,要求浏览器将接收的cookie存放在客户端计算机硬盘上,同时需要指定cookie在硬盘上的存活时间,在存活时间范围内,即使关机也不会消失,存活时间到达的时候,会自动从硬盘上删除

3.代码实现:

cookie.setMaxAge(60);//cookie在硬盘上存活1分钟

十一、HttpSession接口

1.介绍

1)HttpSession接口来自于Servlet规范下的一个接口,存在于Tomcat中的servlet-api.jar

其实现类由Http服务器提供,实现类存在于servlet-api.jar中

2)如果两个Servlet来自同一个网站,并为同一个浏览器/用户提供服务,此时可以借助于HttpSession对象进行数据共享

3)开发人员习惯将HttpSession对象叫做:会话作用域对象

2.HttpSession和Cookie区别

1)存储位置:Cookie在客户端计算机中,Session在服务器内存中

2)数据类型:Cookie只支持存放String类型的数据,HttpSession可以支持任意类型(Object)

3)数据量:一个Cookie只能放一个数据,HttpSession可以存放任意多个数据

4)参照物:Cookie相当于客户在服务器端的会员卡,HttpSession相当于用户在服务器端的储物柜

3.命令实现

//1.调用请求对象向tomcat获取当前用户在服务器端的私人储物柜(Session)
HttpSession session = request.getSession();
//2.将数据添加到私人储物柜
session.setAttribute("key1",共享数据);
//3.获取私人存储柜的数据
Object obj = session.getAttribute("key");

4.Http服务器是如何将用户和服务器端的session关联起来的

Tomcat在创建HttpSession对象的时候,会为这个session创建一个唯一的编号

tomcat将编号保存到Cookie对象,推送到单曲浏览器缓存,Cookie:JSESSIONID=123456789

5.getSession() 于getSession(false);

1)getSession():如果当前用户已经拥有了自己的session,要求tomcat将这个session返回

如果没有自己的session,就为当前的用户创建一个全新的session

2)getSession(false):如果当前用户已经拥有了自己的session,要求tomcat将这个session返回

如果没有自己的session,就返回null

当需要判断用户身份合法性的时候用getSession(false);

6.HttpSession销毁时机

1.用户于HttpSession关联使用的Cookie只能放在浏览器缓存中

2.在浏览器关闭时,意味着用户与他的HttpSession关系被切断

3.由于tomcat无法监测浏览器何时关闭,因此在浏览器关闭时并不会导致tomcat将对应的HttpSession进行销毁

4.为了解决这个问题,Tomcat为每个HttpSession对象设置一个空闲时间

这个空闲时间默认为30分钟,如果HttpSession对象空闲时间达到30分钟,此时Tomcat就认为用户已经放弃了自己的HttpSession,此时tomcat就会销毁这个HttpSession

7.HttpSession手动设置

当前网站/web/WEB_INF/web.xml

<session-config>
    <session-timeout>5</session-timeout><!--最大空闲时间五分钟-->
</session-config>

十二、HttpServletRequset接口实现数据共享

1.介绍

1)如果在同一个网站中,两个Servlet之间通过请求转发方式进行调用,彼此之间共享一个请求协议包。因此Servlet之间共享一个请求对象,因此可以利用这个请求对象实现数据共享

2)若请求对象用来实现数据共享的时候,一般叫做请求作用域对象2.命令实现

OneServlet{
    public void doGet(HttpServletRequset req,HttpServletResponse resp){
        //1.将数据添加到请求作用域的attribute属性
        req.setAttribute("key1",数据);
        //2.向tomcat申请调用TwoServlet
        req.getRequsetDispatcher("/two").forword(req,resp);
        
    }
}

TwoServlet{
    public void doGet(HttpServletRequset req,HttpServletResponse resp){
        //从当前请求对象得到OneServlet写入的共享数据
        Object obj = req.getAttribute("key1");
        
    }
}

十三、Servlet扩展—监听器接口

1.介绍:

1)一组来自Servlet规范下的接口,共有8个接口,在servlet-api.jar中

​ 2)监听器接口需要由开发人员亲自实现,Http服务器提供jar包并没有对应的实现类

​ 3)监听器接口用于监控作用域对象生命周期变化时刻和作用域对象共享数据的变化

2.作用域对象:

​ 1)在Servlet规范中,认为在服务器端内存中可以在某些条件下为两个Servlet提供共享数据解决方案的对象被称为作用域对象

​ 2)Servlet规范下的作用域对象:

​ ServletContext:全局作用域对象

​ HttpSession:会话作用域对象

​ HttpServletRequest: 请求作用域对象

3.监听器接口实现类开发的三步:​

1)根据接口的实际情况,选择对应的监听器接口进行实现

​ 2)重写监听器接口声明(监听事件处理方法)

​ 3)在web.xml文件将监听器接口实现类注册到Http服务器

注册方法:

<listener>
<listener-class>com.fjh.listener.ServletContextTestListener</listener-class>
</listener>

4.ServletContextListener接口:

1)作用:监听ServletContext的创建与销毁

2)监听事件的处理方法:

//全局作用域对象被http服务器初始化的时候被调用
public void contextInitialized(ServletContextEvent servletContextEvent) {}
//全局作用域对象被http服务器销毁的时候出发使用
public void contextDestroyed(ServletContextEvent servletContextEvent) {}

5.ServletContextAttributeListener接口:

1)作用:监听ServletContext共享数据的变化时刻

2)监听事件处理方法:

//添加共享数据
public void contextAdd();
//更新共享数据
public void contextReplaced();
//删除共享数据
public void contextRemove();

3)全局作用域对象共享数据变化时刻

ServletContext application = request.getServletContext();
application.setAttribute("key1",100);//添加共享数据
application.setAttribute("key1",200);//更新共享数据
application.removeAttribute("key1");//删除共享数据

十四、使用监听器接口提高程序运行速度

1、正常时间消耗情况

Date beginDate = new Date();
int result = userDao.addUser(userName,password,sex,email);
Date endDate = new Date();
System.out.println("添加用户消耗的时间:"+(endDate.getTime()-beginDate.getTime())+"毫秒");

耗时:大概20毫秒左右

2、使用监听器提高运行速度

1)思路:

正常的情况下最消耗时间的是创建数据库Connection的时间,如果在tomcat加载的时候就将连接创建好,然后用的时候分配,不用的时候也不销毁,而是等待其他用户的连接,那么速度就可以提升

步骤:

1、在tomcat初始化的时候创建多个数据库连接对象,并放入Map中

2、用户添加的时候调用map中的连接然后使之处于使用状态,用完之后将其修改为空闲状态

3、在tomcat关闭的时候关闭所有的数据库连接

代码实现:

监听器类

package com.fjh.listener;

import com.fjh.util.DButil;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class ServletContextTestListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //获取全局作用域对象
        ServletContext application = servletContextEvent.getServletContext();
        //创建数据库连接并放入map中
        Map conMap = new HashMap<>();
        for(int i = 0;i<20;i++){
            try {
                Connection con = DButil.getConnection();
                conMap.put(con,true);
                System.out.println("连接对象被创建:"+con);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //将map放入全局作用对象中
        application.setAttribute("jdbcCon",conMap);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        //tomcat关闭的时候将连接断开
        ServletContext application = servletContextEvent.getServletContext();
        Map jdbcMap = (Map)application.getAttribute("jdbcCon");
        Iterator it = jdbcMap.keySet().iterator();
        while (it.hasNext()){
            Connection con = (Connection) it.next();
            if(con != null){
                DButil.close((Connection) con,null,null);
                System.out.println("连接对象被关闭"+con);
            }
        }
    }
}

JDBC工具类中重写的方法

//通过jdbcCon获取连接对象
    public static Connection getConnection(HttpServletRequest req) throws SQLException {
        ServletContext application = req.getServletContext();
        Map jdbcMap = (Map)application.getAttribute("jdbcCon");
        Iterator it = jdbcMap.keySet().iterator();
        Connection con = null;
        while (it.hasNext()){
            con = (Connection) it.next();
            boolean flag = (boolean)jdbcMap.get(con);
            if(flag){
                //调用的时候将flag置为false
                jdbcMap.put(con,false);
                break;
            }
        }
        return con;
    }
    //获取连接(原方法)
    public static Connection getConnection() throws SQLException {
        ResourceBundle bundle = ResourceBundle.getBundle("com.fjh.properties.jdbc");
        return DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),bundle.getString("password"));
    }
     //释放资源(jdbcCon)
    public static void close(HttpServletRequest req,Connection con, Statement statement, ResultSet resultSet){
        ServletContext application = req.getServletContext();
        Map jdbcMap = (Map)application.getAttribute("jdbcCon");
        jdbcMap.put(con,true);
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    //释放资源(原方法)
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }  

使用后添加用户用时:5-7毫秒

十五、Servlet扩展—过滤器接口(Filter)

1.介绍

1)来自于Servlet规范下的接口,在tomcat中存在于servlet-api.jar包

2)Filter接口实现类由开发人员负责提供,http服务器不负责提供

3)Filter接口在Http服务器调用资源文件之前,对Http服务器进行拦截

2.具体作用:

1)拦截Http服务器,帮助Http服务器检查当前请求的合法性

2)拦截Http服务器,对当前请求进行增强操作

3.Filter接口实现的步骤(三步)

1)创建一个java类实现FIlter接口

2)重写Filter接口中的都Filter方法

3)在web.xml注册

<!--将过滤器类交给tomcat-->
<filter>
    <filter-name>过滤器名称</filter-name>
    <filter-class>过滤器对应的实现类</filter-class>
</filter>
<!--通知tomcat在调用何种资源文件时需要被拦截-->
<filter-mapping>
    <filter-name>过滤器名称</filter-name>
    <url-pattern>/资源名称</url-pattern>
</filter-mapping>

4、过滤器检查请求合法性

xml配置

<!--  将过滤器实现类告知tomcat  -->
    <filter>
        <filter-name>FilterTest</filter-name>
        <filter-class>com.fjh.filter.FilterTest</filter-class>
    </filter>
<!--  绑定到url上  -->
    <filter-mapping>
        <filter-name>FilterTest</filter-name>
        <url-pattern>/mm.jpg</url-pattern>
    </filter-mapping>

java代码

package com.fjh.filter;

import javax.servlet.*;
import java.io.IOException;

/**
 * http://127.0.0.1:8080/p01?age=70
 *
 */
public class FilterTest implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器被创建");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        String age = servletRequest.getParameter("age");
        if(Integer.valueOf(age)<20){
            servletResponse.setContentType("text/html;charset=utf-8");
            servletResponse.getWriter().print("<font>小孩子要专心学习!</font>");
        }else{
            filterChain.doFilter(servletRequest,servletResponse);//放行
        }
    }

    @Override
    public void destroy() {
        System.out.println("过滤器被销毁");
    }
}

效果图:

age=15

image-20210425221855802

age=25

 5、过滤器对拦截的请求进行增强操作

<filter>
    <filter-name>charsetFilter</filter-name>
    <filter-class>对应的类</filter-class>
</filter>
<filter-mapping>
    <filter-name>charsetFilter</filter-name>
    <url-pattern>/*</url-pattern><!--对所有的资源进行拦截设置字符编码格式-->
</filter-mapping>

6、过滤器拦截地址的格式

1)拦截某个具体的文件

<url-pattern>/img/abc.jpg</url-pattern>

2)拦截某个文件下的所有资源文件

<url-pattern>/img/*</url-pattern>

3)拦截某一类型文件

<url-pattern>*.jpg</url-pattern>

4)调用网站下任意文件时拦截

<url-pattern>/*</url-pattern>

7、过滤器拦击用户非法登录

java

package com.fjh.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class VerifyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpSession session = req.getSession(false);
//        不过滤登录页面,登录请求
        String reqPath = req.getServletPath();
        if(reqPath.equals("/login.html")||reqPath.equals("/login_error.html")||reqPath.equals("/login")){
            filterChain.doFilter(req,servletResponse);//放行
        }else{
            if(session != null){
                filterChain.doFilter(req,servletResponse);//合法用户正常跳转
            }else {
                req.getRequestDispatcher("/login_error.html").forward(req,servletResponse);//非法用户跳转登录页面
            }
        }
    }
}

xml

    <filter>
        <filter-name>VerifyFilter</filter-name>
        <filter-class>com.fjh.filter.VerifyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>VerifyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mizui_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值