首页 > 其他分享 >Servlet梳理

Servlet梳理

时间:2024-11-05 12:16:43浏览次数:5  
标签:web service tomcat Servlet public servlet 梳理

文章目录

1、Servlet概述

1_介绍

在这里插入图片描述

  1. S e r v l e t Servlet Servlet 是一个接口,即规范。

  2. 定义的实现类必须实现接口中的所有的抽象方法。

  3. S e r v l e t Servlet Servlet 全称 Server Applet 服务器端的程序。

    是 S u n Sun Sun公司提供一套规范,用来处理客户端请求、响应给浏览器的动态web资源。

    其实 S e r v l e t Servlet Servlet的实质就是 j a v a java java代码,通过 j a v a java java的 A P I API API动态的向客户端输出内容,并且从客户端接收数据。

  4. 一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现 S e r v l e t Servlet Servlet 接口

2_Servlet作用

浏览器访问的静态资源即html

web资源除了静态资源还有动态资源,即数据可以实现变化,并且前端浏览器通过动态资源可以实现数据的交互。

那么如果想实现客户端访问服务器的动态资源,需要我们在后端中定义类直接或者间接实现 S e r v l e t Servlet Servlet接口。

在这里插入图片描述

  1. 接收客户端的请求
  2. 处理业务逻辑
  3. 响应数据给浏览器客户端

2、Servlet开始

1_结构

在这里插入图片描述

2_实现步骤

1.创建web项目

2.导入 S e r v l e t Servlet Servlet 依赖


<!--导入servlet依赖-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
</dependency>

3.在创建的web项目中自定义类实现 S e r v l e t Servlet Servlet接口

4.在自定义类中实现 S e r v l e t Servlet Servlet接口中的所有的抽象方法

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

//3.在创建的web项目中自定义类实现Servlet接口
public class HelloWorldServlet implements Servlet {
    //4.在自定义类中实现Servlet接口中的所有的抽象方法 ctrl+i
    @Override
    public void init(ServletConfig config) throws ServletException {

    }

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

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        //5.在实现Servlet接口的service方法体中书写代码处理业务逻辑
        System.out.println("servlet入门案例");
    }

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

    @Override
    public void destroy() {

    }

}

5.在实现 S e r v l e t Servlet Servlet接口的service方法体中书写代码处理业务逻辑

void service(ServletRequest req, ServletResponse res)  

6.在web项目的核心配置文件web.xml中配置访问 s e r v l e t servlet servlet 的路径。

<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">
    <display-name>Archetype Created Web Application</display-name>

    <!--
     5.在web项目的核心配置文件web.xml中配置访问servlet的路径。
    	    说明:这样配置是告知tomcat有具体的Servlet类需要被访问。
  -->
    <!--
        1.<servlet> 表示将当前Servlet类注册到tomcat中,告知tomcat有一个类要被访问
        一个servlet标签对应一个servlet对象
    -->
    <servlet>
        <!--
            表示当前要被访问类的标识,在当前web.xml中要唯一,helloWorldServlet属于标识符
        -->
        <servlet-name>helloWorldServlet</servlet-name>
        <!--
            配置要访问 的servlet类,必须是类的全路径:包名.类名。
            说明:tomcat底层通过获取这里的类全路径使用反射技术调用当前类的无参构造方法创建对象
        -->
        <servlet-class>com.example.sh.HelloWorldServlet</servlet-class>
    </servlet>
    <!--
        配置要访问的servlet类的映射路径
    -->
    <servlet-mapping>
        <!--这里要和上面的servlet-name文本值一致,这里找到上面的servlet-name-->
        <servlet-name>helloWorldServlet</servlet-name>
        <!--浏览器上地址栏上输入的映射路径及访问路径,这里必须加/-->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

说明:这样配置是告知 t o m c a t tomcat tomcat有具体的 S e r v l e t Servlet Servlet类需要被访问。

7.启动 t o m c a t tomcat tomcat

8.在浏览器中访问 S e r v l e t Servlet Servlet 类

3_执行原理

在这里插入图片描述

