Servlet-01

news2024/11/24 4:31:01

文章目录

  • Servlet
    • 创建Servlet
    • 探究Servlet的生命周期
  • HttpServlet
    • @WebServlet注解详解
  • 重定向与请求转发
  • ServletContext
    • ServletContext中的接口
  • HttpServletRequest
  • HttpServletResponse
  • 状态码解释
  • Cookie

Servlet

Q:它能做什么呢?

A:我们可以通过实现Servlet来进行动态网页响应,使用Servlet,不再是直接由Tomcat服务器发送我们编写好的静态网页内容(HTML文件),而是由我们通过Java代码进行动态拼接的结果,它能够很好地实现动态网页的返回。

当然,Servlet并不是专用于HTTP协议通信,也可以用于其他的通信,但是一般都是用于HTTP。


创建Servlet

我们只需要实现Servlet类即可,并添加注解@WebServlet来进行注册。

@WebServlet("/test")
public class TestServlet implements Servlet {
		...实现接口方法
}

除了直接编写一个类,我们也可以在web.xml中进行注册,现将类上@WebServlet的注解去掉:

<servlet>
    <servlet-name>test</servlet-name>
    <servlet-class>com.example.webtest.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>test</servlet-name>
    <url-pattern>/test</url-pattern>
</servlet-mapping>

这样的方式也能注册Servlet


实际上,Tomcat服务器会为我们提供一些默认的Servlet,也就是说在服务器启动后,即使我们什么都不编写,Tomcat也自带了几个默认的Servlet,他们编写在conf目录下的web.xml中:

<!-- The mapping for the default servlet -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

我们发现,默认的Servlet实际上可以帮助我们去访问一些静态资源,这也是为什么我们启动Tomcat服务器之后,能够直接访问webapp目录下的静态页面。


探究Servlet的生命周期

Q:一个Servlet是如何运行的。

A:首先我们需要了解,Servlet中的方法各自是在什么时候被调用的,我们先编写一个打印语句来看看:

public class TestServlet implements Servlet {

    public TestServlet(){
        System.out.println("我是构造方法!");
    }

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

    @Override
    public ServletConfig getServletConfig() {
        System.out.println("我是getServletConfig");
        return null;
    }

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

    @Override
    public String getServletInfo() {
        System.out.println("我是getServletInfo");
        return null;
    }

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

我们首先启动一次服务器,然后访问我们定义的页面,然后再关闭服务器,得到如下的顺序:

我是构造方法!
我是init
我是service
我是service(出现两次是因为浏览器请求了2次,是因为有一次是请求favicon.ico,浏览器通病)

我是destroy

我们可以多次尝试去访问此页面,但是init和构造方法只会执行一次,而每次访问都会执行的是service方法,因此,一个Servlet的生命周期为:

  • 首先执行构造方法完成 Servlet 初始化
  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

现在我们发现,实际上在Web应用程序运行时,每当浏览器向服务器发起一个请求时,都会创建一个线程执行一次service方法,来让我们处理用户的请求,并将结果响应给用户。


我们发现service方法中,还有两个参数,ServletRequestServletResponse,实际上,用户发起的HTTP请求,就被Tomcat服务器封装为了一个ServletRequest对象,我们得到是其实是Tomcat服务器帮助我们创建的一个实现类,HTTP请求报文中的所有内容,都可以从ServletRequest对象中获取,同理,ServletResponse就是我们需要返回给浏览器的HTTP响应报文实体类封装。

那么我们来看看ServletRequest中有哪些内容,我们可以获取请求的一些信息:

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    //首先将其转换为HttpServletRequest(继承自ServletRequest,一般是此接口实现)
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        
        System.out.println(request.getProtocol());  //获取协议版本
        System.out.println(request.getRemoteAddr());  //获取访问者的IP地址
  		  System.out.println(request.getMethod());   //获取请求方法
        //获取头部信息
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()){
            String name = enumeration.nextElement();
            System.out.println(name + ": " + request.getHeader(name));
        }
}

我们发现,整个HTTP请求报文中的所有内容,都可以通过HttpServletRequest对象来获取,当然,它的作用肯定不仅仅是获取头部信息

