【JavaWeb】Servlet与过滤器

目录

Servlet

  • Server+Applet,是一种服务器端的Java应用程序
  • 只有当一个服务器端的程序使用了Servlet API的时候,这个服务端的程序才能称之为Servlet
  • Servlet是JavaWeb三大组件之一,三大组件是:Servlet程序、Filter过滤器、Listener监听器
  • Servlet是运行在服务器上的一个java小程序,它可以接受客户端发送过来的请求,并响应数据给客户端

Servlet做了什么

  • 本身不做任何业务处理
  • 只是接收请求并决定调用哪个JavaBean去处理请求
  • 确定用哪个页面来显示处理返回的数据

JSP与Servlet的关系

Servlet是运行在服务器端的Java应用程序

主要Servlet API介绍

  • javax.servlet.Servlet接口
    所有Java Servlet的基础接口类,规定了必须由Servlet具体类实现的方法集
  • javax.servlet.GenericServlet类
    是Servlet的通用版本,是一种与协议无关的Servlet
  • javax.servlet.http.HttpServlet类
    在GenericServlet基础上扩展的基于Http协议的Servlet

如何创建Servlet

  • 实现Servlet接口
  • 继承GenericServlet类
  • 继承HttpServlet类

Servlet中主要方法

  • init():Servlet的初始化方法,仅仅会执行一次
  • service():处理请求和生成响应
  • destroy():在服务器停止并且程序中的Servlet对象不再使用的时候调用,只执行一次

ServletRequest

  • 封装客户的请求信息
  • 作用相当于JSP内置对象request

ServletResponse

  • 创建响应信息,将处理结果返回给客户端
  • 作用相当于JSP内置对象response

ServletConfig

  • 包含了Servlet的初始化参数信息

Servlet生命周期

  1. 加载和实例化
  2. 初始化
  3. 处理请求
  4. 销毁
生命周期 谁来做 何时做
实例化 Servlet 容器 当Servlet容器启动或者容器检测到客户端请求时
初始化 Servlet 容器 实例化后,容器调用Servlet的init()初始化对象
处理请求 Servlet 容器 得到客户端请求并做出处理时
销毁 Servlet 容器 当程序中的Servlet对象不再使用的时候,或者Web服务器停止运行的时候

Servlet创建

java 复制代码
package com.zjl.servlet;

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

/**
 * @author: zjl
 * @datetime: 2024/4/10
 * @desc:
 */
public class HelloServlet extends HttpServlet {
    public HelloServlet() {
        System.out.println("生命周期之------------------创建实例");
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        String mycharset = config.getInitParameter("mycharset");
        System.out.println("初始化时加载配置中的参数为:" + mycharset);
        System.out.println("生命周期之------------------初始化");
    }

    //接收Get请求
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("生命周期之------------------处理请求");
        req.setCharacterEncoding("UTF-8");//设置请求字符集编码
        resp.setCharacterEncoding("UTF-8");//设置响应字符集编码
        req.setAttribute("key","value");//将数据保存在request域,以键值对方式
        req.getSession().setAttribute("sessionKey","sessionValue");//根据request获取所在的session会话,并向会话保存一个数据
        req.getRequestDispatcher("welcome.jsp").forward(req,resp);//转发跳转页面
    }
    //接收POST请求
    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("生命周期之------------------处理请求");
    }

    /*@Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("生命周期之------------------处理请求");
    }*/
    @Override
    public void destroy() {
        System.out.println("生命周期之------------------销毁");
    }
}

Servlet部署与运行

  • 修改web.xml(部署描述文件)
    • 添加:把Servlet内部名映射到一个Servlet类名
    • 添加:把用户访问的URL映射到Servlet的内部名
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <servlet>
    <servlet-name>helloServlet</servlet-name>
    <servlet-class>com.zjl.servlet.HelloServlet</servlet-class>
    <init-param>
      <param-name>mycharset</param-name>
      <param-value>utf-t</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello.do</url-pattern>
  </servlet-mapping>
</web-app>
  • 通过URL访问Servlet

ServletConfig类

  • ServletConfig类从类名上来看,就知道是Servlet程序的配置信息类
  • Servlet程序和ServletConfig对象都是由Tomcat负责创建,我们负责调用
  • Servlet程序默认是第一次访问的时候创建,ServletCongfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象

ServletConfig类的三大作用

  1. 可以获取Servlet程序的别名servlet-name的值
  2. 获取初始化参数init-param
  3. 获取ServletContext对象
java 复制代码
	@Override
    public void init(ServletConfig config) throws ServletException {
        String mycharset = config.getInitParameter("mycharset");
        System.out.println("初始化时加载配置中的参数为:" + mycharset);
        System.out.println("生命周期之------------------初始化");
        config.getServletContext();
        config.getServletName();
    }