说明:

  1. 当我们运行的时候, t o m c a t tomcat tomcat之所以会启动,是因为程序入口(main方法)在 t o m c a t tomcat tomcat中

  2. t o m c a t tomcat tomcat开始运行,会加载web项目里面的配置文件web.xml(xml解析,读取数据)

    主要是根据url-pattern 找到对应的servlet-class

  3. 然后 t o m c a t tomcat tomcat 进入等待状态(永不停止,除非手动关闭)

  4. 当用户在浏览器中输入地址:http://localhost:8080/hello就会定位到 t o m c a t tomcat tomcat的访问的项目下面的某个 s e r v l e t servlet servlet中

  5. t o m c a t tomcat tomcat会根据 /hello 的 s e r v l e t servlet servlet的虚拟路径 找到HelloServlet的全限定名

  6. t o m c a t tomcat tomcat底层通过反射创建HelloServlet的对象,并调用HelloServletservice方法:

    Class clazz = Class.forName("全限定名");
    Servlet servlet = clazz.newInstance();//实际上HelloServlet对象,向上转型
    servlet.service();
    

4_生命周期

生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程。

生命周期的api:

// 1. servlet对象创建完毕,使用对象调用此方法,初始化方法,只有在第一次访问的时候执行一次
public void init(ServletConfig servletConfig);
// 2. 用户访问servlet时,调用此方法 (每次访问都会调用一次)
public void service(ServletRequest servletRequest, ServletResponse servletResponse);
// 3. servlet对象销毁时,调用此方法
public void destroy();

S e r v l e t Servlet Servlet 生命周期的api执行时机图解

在这里插入图片描述

  • 创建(默认情况下)

    用户第一次访问时, t o m c a t tomcat tomcat 服务器创建 s e r v l e t servlet servlet,执行init方法

  • 运行(提供服务)

    用户每次访问时,都执行service方法

  • 销毁

    服务器正常关闭时, t o m c a t tomcat tomcat 服务器销毁 s e r v l e t servlet servlet,执行destroy方法

代码实现:

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

public class Life01Servlet implements Servlet {
    /*
        反射调用无参构造方法创建对象
     */

    public Life01Servlet() {
        System.out.println("无参构造方法执行了......");
    }

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

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

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

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

    @Override
    public void destroy() {
        System.out.println("destroy......");
    }
}

结果:

在这里插入图片描述

5_配置立刻加载

服务器启动,立刻加载 S e r v l e t Servlet Servlet对象:

  1. 问题:发现 init 默认第一次被访问的时候才调用,适合用来初始化项目数据

    如果项目数据很多,加载就需要一定的时间,这样就会给用户的体验不好,因为要等比较久的时间

  2. 解决:服务器一启动,就执行init方法

  3. 实现:在web.xml核心配置文件中对应的 s e r v l e t servlet servlet 标签中按照如下配置:

注意:

  1. 使用<load-on-startup></load-on-startup>标签进行配置,表示标记容器是否应该在启动的时候加载这个 s e r v l e t servlet servlet(实例化并调用其init()方法)

  2. 它的文本值必须是一个整数,表示 s e r v l e t servlet servlet应该被载入的顺序

  3. 如果文本值是负数:默认值是-1 【用户第一次访问时,创建】

  4. 当值大于等于0时,表示容器在应用启动时就加载并初始化这个 s e r v l e t servlet servlet;

  5. 正数的值越小,该 s e r v l e t servlet servlet的优先级越高,应用启动时就越先加载。

  6. 当值相同时,容器就会自己选择顺序来加载

<servlet>
    <servlet-name>life01Servlet</servlet-name>
    <servlet-class>com.example.sh.Life01Servlet</servlet-class>
    <!--
        load-on-startup 标签可以让tomcat服务器启动就创建对应的servlet。标签文本值必须是整数:
        数字越小,创建servlet的优先级越高
    -->
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>life01Servlet</servlet-name>
    <url-pattern>/life01</url-pattern>
</servlet-mapping>