那么我们再来看看ServletResponse,这个是服务端的响应内容,我们可以在这里填写我们想要发送给浏览器显示的内容:

//转换为HttpServletResponse(同上)
HttpServletResponse response = (HttpServletResponse) servletResponse;
//设定内容类型以及编码格式(普通HTML文本使用text/html,之后会讲解文件传输)
response.setHeader("Content-type", "text/html;charset=UTF-8");
//获取Writer直接写入内容
response.getWriter().write("我是响应内容!");
//所有内容写入完成之后,再发送给浏览器

现在我们在浏览器中打开此页面,就能够收到服务器发来的响应内容了。其中,响应头部分,是由Tomcat帮助我们生成的一个默认响应头。


在这里插入图片描述


HttpServlet

Servlet有一个直接实现抽象类GenericServlet,那么我们来看看此类做了什么事情。

我们发现,这个类完善了配置文件读取和Servlet信息相关的的操作,但是依然没有去实现service方法,因此此类仅仅是用于完善一个Servlet的基本操作,那么我们接着来看HttpServlet,它是遵循HTTP协议的一种Servlet,继承自GenericServlet,它根据HTTP协议的规则,完善了service方法。

在阅读了HttpServlet源码之后,我们发现,其实我们只需要继承HttpServlet来编写我们的Servlet就可以了,并且它已经帮助我们提前实现了一些操作,这样就会给我们省去很多的时间。

@WebServlet("/test")
public class TestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("<h1>恭喜你解锁了全新玩法</h1>");
    }
}

现在,我们只需要重写对应的请求方式,就可以快速完成Servlet的编写。


@WebServlet注解详解

我们接着来看WebServlet注解,我们前面已经得知,可以直接使用此注解来快速注册一个Servlet,那么我们来想细看看此注解还有什么其他的玩法。

首先name属性就是Servlet名称,而urlPatterns和value实际上是同样功能,就是代表当前Servlet的访问路径,它不仅仅可以是一个固定值,还可以进行通配符匹配:

@WebServlet("/test/*")

上面的路径表示,所有匹配/test/随便什么的路径名称,都可以访问此Servlet,我们可以在浏览器中尝试一下。

也可以进行某个扩展名称的匹配:

@WebServlet("*.js")

这样的话,获取任何以js结尾的文件,都会由我们自己定义的Servlet处理。

那么如果我们的路径为/呢?

@WebServlet("/")

此路径和Tomcat默认为我们提供的Servlet冲突,会直接替换掉默认的,而使用我们的,此路径的意思为,如果没有找到匹配当前访问路径的Servlet,那么久会使用此Servlet进行处理。

我们还可以为一个Servlet配置多个访问路径:

@WebServlet({"/test1", "/test2"})

我们接着来看loadOnStartup属性,此属性决定了是否在Tomcat启动时就加载此Servlet,默认情况下,Servlet只有在被访问时才会加载,它的默认值为-1,表示不在启动时加载,我们可以将其修改为大于等于0的数,来开启启动时加载。并且数字的大小决定了此Servlet的启动优先级。

@WebServlet(value = "/test", loadOnStartup = 1)
public class TestServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        super.init();
        log.info("我被初始化了!");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().write("<h1>balbalaba</h1>");
    }
}

重定向与请求转发

resp.sendRedirect("time");//重定向
req.getRequestDispatcher("/time").forward(req, resp);//请求转发

Q:请求转发有什么好处呢?

A:它可以携带数据!

req.setAttribute("test", "我是请求转发前的数据");
req.getRequestDispatcher("/time").forward(req, resp);
System.out.println(req.getAttribute("test"));

通过setAttribute方法来给当前请求添加一个附加数据,在请求转发后,我们可以直接获取到该数据。

两者的区别为:

  • 请求转发是一次请求,重定向是两次请求
  • 请求转发地址栏不会发生改变, 重定向地址栏会发生改变
  • 请求转发可以共享请求参数 ,重定向之后,就获取不了共享参数了
  • 请求转发只能转发给内部的Servlet

在这里插入图片描述

ServletContext