ServletContext类

  1. ServletContext是一个接口,它表示Servlet上下文对象
  2. 一个web工程,只有一个ServletContext对象实例
  3. ServletContext对象是一个域对象
  4. ServletContext是在web工程部署启动的时候创建,在web工程停止的时候销毁

域对象:是可以像Map一样存取数据的对象
这里的域指的是存取数据的操作范围是整个web工程

存数据 取数据 删除数据
Map put() get()
域对象 setAttribute() getAttribute()

ServletContext类的四个作用

  1. 获取web.xml中配置的上下文参数context-param
    属于整个工程,也就是说所有的Servlet都可以访问到
xml 复制代码
<!--context-param是上下文参数(它属于整个web工程)-->
<context-param>
  <param-name>username</param-name>
  <param-value>context</param-value>
</context-param>
<!--context-param是上下文参数(它属于整个web工程)-->
<context-param>
  <param-name>password</param-name>
  <param-value>root</param-value>
</context-param>
  1. 获取当前的工程路径,格式:/工程路径
java 复制代码
//2、获取当前的工程路径,格式: /工程路径
System.out.println("当前工程路径:" + servletContext.getContextPath());
  1. 获取工程部署后在服务器硬盘上的绝对路径
java 复制代码
	@Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取工程部署后在服务器硬盘上的绝对路径
        /**
         *      / 斜杠被服务器解析地址为http://ip:port/工程名/  映射到IDEA代码的web目录
         */
        System.out.println("工程部署的路径是:" + servletContext.getRealPath("/"));
        System.out.println("工程下imgs目录的绝对路径是:" + servletContext.getRealPath("/imgs"));
        System.out.println("工程下imgs目录下1.jpg的绝对路径是:" + servletContext.getRealPath("/imgs/1.jpg"));
    }
  1. 像Map一样存取数据
  • 当我们存储之前,还未存储的时候,此时去获取数据,是获取不到即返回null
  • 一个web工程,只有一个ServletContext对象实例,因此地址一致
java 复制代码
	@Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取ServletContext对象
        ServletContext servletContext = getServletContext();
        // System.out.println(servletContext);
        System.out.println("保存之前Context1 中获取域数据key1的值是:" + servletContext.getAttribute("key1"));

        servletContext.setAttribute("key1", "value1");

        System.out.println("Context1 中获取域数据key1的值是:" + servletContext.getAttribute("key1"));
    }

HTTP协议

  • 协议是指双方、或多方,相互约定好的,大家都需要遵守的规则,叫协议
  • 所谓HTTP协议,就是指:客户端和服务端之间通信时,发送的数据,需要遵守的规则,叫HTTP协议
  • HTTP协议中的数据又叫报文
  • 客户端给服务器发送数据叫请求
  • 服务器给客户端回传数据叫响应

GET请求和POST请求

GET

格式
  1. 请求行
    请求的方式
    请求的资源路径[+?+请求参数]
    请求的协议的版本号
  2. 请求头
    key : value 组成,不同的键值对,表示不同的含义

POST

格式
  1. 请求行
    请求的方式
    请求的资源路径[+?+请求参数]
    请求的协议的版本号
  2. 请求头
    key : value 组成,不同的键值对,表示不同的含义
  3. 请求体 ==> 就是发送给服务器的数据

常用的请求头的说明

  • Accept:表示客户端可以接受的数据类型
  • Accpet-Language:表示客户端可以接受的语言类型
  • User-Agent:表示客户端浏览器的信号
  • Host:表示请求时的服务器ip和端口号

GET请求和POST请求的种类(即哪些是)

GET请求有:
  1. form 标签 method="get"
  2. a 标签
  3. link 标签引入 css 文件
  4. Script 标签引入 js 文件
  5. img 标签引入图片
  6. iframe 引入 html 页面
  7. 在浏览器地址栏中输入地址后敲回车

POST请求有:

  • form 标签 method="post"

响应的HTTP协议格式

  1. 响应行

    响应的协议和版本号

    响应状态码

    响应状态描述符

  2. 响应头

    key : value 不同的响应头,有其不同的含义

  3. 响应体 ==> 就是回传给客户端的数据

常用的响应码

响应码 说明
200 表示请求成功
302 表示请求重定向
404 表示请求服务器以及收到了,但是你要的数据不存在(请求地址错误)
500 表示服务器已经收到请求,但是服务器内部错误(代码错误)

MIME类型说明

  • MIME是HTTP协议中的数据类型
  • MIME 的英文全称是"Multipurpose Internet Mail Extensions" 多功能 Internet 邮件扩充服务。MIME 类型的格式是"大类型/小类型",并与某一种文件的扩展名相对应