load-on-startup 标签可以让 t o m c a t tomcat tomcat服务器启动就创建对应的 s e r v l e t servlet servlet。标签文本值必须是整数——数字越小,创建 s e r v l e t servlet servlet的优先级越高,建议是大于等于0的整数。

<load-on-startup>2</load-on-startup>

配置load-on-startup标签后 s e r v l e t servlet servlet生命周期如下:

在这里插入图片描述

6_Servlet实现方式

一共有三种:

在这里插入图片描述

1.自定义类实现 S e r v l e t Servlet Servlet接口

2.自定义类继承抽象类GenericServlet

解决问题:

  • S e r v l e t Servlet Servlet中使用频率最高,最重要的方法是service方法(大部分场景),但是我们每次编写 S e r v l e t Servlet Servlet实现类,都是直接实现 S e r v l e t Servlet Servlet接口,重写5个抽象方法(太冗余了)
  • 我们可以自定义类继承GenericServlet抽象类,只在子类中重写service即可。不用重写所有的抽象方法。
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/*
1.自定义类继承GenericServlet类
 */
public class Demo01Servlet extends GenericServlet {


    //    2.在子类中重写service方法,处理业务逻辑
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("service....");
    }
}

web.xml中进行映射路径的配置

<!--3.在web.xml中进行映射路径的配置-->
<servlet>
    <servlet-name>demo01Servlet</servlet-name>
    <servlet-class>com.example.sh.Demo01Servlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>demo01Servlet</servlet-name>
    <url-pattern>/demo01</url-pattern>
</servlet-mapping>

3.自定义类继承抽象类HttpServlet 重点

解决问题:

  • 我们在前端的常用的请求方式有两种(get/post)。

  • 但我们现在的service方法无论什么请求方式都会统一的执行service方法,我们无法很好的区别是哪一种请求方式。

  • 解决问题:我们可以自定义类继承HttpServlet就可以根据不同的请求做不同的处理:get/post

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

/*
    1.自定义类继承HttpServlet
 */
public class Demo02Servlet extends HttpServlet {
    /*
        	2.在子类中根据不同的请求方式重写请求方式的方法:
		    	get请求---重写doGet方法
		    	post请求---重写doPost方法
     */
    //	3.在方法体中书写处理业务逻辑的代码
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	//GET请求执行的方法
        System.out.println("get....");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	//POST请求执行的方法
        System.out.println("post....");
    }
}

实现 s e r v l e t servlet servlet方式三的好处:

  1. 可以根据不同的请求执行对应的方法

  2. 可以处理满足 h t t p http http协议的请求和响应

ServletRequest这个对象封装了浏览器发送的所有请求数据,兼容大部分协议。

HttpServletRequest是子接口,可以匹配 h t t p http http协议下的所有请求。

执行流程

正常浏览器访问 t o m c a t tomcat tomcat服务器需要访问 s e r v l e t servlet servlet接口中的service方法,但是方式三在子类中没有重写 s e r v l e t servlet servlet中的service方法,只重写了doGetdoPost方法,那么底层是如何执行的呢?

在这里插入图片描述

当我们访问自定义类的 s e r v l e t servlet servlet的时候先访问HttpServlet类实现 S e r v l e t Servlet Servlet接口中的service方法,在service方法体中调用了重载的service方法,在该方法体内部获取请求方式,根据不同的请求方式来执行对应的方法。

7_Servlet映射路径

一个 S e r v l e t Servlet Servlet映射单个url

在这里插入图片描述

一个 S e r v l e t Servlet Servlet映射多个url

在这里插入图片描述

注解版本:

在这里插入图片描述

8_Servlet映射路径配置规范

s e r v l e t servlet servlet 映射路径一共有四种:

1.完全路径匹配:就是访问什么在web.xml的<url-pattern>/path02</url-pattern>标签文本中配置什么路径。/hello /user

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

public class PathOneServlet extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("PathOneServlet....");
    }
}
<servlet>
    <servlet-name>pathOneServlet</servlet-name>
    <servlet-class>com.example.sh.PathOneServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>pathOneServlet</servlet-name>
    <!--完全路径匹配-->
    <url-pattern>/user/one</url-pattern>
</servlet-mapping>