ServletContext全局唯一,它是属于整个Web应用程序的,我们可以通过getServletContext()来获取到此对象。

此对象也能设置附加值:

ServletContext context = getServletContext();
context.setAttribute("test", "我是重定向之前的数据");
resp.sendRedirect("time");
System.out.println(getServletContext().getAttribute("test"));

因为无论在哪里,无论什么时间,获取到的ServletContext始终是同一个对象,因此我们可以随时随地获取我们添加的属性。

它不仅仅可以用来进行数据传递,还可以做一些其他的事情,比如请求转发:

context.getRequestDispatcher("/time").forward(req, resp);

它还可以获取根目录下的资源文件(注意是webapp根目录下的,不是resource中的资源)

ServletContext中的接口

Enumeration<String> enumeration = getServletContext().getAttributeNames();//包含了ServletContext中的所有域属性名
Object object=getServletContext().getAttribute("name");//返回与之匹配的域属性值
getServletContext().removeAttribute("name");//删除该属性名对应的域属性
getServletContext().setAttribute("la","巴拉巴拉");//设置ServletContext的域属性,前者为属性名,后者为域属性值

上面的为全局的属性,也可以通过请求转发来实现一写信息的转发(下面还有解释)

req.setAttribute("name", "value");//设置域属性
String name=req.getAttribute("name");//获取域属性值

也可以获取web应用下的资源文件

其他方法遇到了再查,再记录


HttpServletRequest

  • HttpServletRequest 对象代表客户端的请求

  • 当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中