常见的MIME类型
文件 MIME类型
超文本标记语言文本 .html, .htm text/html
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
GIF图形 .gif image/gif
JDEG图形 .jpeg, .jpg image/jpeg
au声音文件 .au audio/basic
MIDI音乐文件 .mid, .midi audio.midi, audio/x-midi
RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg, .mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar

HttpServletRequest类

  • 对应JSP的内置对象request
  • 每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中,然后传递到service方法或doGet方法或doPost方法中给我们使用。而我们可以通过HttpServletRequest对象,获取到所有请求的信息
  • 普通的访问无法访问到WEB-INF目录下的内容,但是请求转发可以访问到
java 复制代码
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/WEB-INF/form.html");
  • 无法访问工程以外的资源,因为默认放本工程目录下
java 复制代码
RequestDispatcher requestDispatcher = req.getRequestDispatcher("http://www.baidu.com");//会报错

常用方法

方法名 作用
getRequestURI() 获取请求的资源路径
getRequestURL() 获取请求的统一资源定位符(绝对路径)
getRemoteHost() 获取客户端的ip地址
getHeader() 获取请求头
getParameter() 获取请求的参数
getParameterValues() 获取请求的参数(多个值的时候使用)[如复选框]
getMethod() 获取请求的方式GET或POST
setAttribute(key, value) 设置域数据
getAttribute(key) 获取域数据
getRequestDispatcher() 获取请求转发对象

HttpServletResponse类

  • 对应JSP内置对象response
  • HttpServletResponse类和HttpServletRequest类一样,每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用。HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息
  • 我们如果需要设置返回给客户端的信息,都可以通过HttpServletResponse对象来进行设置
  • 不共享Request域中数据
  • 不能访问WEB-INF下的资源。是因为WEB-INF是受保护的,而浏览器是不能够访问受保护的,当重新第二次到新地址,也是浏览器发送请求,因此不能访问到受保护的WEB-INF目录
  • 可以访问工程下的资源
类别 表示 作用
字节流 getOutputStream() 常用于下载(传递二进制数据)
字符流 getWriter() 常用于回传字符串(常用)

注意:两个流同时只能使用一个
使用了字节流,就不能再使用字符流了,反之亦然,否则就会报错

@WebServlet注解

  • 在Servlet中,设置了@WebServlet注解,当请求该Servlet时,服务器就会自动读取当中的信息

  • 如果注解@WebServlet("/category"),则表示该Servlet默认的请求路径为.../category,这里省略了urlPatterns属性名,完整的写法应该是:@WebServlet(urlPatterns = "/category")

  • 如果在@WebServlet中需要设置多个属性,必须给属性值加上属性名称,中间用逗号隔开,否则会报错.

  • 若没有设置@WebServlet的name属性,默认值会是Servlet的类完整名称.

  • 在servlet3.0以后,web.xml中对Servlet配置,同样可以在@WebServlet注解中配置.

属性列表

属性名 类型 描述
name String 指定Servlet 的 name 属性,等价于 。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。
value String[] 该属性等价于 urlPatterns 属性。两个属性不能同时使用。
urlPatterns String[] 指定一组 Servlet 的 URL 匹配模式。等价于标签。
loadOnStartup int 指定 Servlet 的加载顺序,等价于 标签。
initParams WebInitParam[] 指定一组 Servlet 初始化参数,等价于标签。
asyncSupported boolean 声明 Servlet 是否支持异步操作模式,等价于 标签。
description String 该 Servlet 的描述信息,等价于 标签。
displayName String 该 Servlet 的显示名,通常配合工具使用,等价于 标签。

过滤器

拦截所有访问web资源的请求或者响应(servlet、Jsp页面、HTML页面),从而实现我们自己的业务逻辑,这些逻辑可以是实现访问权限的控制、过滤敏感词、压缩响应等功能。

  • 是向Web应用程序的请求和响应添加功能的Web服务组件
  • 过滤器可以统一地集中处理请求和响应
  • 使用过滤器技术实现对请求数据的过滤

原理

过滤器是"链接"在容器的处理过程中的,它会在servlet处理器之前访问进入的请求,并且在响应信息返回客服端之前访问这些响应信息。这样就可以动态的修改请求和响应中的内容。

代码

java 复制代码
package com.zjl.filter;

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

/**
 * @author: zjl
 * @datetime: 2024/4/10
 * @desc:
 */
public class MyCharsetFilter implements Filter {
    private String encode;
    public MyCharsetFilter(){
        System.out.println("生命周期之------创建");
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        encode = filterConfig.getInitParameter("encode");
        System.out.println("生命周期之------初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("生命周期之------执行过滤");
        servletResponse.setCharacterEncoding(encode);
        servletRequest.setCharacterEncoding(encode);
        filterChain.doFilter(servletRequest,servletResponse);//执行过滤
    }

    @Override
    public void destroy() {
        System.out.println("生命周期之------销毁");
    }
}

配置

xml 复制代码
<filter>
    <filter-name>mycharset</filter-name>
    <filter-class>com.zjl.filter.MyCharsetFilter</filter-class>
    <init-param>
      <param-name>encode</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>mycharset</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

生命周期