2.目录匹配:/user/* 只要访问以/user开始的的路径都可以访问对应的 S e r v l e t Servlet Servlet。

public class PathTwoServlet extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("PathTwoServlet....");
    }
}
<servlet>
    <servlet-name>pathTwoServlet</servlet-name>
    <servlet-class>com.example.sh.PathTwoServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>pathTwoServlet</servlet-name>
    <!--目录匹配-->
    <url-pattern>/user/*</url-pattern>
</servlet-mapping>

3.后缀名匹配:*.do *.action(注意这里不能书写/),访问以.do或者.action结尾的资源路径(后缀都属于标识符)。

<servlet>
    <servlet-name>pathThrServlet</servlet-name>
    <servlet-class>com.example.sh.PathThrServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>pathThrServlet</servlet-name>
    <!--后缀名匹配,前面不能加/-->
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

4.缺省路径:/ 如果上述三种路径都不满足就访问缺省路径。

<servlet>
    <servlet-name>pathFourServlet</servlet-name>
    <servlet-class>com.example.sh.PathFourServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>pathFourServlet</servlet-name>
    <!--缺省路径匹配-->
    <url-pattern>/</url-pattern>
</servlet-mapping>

后缀名匹配和缺省路径都不推荐去配置:

  • 缺省路径会使如index.html这种资源无法被访问,只能访问缺省路径的 s e r v l e t servlet servlet。

  • 后缀名匹配也会导致某一类后缀的静态资源无法访问,比如:.html

上述访问路径的优先级: 完全路径匹配 > 目录匹配 > 后缀名匹配 > 缺省路径

9_相对路径

绝对路径两种写法:

  1. 带网络三要素的绝对路径:

    http://ip地址:端口号/资源路径

  2. 不带网络三要素的绝对路径:

    /资源路径 这里的/不能省略 ,要求访问的资源必须在同一个服务器上。

相对路径:不是相对当前项目,而是针对当前浏览器地址栏上的url而言的。

案例:

  • 假设我们在浏览器地址栏访问的页面路径: http://localhost:8080/demo01.html

  • 而在demo01.html页面想使用相对路径访问 s e r v l e t servlet servlet:http://localhost:8080/pathAbso

说明:

  • 如果在http://localhost:8080/demo01.html 页面中访问 http://localhost:8080/pathAbso 的 s e r v l e t servlet servlet,我们通过url观察发现只有最后一级目录不一样。

  • 所以在demo01.html页面中相对的路径的写法是:./pathAbso 这里的./表示当前路径,可以省略不写即直接写 pathAbso

10_常见问题

1.遇到500错误

表示服务器内部异常。

在这里插入图片描述

2.遇到404错误

浏览器客户端访问服务器的资源不存在。

在这里插入图片描述
注意:报404的根本原因是用户操作不当导致的。

3.遇到405错误

服务器 s e r v l e t servlet servlet 没有重写doGet或者doPost方法。

在这里插入图片描述

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

/*
    TODO:编写Servlet常见异常
        1.服务器内部出现异常===在浏览器中显示的是500:HTTP Status 500 – Internal Server Error
            解决方案:找出异常位置修改代码
        2.浏览器出现404===就是用户问题,用户操作不当,访问的资源在服务器中不存在,基本都是路径有问题。HTTP Status 404 – Not Found
            解决方案:
                1)查看你在地址栏上输入的地址路径和服务器中的资源路径是否匹配
                2)当前项目配置了虚拟路径,但是你访问的时候没有加虚拟路径
                3) 访问的路径在当前项目中存在,但是在当前项目中的target位置不存在,
                    执行maven生命周期命令===clean清除target,重启启动tomcat即可
        3.浏览器出现405===子类Servlet没有重写父类HttpServlet类中的doGet和doPost方法导致调用了父类
            HttpServlet中doGet和doPost方法 HTTP Status 405 – Method Not Allowed
            解决方案:子类重写HttpServlet的doGet和doPost方法,并且在子类方法体中不能调用父类中的doGet和doPost方法,不能书写:
                super.doGet(req, resp);
 */