HttpServletRequest常用方法:

  1. getRequestURI() 获取请求的资源路径

  2. getRequestURL() 获取请求的统一资源定位符(绝对路径

  3. getRemoteHost() 获取客户端的 主机, getRemoteAddr()

  4. getHeader() 获取请求头

  5. getParameter() 获取请求的参数

  6. getParameterValues() 获取请求的参数(多个值的时候使用), 比如 checkbox, 返回的数组

  7. getMethod() 获取请求的方式 GET 或 POST

  8. setAttribute(key, value) 设置域数据

  9. getAttribute(key) 获取域数据

  10. getRequestDispatcher() 获取请求转发对象, 请求转发的核心对象

因为浏览器地址栏会停止在第一个 servlet ,如果你刷新页面,会再次发出请求(并且会 带数据), 所以在支付页面情况下,不要使用请求转发,否则会造成重复支付


HttpServletResponse

他是通过流来给客户端传递数据的

字节流		getOutputStream()	常用于下载(传递二进制数据)
字符流		getWriter()			常用于回传字符串(非常常用)
// 两个流同时只能使用一个,也就是用了字节流就不能用字符流了,用了字符流就不能用字节流了

对于getWriter

他获取的对象为PrintWriter类型的数据

resp.getWriter().write("hello servlet");
//或者
PrintWriter writer=resp.getWriter();
writer.write("hello ");

在向客户端写入东西时,要设置编码规则!!!

resp.setContentType("text/html;charset=UTF-8");

还有一种方法:setHeader(),应该没上面的好用,就不写了


状态码解释

状态码状态码描述说明
200OK请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。
302Move temporarily重定向,请求的资源临时从不同的 地址响应请求。
304Not Modified从浏览器缓存中读取数据,不从服务器重新获取数据。例如,用户第一次从浏览器访问服务器端图片资源,以后在访问该图片资源的时候就不会再从服务器上加载而直接到浏览器缓存中加载,这样效率更高。
404Not Found请求资源不存在。通常是用户路径编写错误,也可能是服务器资源已删除。
403Forbidden服务器已经理解请求,但是拒绝执行它
405Method Not Allowed请求行中指定的请求方法不能被用于请求相应的资源
500Internal Server Error服务器内部错误。通常程序抛异常

Cookie

什么是Cookie?它可以在浏览器中保存一些信息,并且在下次请求时,请求头中会携带这些信息。

我们可以编写一个测试用例来看看:

Cookie cookie = new Cookie("test", "yyds");
resp.addCookie(cookie);
resp.sendRedirect("time");
for (Cookie cookie : req.getCookies()) {
    System.out.println(cookie.getName() + ": " + cookie.getValue());
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1804189.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用汇编和proteus实现仿真数码管显示电路

proteus介绍&#xff1a; proteus是一个十分便捷的用于电路仿真的软件&#xff0c;可以用于实现电路的设计、仿真、调试等。并且可以在对应的代码编辑区域&#xff0c;使用代码实现电路功能的仿真。 汇编语言介绍&#xff1a; 百度百科介绍如下&#xff1a; 汇编语言是培养…

1-5 C语言操作符

C语言提供了非常丰富的操作符&#xff0c;使得C语言使用起来非常的方便 算数操作符&#xff1a; 加 减 乘 除 取模 【 - * / %】 注&#xff1a;除号的两端都是整数的时候执行的是整数的除法&#xff0c;如果…

Unity 编辑器扩展,获取目录下所有的预制件

先看演示效果 实现方案 1创建几个用于测试的cube 2&#xff0c;创建一个Editor脚本 3&#xff0c;编写脚本内容 附上源码 using UnityEditor; using UnityEngine;public class GetPrefeb : EditorWindow {private string folderPath "Assets/Resources"; // 指定预…

【Python】数据处理:文本文件操作

在Python中&#xff0c;处理文本文件是非常常见的任务。可以使用内置的open函数来打开、读取和写入文本文件。 打开文件 使用open函数打开文件。该函数有两个主要参数&#xff1a; open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, ope…

ssm602社区医疗保健监控系统+vue【以测试】

前言&#xff1a;&#x1f469;‍&#x1f4bb; 计算机行业的同仁们&#xff0c;大家好&#xff01;作为专注于Java领域多年的开发者&#xff0c;我非常理解实践案例的重要性。以下是一些我认为有助于提升你们技能的资源&#xff1a; &#x1f469;‍&#x1f4bb; SpringBoot…

【设计模式】行为型设计模式之 策略模式学习实践

介绍 策略模式&#xff08;Strategy&#xff09;&#xff0c;就是⼀个问题有多种解决⽅案&#xff0c;选择其中的⼀种使⽤&#xff0c;这种情况下我们 使⽤策略模式来实现灵活地选择&#xff0c;也能够⽅便地增加新的解决⽅案。⽐如做数学题&#xff0c;⼀个问题的 解法可能有…

Linux shell编程基础

Shell 是一个用 C 语言编写的程序&#xff0c;它是用户使用 Linux 的桥梁。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言。Shell 是指一种应用程序&#xff0c;这个应用程序提供了一个界面&#xff0c;用户通过这个界面访问 Linux 内核的服务。 Shell 脚本&#x…

GQA,MLA之外的另一种KV Cache压缩方式:动态内存压缩(DMC)

0x0. 前言 在openreview上看到最近NV的一个KV Cache压缩工作&#xff1a;https://openreview.net/pdf?idtDRYrAkOB7 &#xff0c;感觉思路还是有一些意思的&#xff0c;所以这里就分享一下。 简单来说就是paper提出通过一种特殊的方式continue train一下原始的大模型&#x…

打破 AIGC 算力困境,io.net 如何实现“GPU 互联网”?

AIGC 在全球快速发展的当下&#xff0c;诸多项目深陷 GPU 运力不足&#xff0c;速度放缓、任务宕机、项目崩溃等困境&#xff0c;作为瞄准 AI 理念和 DePIN 赛道的 Solana 生态项目新星 io.net 来说&#xff0c;如何集成项目控制与云计算服务成为抢占市场的重要发力方向。第 11…

将web项目打包成electron桌面端教程(一)vue3+vite+js

说明&#xff1a;后续项目需要web端和桌面端&#xff0c;为了提高开发效率&#xff0c;准备直接将web端的代码打包成桌面端&#xff0c;在此提前记录一下demo打包的过程&#xff0c;需要注意的是vue2或者vue3的打包方式各不同&#xff0c;如果你的项目不是vue3vitejs&#xff0…

Nagios的安装和使用

*实验* *nagios安装和使用* Nagios 是一个监视系统运行状态和网络信息的监视系统。Nagios 能监视所指定的本地或远程主机以及服务&#xff0c;同时提供异常通知功能等. Nagios 可运行在 Linux/Unix 平台之上&#xff0c;同时提供一个可选的基于浏览器的 WEB 界面以方便系统管…

go语言后端开发学习(二)——基于七牛云实现的资源上传模块

前言 在之前的文章中我介绍过我们基于gin框架怎么实现本地上传图片和文本这类的文件资源(具体文章可以参考gin框架学习笔记(二) ——相关数据与文件的响应)&#xff0c;但是在我们实际上的项目开发中一般却是不会使用本地上传资源的方式来上传的&#xff0c;因为文件的上传与读…

项目验收总体计划书(实际项目验收原件参考Word)

测试目标&#xff1a;确保项目的需求分析说明书中的所有功能需求都已实现&#xff0c;且能正常运行&#xff1b;确保项目的业务流程符合用户和产品设计要求&#xff1b;确保项目的界面美观、风格一致、易学习、易操作、易理解。 软件全套文档过去进主页。 一、 前言 &#xff0…

图鸟UI-Icon演示:探索多功能前端模板的魅力

在当今数字化的时代&#xff0c;用户界面&#xff08;UI&#xff09;设计在提升用户体验方面扮演着至关重要的角色。随着技术的不断进步&#xff0c;开发者们对于高效、统一且美观的UI组件需求日益增加。图鸟UI&#xff0c;作为一款功能强大且灵活的UI框架&#xff0c;正满足了…

一款免费文件夹同步工具,旨在帮助用户在不同磁盘或文件夹间进行文件和目录的复制、移动和同步工作

一、简介 1、一款免费文件夹同步工具&#xff0c;旨在帮助用户在不同磁盘或文件夹间进行文件和目录的复制、移动和同步工作。这款工具因其简单易用、高度可定制化的特点&#xff0c;受到了广大用户的青睐。SyncToy支持多种同步模式&#xff0c;包括镜像同步、单向同步以及增量同…

第四篇红队笔记-百靶精讲之Prime-wfuzz-wpscan-openssl enc

靶机Prime渗透 主机发现 nmap扫描与分析 目录爆破与模糊测试 dirb 目录扫描 dev secret.txt wfuzz发现 file参数 根据secret.txt-location.txt 和 file参数结合 secrettier360 根据filelocation.txt得到的on some other php page&#xff08;改用之前扫到image.p…

GDAL 保存TIFF时的Options的可选项

使用GDAL保存文件时&#xff0c;高级操作需要对参数Options进行设置&#xff0c;但代码注释中没有这个参数的可选项&#xff0c;在GDAL的官网上有这部分内容&#xff0c;在此记录&#xff0c;以防遗忘&#xff0c;也为方便同道中人查询。 官网关于gdal Driver options参数设置的…

Oxlint 会取代 Eslint 吗?

最近&#xff0c;一个基于 Rust 的代码检查工具 Oxlint 在国外前端社区引起了热议&#xff0c;许多专家对其给予了高度评价。那么&#xff0c;相比于它的大哥 Eslint&#xff0c;Oxlint 有哪些优势&#xff1f;它会在未来取代 Eslint 吗&#xff1f;本文将讨论这个话题。 Oxc 和…

STM32高级控制定时器(STM32F103):TIM1和TIM8介绍

目录 概述 1 认识TIM1和TIM8 2 TIM1和TIM8的特性 3 TIM1和TIM6时基和分频 3.1 时基单元 3.2 预分频 3.3 时基和分频相关寄存器 3.3.1TIMx_CR1 3.3.2 TIMx_PSC 概述 本文主要介绍STM32高级定时器TIM1和TIM8的功能&#xff0c;还介绍了与之相关的寄存器的配置参数。包括…

Vue CLI 4与项目构建实战指南

title: Vue CLI 4与项目构建实战指南 date: 2024/6/9 updated: 2024/6/9 excerpt: 这篇文章介绍了如何使用Vue CLI优化项目构建配置&#xff0c;提高开发效率&#xff0c;涉及配置管理、项目部署策略、插件系统定制以及Webpack和TypeScript的深度集成技巧。 categories: 前端…