  • 实例化
  • 初始化:init()
  • 过滤:doFilter()
  • 销毁:destroy()

destroy()

  • 当web服务器调用该方法时,表示过滤器将被销毁。

init()

  • 当web服务器调用该方法时,表示过滤器将被注册到服务中

doFilter()

  • 当服务器调用Filter中的doFilter()方法,它会将每一个请求或者响应传递给下一个资源

备注

  • Filter是在应用启动是被创建和初始化的。
  • Filter是单例多线程的(创建和初始化只会被执行一次)
  • doFilter()方法无论是那一个线程访问,只要由该Filter进行过滤,那么就会执行该Filter的doFilter()方法,并且是每过滤一次就会执行一次doFilter()。
  • Filter中destroy方法是在应用被停止时调用的,它意味着销毁这个Filter。
  • FilterConfig指的是Filter在web.xml中的注册信息 ,它将注册信息进行封装,然后通过形参的方式传给初始化方法

<filter-mapping>

  • <filter-mapping>标签表示拦截匹配,也就是要拦截那些请求。
  • <filter-name>:要拦截的过滤器名称
  • <url-pattern>:拦截那些路径

<url-pattern>

  • 注意Filter中在写拦截所有路径的时候只能写成/*,而不能写成/,因为写成/它就不走拦截器中的doFilter方法了。

  • 在Servlet中/*即会拦截动态资源又会拦截静态资源,而/不会拦截动态资源

Filter里面的标签

  • dispatcher表示分发器,表示过滤器所拦截的资源被servlet容器调用的方式,可以是REQUEST,INCLUDE,FORWARD,ERROR中的任何一个,默认是REQUEST。
  • 用户可以设置多个<dispatcher>子元素用来指定过滤器对资源的多种调用方式进行拦截。
属性 作用
FORWARD 表示当前过滤器只会拦截由一个Servlet通过RequestDispatcher的forward()完成跳转
INCLUDE 表示当前过滤器只会拦截由一个Servlet通过RequestDispatcher的include()完成跳转
REQUEST 表示当前过滤器会拦截普通请求,但对于forward()与include()的跳转不进行拦截,REQUEST是默认的。
ERROR 表示当跳转到指定的错误处理页面时,这个跳转请求会被当前过滤器拦截

过滤器链

多个过滤器会形成过滤器链

总结:执行原理

Servlet的执行原理:

  • 在Servlet中有两个Map,这两个Map的key均为Servlet注册时的值,但value是不同的。第一个Map的value是Servlet实例对象的引用,第二个Map的value为的值,即Servlet类的全限定类名。

  • 当对Servlet的请求到达Servlet容器时,会先对请求进行解析,使用该解析出的URL,作为比较对象,从第一个Map中查找是否有匹配的key,若不存在匹配的key,那么读取其value,即Servlet对象的引用,执行该Servlet的service()方法。

  • 若不存在匹配的key ,那么再从第二个Map中查找是否有匹配的key。若存在,这读取其value,即读取其value,即要访问的Servlet的全限定类名。然后使用反射机制创建该Servlet实例,并将该实例写入到第一个Map中,然后在执行该Servlet的service()方法。

  • 若第二个Map中也没有找到匹配的key,那么就跳转到错误处理页面404。

Filter的执行原理:

  • 一个数组与一个Map :

    • 一个Map:Map的key为的值,value为Filter实例对象的引用
    • 一个数组:存在着与请求相匹配的所有Filter
  • 当对某资源的请求到达Web容器时,会先对请求进行解析,使用解析出的URI作为比较对象,从Map中查找是否存在相匹配的key。若存在,那么读取其value,即Filter对象的引用,将该应用存入到数组中。然后继续向后查找,直到将Map查找完毕。这样在数组中就会存在按照查找顺序排好序的Filter引用。

  • 数组初始化完毕后,开始按照数组元素顺序进行执行。所有数组中的Filter全部执行完毕后,再跳转到请求的目标资源。

相关推荐
陈王卜10 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、10 分钟前
Spring Boot 注解
java·spring boot
java亮小白199715 分钟前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF22 分钟前
java Queue 详解
java·队列
武子康43 分钟前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs
武子康1 小时前
大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本
java·大数据·数据仓库·hive·hadoop·mysql
苏-言1 小时前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
界面开发小八哥1 小时前
更高效的Java 23开发,IntelliJ IDEA助力全面升级
java·开发语言·ide·intellij-idea·开发工具
草莓base1 小时前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
Allen Bright1 小时前
maven概述
java·maven