public class ExceptionDemo01Servlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //调用父类HttpServlet类中doGet(req, resp),那么就会报错HTTP Status 405 – Method Not Allowed
        //详见父类源码
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }
}

4.启动服务器报错

注意:只要启动服务器报错基本都是你的路径有问题。

路径没有书写 /

<url-pattern>demo04</url-pattern>

在这里插入图片描述

3、Servlet3.0注解开发

t o m c a t tomcat tomcat 7以上的版本都支持 S e r v l e t Servlet Servlet 3.0

使用web.xml配置映射路径的方式属于 s e r v l e t 2.5 servlet2.5 servlet2.5的技术。

从 s e r v l e t 3.0 servlet3.0 servlet3.0开始引入注解配置访问 s e r v l e t servlet servlet取代了web.xml配置。

1_Servlet3.0新增特性

  1. 注解支持; S e r v l e t Servlet Servlet、FilterListener无需在web.xml中进行配置,可以通过对应注解进行配置;
  2. 支持Web模块;
  3. S e r v l e t Servlet Servlet异步处理;
  4. 文件上传API简化;

2_Servlet3.0的注解

  1. @WebServlet :修饰 S e r v l e t Servlet Servlet类,用于部署 S e r v l e t Servlet Servlet类。
  2. @WebFilter:修饰Filter类,用于部署Filter
  3. @WebInitParam:与@WebServlet@WebFilter注解连用,为它们配置参数
  4. @MultipartConfig:修饰 S e r v l e t Servlet Servlet类,指定该 S e r v l e t Servlet Servlet类负责处理multipart/form-data类型的请求(主要用于处理上传文件)
  5. @ServletSecurity:修饰 S e r v l e t Servlet Servlet类,与 J A A S JAAS JAAS(Java验证和授权API)有关的注解
  6. @HttpConstrait:与@ServletSecurity连用
  7. @HttpMethodConstrait:与@ServletSecurity连用

示例代码片

修饰过滤器Filter

@WebFilter(
        filterName="log",
        urlPatterns={"/*"},
        initParams={
        @WebInitParam(name="encoding",value="GBK"),
        @WebInitParam(name="loginPage",value="/login.jsp")
        })
public class MyFilter implements Filter {
    //内容省略......
}

修饰 S e r v l e t Servlet Servlet

在这里插入图片描述

@WebServlet(name="test",
    urlPatterns={"/basic.do"},
    initParams={
        @WebInitParam(name="userName",value="peter"),
        @WebInitParam(name="age",value="100")
        })
public class TestServlet extends HttpServlet{
    //内容省略....
}

修饰监听器Listener:

@WebListener
public class MyRequestListener implements ServletRequestListener{
    //内容省略...
}

3_Servlet3.0的Web模块支持

  1. 原来一个web应用的任何配置都需要在web.xml中进行,因此会使得web.xml变得很混乱,而且灵活性差。现在可通过Web模块来部署管理它们。

  2. Web模块对应一个Jar包,即 S e r v l e t Servlet Servlet 3.0可以将每个 S e r v l e t Servlet Servlet、FilterListener 打成jar包,然后放在WEB-INF\lib中。

  3. 每个模块都有自己的配置文件,这个配置文件的名称为 web-fragment.xml

  4. 制作一个 S e r v l e t Servlet Servlet 模块的步骤:

    1. 正常编写 S e r v l e t Servlet Servlet,并编译;
    2. 将此编译class文件及所在包通过jar包命令打成jar包;
    3. 将此jar包用winrar打开,将META-INF中的manifest删除后添加web-fragment.xml
    4. 将此jar包放入WEB-INF\lib中即可;
  5. web-fragment.xml说明:

    1. <web-fragment>为根元素;
    2. <name></name>表示模块名称(模块的唯一标识);
    3. <ordering></ordering>定义模块加载顺序的标签,当然可以不设置模块加载顺序;
    4. <before><others/></before>表示在所有模块前面加载(第一个加载);
    5. <after><name>A</name></after>表示在A模块后面加载;
    6. 可以在里面部署 listenerfilter、 s e r v l e t servlet servlet
    7. 值得注意的是,web.xml中用<absolute-ordering>标签指定的模块加载顺序将会覆盖web模块的web-fragment.xml文件中指定的加载顺序。
  6. 如何用myEclipsejar包(有些人不知道)

    右键你web项目里的编写的 s e r v l e t servlet servlet(或filterlistener)类——>Export…——>JAR file——>NEXT——>(Browser)填写导出名字和存放位置——>finish

    这样就生成了我们需要的jar包了

  7. 示例

    s e r v l e t servlet servlet类代码片:

@WebServlet(name="test",urlPatterns={"/basic.do"})
public class TestServlet extends HttpServlet{

    //使用该方法可响应客户端的所有请求
    public void service(HttpServletRequest req, HttpServletResponse resp)throws IOException{
        System.out.println("进servlet了");
        PrintStream out = new PrintStream(resp.getOutputStream());
        //向页面输入下面字符串
        out.print("1234567890");
    }

}

web-fragment.xml代码片

<web-fragment version="4.0" 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-fragment_4_0.xsd">
    <!-- 这里可以定义过滤器、Servlet等 -->
    <!-- 指定模块名称 :唯一标识-->
    <name>mySerModule</name>
    <!-- 加载顺序 -->
    <ordering>
        <!-- 在其它模块之前加载 -->
        <before>
            <others/>
        </before>
    </ordering>
</web-fragment>

web-fragment.xml里的配置和之前的web.xml里类似,如果是注解实现的 s e r v l e t servlet servlet的配置,则在web-fragment.xml里就将不再写配置了,如果不是,则还需要写配置。

打成jar包放在一个项目里面启动后,就可通过上面 s e r v l e t servlet servlet注解配置的/basic.do路径访问上面的service了。

4_Servlet3.0提供的异步处理

提供异步原因

在以前的 s e r v l e t servlet servlet中,如果作为控制器的 s e r v l e t servlet servlet调用了一个较为耗时的业务方法,则 s e r v l e t servlet servlet必须等到业务执行完后才会生成响应,这使得这次调用成了阻塞式调用,效率比较差。

实现异步原理

​重新开一个线程单独去调用耗时的业务方法。

配置servlet类成为异步的servlet类

  1. 通过注解asyncSupported=true实现
  2. 通过web.xml配置
<servlet>
    <servlet-name>test1</servlet-name>
    <servlet-class>com.example.servlet.AsyncServlet</servlet-class>
    <async-suppored>true</async-suppored>
</servlet>
<servlet-mapping>
    <servlet-name>test1</servlet-name>
    <url-pattern>/basic.do</url-pattern>
</servlet-mapping>

具体实现

java代码:

@WebServlet(name = "AsyncServlet", urlPatterns = {"/testAsyn.do"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //解决乱码
        request.setCharacterEncoding("GBK");
        response.setContentType("text/html;charset=GBK");
        //通过request获得AsyncContent对象
        AsyncContext actx = request.startAsync(); //重点方法**
        //设置异步调用超时时长
        actx.setTimeout(30 * 3000);
        //启动异步调用的线程
        actx.start(new MyThread(actx));//重点方法**

        // 直接输出到页面的内容(不等异步完成就直接给页面)
        //但这些内容必须放在标签内,否则会在页面输出错误内容,这儿反正我测试是这样,具体不知对不对??
        PrintWriter out = response.getWriter();
        out.println("<h1>不等异步返回结果就直接返到页面的内容</h1>");
        out.flush();
    }
}

//异步处理业务的线程类
public class MyThread implements Runnable {
    private AsyncContext actx;

    //构造
    public MyThread(AsyncContext actx) {
        this.actx = actx;
    }

    public void run() {
        try {
            //等待5秒,模拟处理耗时的业务
            Thread.sleep(4 * 1000);
            //获得request对象,添加数据给页面
            ServletRequest req = actx.getRequest();
            req.setAttribute("content", "异步获得的数据");
            //将请求dispath到index.jsp页面,该页面的session必须设为false
            actx.dispatch("/index.jsp");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

页面代码(页头里session设为false,表时该页面不会再创建session):

<%@ page language="java" import="java.util.*" pageEncoding="utf-8" session="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>  
  <body>
    <a href="<%=basePath%>/testAsyn.do">测试异步调用</a>
    异步结果:${content}
  </body>
</html>

异步监听器

异步监听器用来监听异步 S e r v l e t Servlet Servlet的异步处理事件,通过实现AsyncListener接口实现,代码如下:

public class MyAsyncListener implements AsyncListener{

    //异步调用完成时触发
    @Override
    public void onComplete(AsyncEvent event) throws IOException {
        // 省略....       
    }

    //异步调用出错时触发
    @Override
    public void one rror(AsyncEvent event) throws IOException {
        // 省略....       
    }

    //异步调用开始触发
    @Override
    public void onStartAsync(AsyncEvent event) throws IOException {
        // 省略....       
    }

    //异步调用超时触发
    @Override
    public void onTimeout(AsyncEvent event) throws IOException {
        // 省略....       
    }

}

还需要在异步 S e r v l e t Servlet Servlet里注册异步监听器,即添加如下代码即可:

 actx.addListener(new MyAsyncListener());

Filter异步调用与 S e r v l e t Servlet Servlet一样。

改进的ServletAPI(上传文件)

  1. 改进内容

    1. HttpServletRequest增加了对上传文件的支持
    2. ServletContext允许通过编程的方式动态注册 S e r v l e t Servlet Servlet、Filter
  2. HttpServletRequest提供了如下两个方法处理文件的上传

    1. Part getPart(String name) 根据名称获取文件上传域

    2. Collection<Part> getParts() 获取所有文件上传域

  3. 上传文件时一定要为表单域设置enctype属性,它表示表单数据的编码方式,有如下三个值:

    application/x-www-form-urlencoded(默认),它只处理表单里的value属性值,它会将value值处理成URL编码方式。

    如果此时表单域里有上传文件的域(type="file"),则只会获取该文件在上传者电脑里的绝对路径串,该串没什么实际意义。

    1. multipart/form-data 此处编码方式会以二制流的方式来处理表单数据,此时会将文件内容也封装到请求参数里。
    2. texst/plain 当表单的action属性为mailto:URL的形式时比较方便,主要适用于直接通过表单发送邮件的方式
  4. 上传文件的 S e r v l e t Servlet Servlet需要加上@MultipartConfig注解

  5. 通过request获取的Part对象就可以操作文件域了

  6. 示例

@WebServlet(name="uploadServlet",urlPatterns="/upload.do")
@MultipartConfig
public class UploaderServlet extends HttpServlet {

    public void service(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{
        //获得Par对象(每个Part对象对应一个文件域)
        Part part = request.getPart("file");
        long size = part.getSize(); //获取上传文件大小
        String info = part.getHeader("content-disposition");//获得包含原始文件名的字符串
        //获取原始文件名
        String fileName = info.substring(info.indexOf("filename=\"")+10,info.length()-1);
        //将文件上传到某个位置
        part.write(getServletContext().getRealPath("/uploadFiles")+"/"+fileName);
    }
}

ServletContext提供了如下方法动态注册 S e r v l e t Servlet Servlet、Filter

  • addServlet(); 动态注册 S e r v l e t Servlet Servlet
  • addFilter(); 动态注册Filter
  • addListener(); 动态注册Listener
  • setInitParameter(String name ,String value); 为Web应用设置初始化参数。

5_展望

S e r v l e t Servlet Servlet 4.0 中也引入了一些重要的新特性:

  1. HTTP/2 支持

    • S e r v l e t Servlet Servlet 4.0 提供对 H T T P / 2 HTTP/2 HTTP/2 的原生支持,允许开发者利用新协议的特性,如多路复用、头部压缩和服务器推送。
  2. 异步处理的改进

    • 增强了异步处理 A P I API API,允许更灵活的非阻塞请求处理,提供了 AsyncContextServletRequest 的新方法。
  3. Servlet 3.1 中的特性扩展

    • 对 S e r v l e t Servlet Servlet 3.1 中的异步功能和非阻塞 I/O 进行了扩展,提供更高效的处理能力。
  4. HTTP 头支持

    • 增强了对 HTTP 头的处理,提供了更灵活的请求和响应头管理。
  5. ServletRequestServletResponse 的增强

    • 添加了新的方法来支持更复杂的请求和响应处理。

S e r v l e t Servlet Servlet 5.0: 主要是把javax.servlet包名改成了jakarta.servlet

S e r v l e t Servlet Servlet 6.0: 继续增加一些新功能,并废除一部分功能。

END…

标签:web,service,tomcat,Servlet,public,servlet,梳理
From: https://blog.csdn.net/m0_62943934/article/details/143468097

相关文章

  • 具身智能领域,全球Top50华人图谱梳理
    AGI(通用人工智能)起于大语言模型(LLM)、终于具身智能,是人工智能未来发展的方向;“机器人+大模型”为AGI走进物理世界提供了更多的可能性,而人形机器人则被业界普遍认为是AGI最佳载体,人工智能大模型则被称作为机器人“大脑”。人形机器人大致分为四大部分:本体、高动态性能的控制算......
  • JavaScript知识点梳理及案例实践
    1.Date对象创建Date对象//方法1:不指定参数varnowd1=newDate();console.log(nowd1.toLocaleString());//方法2:参数为日期字符串vard2=newDate("2004/3/2011:12");console.log(d2.toLocaleString());vard3=newDate("04/03/2011:12");console.log(d3.toLoca......
  • javaweb基于JSP+Servlet开发简单的家居购物商城系统源码 大作业 课程设计
    ......
  • 什么是 Servlet
    参考:Servlet是用来做什么的?Servlet技术的特点、ChatGPT简介Servlet是使用Java语言编写的运行在服务器端的程序。狭义的Servlet是指Java语言中的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet主要用于处......
  • SERVLET程序设计2554停车场计费系统设计与实现源码
    项目包含:源码、论文、讲解视频、说明文档请查看博主个人简介运行环境:推荐jdk1.8开发工具:Eclipse、MyEclipe以及idea(推荐)操作系统:windows108G内存以上(其他windows)浏览器:GoogleChrome(推荐)、Edge、360浏览器;数据库:MySQL5.7;数据库可视化工具:NavicatPremium推荐)以......
  • Servlet -个人理解笔记
    Servlet的作用        Servlet主要是为了衔接web应用的前端和后端的,作为它们俩中间数据交换的桥梁,现在很多web项目都是前后端分离的,前端写前端的后端写后端的,但是他俩所用的编程语言是有区别的,怎么实现它们之间的数据交换呢?Servlet就是为了解决这个,它是用java编写的,目......
  • Mysql梳理11——聚合函数
    Mysql梳理11——聚合函数Mysql梳理11——聚合函数11.1引言11.2聚合函数介绍11.2.1什么是聚合函数11.2.2聚合函数类型11.2.3聚合函数语法11.3具体聚合函数11.3.1AVG和SUM函数11.3.2MIN和MAX函数11.3.3COUNT函数11.4GROUPBY11.4.1基本使用11.4.2使用多个列......
  • springmvc-servlet.xml和web.xml文件的存放路径是哪里?项目添加到Tomcat上运行后就报错
        用eclipse写了一个简单的web项目,springmvc-servlet.xml文件和web.xml文件都配置好了,运行起来能看见hello的web页面,但是有一堆报错,不知道是什么原因                                     ......
  • servlet学习
    1.Servlet是一种通过实现javax.servlet.Servlet接口的Java类,用于处理HTTP请求并返回HTTP响应。它能够接受来自客户端(如浏览器)的请求,进行处理,并生成响应内容(通常是HTML)。2.Servlet的工作原理客户端(浏览器)发出HTTP请求。Web服务器接收到请求,并将其交给负责该请求......
  • 实验四 JavaBean及Servlet使用
    1.完整代码下载:实验三代码2.完整代码下载:实验四代码2.导入代码到eclipse运行【如何处理导入后的报错】......