Servlet —— Servlet API

news2024/11/14 15:35:15
JavaEE传送门

JavaEE

Servlet —— Tomcat, 初学 Servlet 程序

Servlet —— Smart Tomcat,以及一些访问出错可能的原因


目录

  • Servlet API
    • HttpServlet
    • HttpServletRequest
      • 获取 GET 请求中的参数
      • 获取 POST 请求的参数
    • HttpServletResponse


Servlet API

虽然 Servlet 提供的类和方法很多, 但是我们最主要使用的就是三个:

  1. HttpServlet
  2. HttpServletRequest
  3. HttpServletResponse

HttpServlet

核心方法

方法名称调用时机
init在 HttpServlet 实例化之后被调用一次
destory在 HttpServlet 实例不再使用的时候调用一次 (不一定真的能调用到)
service收到 HTTP 请求的时候调用
doGet收到 GET 请求的时候调用(由 service 方法调用)
doPost收到 POST 请求的时候调用(由 service 方法调用)
doPut/doDelete/doOptions/…收到其他请求的时候调用(由 service 方法调用)

# init

创建出 HttpServlet 实例会调用一次. init 方法的作用是用来初始化.

# destroy 不一定真的能调用到的原因:

Tomcat 关闭, 则不再调用 HttpServlet, Tomcat 关闭有两种方法

  1. 杀进程, 比如: 点击 idea 红色方框, 或者用任务管理器结束任务. 此时 destroy 无法被调用.
  2. 通过 8005 端口, 给 Tomcat 发送一个关闭操作, 这时 Tomcat 就可以正常关闭, 就能调用到 destroy.

# service

Tomcat 收到请求, 实际上是先调用 service, 在 service 里面再根据方法, 调用相应的 doXXX.

常见面试题: 谈谈 Servlet 的生命周期

Servlet 生命周期描述的是 Servlet 创建到销毁的过程:

  1. 当一个请求从 HTTP 服务器转发给 Servlet 容器时,容器检查对应的 Servlet 是否创建,没有创建就实例化该 Servlet ,并调用 init() 方法,init()方法只调用一次,之后的请求都从第二步开始执行;
  2. 请求进入 service() 方法,根据请求类型转发给对应的方法处理,如doGet, doPost, 等等
  3. 容器停止前,调用 destory() 方法,进行清理操作,该方法只调用一次,随后 JVM 回收资源。

HttpServletRequest

核心方法

方法描述
String getProtocol()返回请求协议的名称和版本。
String getMethod()返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
String getRequestURI()从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。
String getContextPath()返回指示请求上下文的请求 URI 部分。
String getQueryString()返回包含在路径后的请求 URL 中的查询字符串。
Enumeration getParameterNames()返回一个 String 对象的枚举,包含在该请求中包含的参数的名称.
String getParameter(String name)以字符串形式返回请求参数的值,或者如果参数不存在则返回null。
String[] getParameterValues(String name)返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。
Enumeration getHeaderNames()返回一个枚举,包含在该请求中包含的所有的头名。
String getHeader(String name)以字符串形式返回指定的请求头的值。
String getCharacterEncoding()返回请求主体中使用的字符编码的名称。
String getContentType()返回请求主体的 MIME 类型,如果不知道类型则返回 null。
int getContentLength()以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。
InputStream getInputStream()用于读取请求的 body 内容. 返回一个 InputStream 对象.

代码示例

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //声明响应 body 是 html 结构的数据
        resp.setContentType("text/html");

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(req.getProtocol());
        stringBuilder.append("<br>");//换行
        stringBuilder.append(req.getMethod());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getContextPath());
        stringBuilder.append("<br>");
        stringBuilder.append(req.getQueryString());
        stringBuilder.append("<br>");

        //把请求的 header 也拼进来
        Enumeration<String> headerName = req.getHeaderNames();
        while(headerName.hasMoreElements()) {
            String name = headerName.nextElement();
            String value = req.getHeader(name);
            stringBuilder.append(name + ": " + value);
            stringBuilder.append("<br>");
        }

        resp.getWriter().write(stringBuilder.toString());
    }
}

运行结果展示:

<img src="C:\Users\gujiu\AppData\Roaming\Typora\typora-user-images\image-20230118140803905.png" alt="image-20230118140803905" style="zoom:80%;" /


获取 GET 请求中的参数

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

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取 query string 中的键值对
        // 假设浏览器的请求形如 ?studentId=17&studentName=gujiu
        String studentId = req.getParameter("studentId");
        String studentName = req.getParameter("studentName");
        System.out.println(studentId);
        System.out.println(studentName);

        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write(studentId + ", " + studentName);
    }
}

运行结果展示:

getParameter 获取键值对的时候:

  1. 如果键不存在, 得到的就是 null
  2. 如果键存在, 值不存在, 得到的就是 “”

# 注意事项 #

resp.setContentType("text/html;charset=utf8");
resp.getWriter().write(studentId + ", " + studentName);

这两行代码顺序不能颠倒, 务必要先设置所有的 header 最后再设置 body.


获取 POST 请求的参数

请求的 body 是 x-www-from-urlencoded

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

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过 body 获取, 发 post 请求
        // 请求这里设置的 utf8 , 是告诉 servlet (tomcat) 如何解析
        req.setCharacterEncoding("utf8");
        String studentId = req.getParameter("studentId");
        String studentName = req.getParameter("studentName");
        System.out.println(studentId);
        System.out.println(studentName);

        // 响应这里的 utf8 是告诉浏览器如何解析
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write(studentId + ", " + studentName);
    }
}

使用 postman 发送 POST 请求, 结果展示:

抓包展示:

或者可以用 from 表单的形式发送 POST 请求, 可参考HTTP —— HTTP 响应详解, 构造 HTTP 请求

请求的 body 是 json

如何解析 json 格式呢?

Servlet 没有内置 json 解析, 自己写解析, 比较麻烦 (json 支持嵌套). 我们更好的选择, 是使用现成的第三方库 (市面上又很多的 json 第三方库, 比如: fastson, jackjson, gson…).

我们使用 jackson .

# 我们在中央仓库 搜索 jackson, 如图选择 Jackson Databind

# 选择一个版本 拷贝到 pom.xml 里面的 <dependencies> 标签中. 形如:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.4.1</version>
</dependency>

如果标红记得刷新.

# 写代码

import com.fasterxml.jackson.databind.ObjectMapper;

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

class Student {
    // 这个类中的属性务必是 public 或者带有 public 的 getter/ setter (否则 jackson 无法访问这个对象的属性)
    public int studentId;
    public String studentName;
    //这个类务必要有无参版本的构造方法
}

@WebServlet("/json")
public class JsonServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 此处假设请求的 body 格式为
        // { studentId: 17, studentName: gujiu }

        // ObjectMapper 是 jackson 提供的核心的类
        // 其中一个方法叫做 readValue, 把 json 格式的数据转成 java 的对象
        // 还有一个方法叫做 writeValueAsString, 把 java 对象转成 json 格式的字符串
        ObjectMapper objectMapper = new ObjectMapper();

        // readValue 第一个参数可以是字符串, 也可以是输入流
        // 第二个参数, 是一个类对象, 也就是要解析出来的结果的对象的类;
        Student student = objectMapper.readValue(req.getInputStream(), Student.class);
        System.out.println(student.studentId);
        System.out.println(student.studentName);

        resp.setContentType("application/json; charset=utf8");
	// 两种写法均可	//resp.getWriter().write(objectMapper.writeValueAsString(student));
        objectMapper.writeValue(resp.getWriter(), student);
    }
}

# 使用 postman 构造一个 POST 请求

# 运行结果展示


HttpServletResponse

doXXX 这样的方法里的 HttpServletResponse 对象是个空对象

核心方法

方法描述
void setStatus(int sc)为该响应设置状态码。
void setHeader(String name, String value)设置一个带有给定的名称和值的 header. 如果 name 已经存在, 则覆盖旧的值.
void addHeader(String name, String value)添加一个带有给定的名称和值的 header. 如果 name 已经存在, 不覆盖旧的值, 并列添加新的键值对
void setContentType(String type)设置被发送到客户端的响应的内容类型。
void setCharacterEncoding(String charset)设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。
void sendRedirect(String location)使用指定的重定向位置 URL 发送临时重定向响应到客户端。
PrintWriter getWriter()用于往 body 中写入文本格式数据.
OutputStream getOutputStream()用于往 body 中写入二进制格式数据.

代码示例: 设置状态码

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

@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //约定, 浏览器 query string 传个参数
        //形如 type = 1
        //如果 type为 1, 返回200; 为 2, 返回 404; 为 3, 返回 500
        String type = req.getParameter("type");
        if(type.equals("1")) {
            resp.setStatus(200);
        } else if(type.equals("2")) {
            resp.setStatus(404);
            //返回一个 tomcat 自带的 404 效果
            //resp.sendError(404);
        } else if(type.equals("3")) {
            resp.setStatus(500);
        } else {
            resp.setStatus(504);
        }
    }
}

运行结果展示:

代码示例: 设置响应的 header

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * Description:设置响应的 header 实现页面自动刷新
 */
@WebServlet("/autoRefersh")
public class AutoRefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //直接返回响应就好
        resp.setHeader("refresh", "2");
        resp.getWriter().write(System.currentTimeMillis() + "");
    }
}

# 注意 # 我们设置 2s 刷新一次, 但并不是精确的 2000ms, 会比 2000ms 略多一点, 调度要消耗时间/ 网络传输消耗时间/ 服务器响应消耗时间, 再加上对于 ms 级别的计时存在误差.


代码示例: 构造重定向

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

@WebServlet("/redirct")
public class RedirctServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //进行重定向, 收到请求, 跳转到到 我的主页
        resp.setStatus(302);
        resp.setHeader("Location", "https://blog.csdn.net/m0_58592142?spm=1000.2115.3001.5343");
    }
}

🌷(( ◞•̀д•́)◞⚔◟(•̀д•́◟ ))🌷

以上就是今天要讲的内容了,希望对大家有所帮助,如果有问题欢迎评论指出,会积极改正!!
在这里插入图片描述
在这里插入图片描述

这里是Gujiu吖!!感谢你看到这里🌬
祝今天的你也
开心满怀,笑容常在。

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

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

相关文章

【UE4 第一人称射击游戏】53-制作烟雾弹

上一篇&#xff1a;【UE4 第一人称射击游戏】52-手榴弹攻击丧尸本篇效果&#xff1a;按F键掷出烟雾弹&#xff0c;伴随产生音效和烟雾效果本篇步骤&#xff1a;拷贝一份“GrenadeActor”命名为“SmokeGrenadeActor”双击打开“SmokeGrenadeActor”&#xff0c;删除如下节点改变…

尚医通-医院详情功能(二十七)

目录&#xff1a; &#xff08;1&#xff09;前台用户系统-医院详请-情接口开发 &#xff08;2&#xff09;前台用户系统-技术点-nuxt路由 &#xff08;3&#xff09;前台用户系统-医院详情-前端整合 &#xff08;1&#xff09;前台用户系统-医院详-情接口开发 现在做在页面…

13 Java异常(异常过程解析、throw、throws、try-catch关键字)

文章目录13 异常13.1 异常概念13.2 异常的产生过程解析13.3 异常的阐释和处理13.3.1 throw关键字13.3.2 throws关键字13.3.3 try-catch代码块13.3.4 try-catch-finally代码块Java中final、finally和finalize相似点和区别13.3.5 自定义异常13 异常 13.1 异常概念 异常&#xff…

SpringCloud(12):Zuul路由网关

1 为什么需要服务网关 在分布式系统系统中&#xff0c;有商品、订单、用户、广告、支付等等一大批的服务&#xff0c;前端怎么调用呢&#xff1f;和每个服务一个个打交道&#xff1f;这显然是不可能的&#xff0c;这就需要有一个角色充当所有请求的入口&#xff0c;这个角色就是…

【C++】从0到1入门C++编程学习笔记 - 实战篇:通讯录管理系统

文章目录一、需求分析二、创建项目2.1 创建新项目2.1 添加文件三、菜单功能四、退出功能五、添加联系人5.1 设计联系人结构体5.2 设计通讯录结构体5.3 main 函数中创建通讯录5.4 封装添加联系人函数5.5 测试添加联系人功能六、显示联系人6.1 封装显示联系人函数6.2 测试显示联系…

STM32F103和AIR32F103的FreeRTOS中断优先级

关于 Arm Cortex M 系列内核的中断优先级 Cortex M 的中断和优先级 首先要区分开 中断 和 中断优先级 这是两个不同的东西, 不要搞混了 对于 Cortex-M0 和 Cortex-M0 内核, 除了系统内建中断外, 支持最多 32 个中断对于 Cortex-M3 内核, 除了 16 个内核中断外, 支持最多 240…

前端初学者的Ant Design Pro V6总结(上)

前端初学者的Ant Design Pro V6总结&#xff08;上&#xff09; 一、UI组件开发流程 () > {} 通用&#xff08;异步&#xff09;函数useEmotionCss 定义CSSuseModel获取全局状态useCallback 处理React合成事件JSX 拆分组件initiateState 中CurrentUser空值处理initiateSta…

8. 数字类型讲解

python3 数字类型的使用 1. 基础知识 Python 数字数据类型用于存储数值。 数据类型是不允许改变的,这就意味着如果改变数字数据类型的值&#xff0c;将重新分配内存空间。 可以使用del语句删除一些数字对象的引用。 del var1[,var2[,var3[....,varN]]]Python 支持三种不同的…

计算机视觉算法——基于深度学习的高精地图算法(HDMapNet / VectorMapNet / MapTR / VectorNet)

计算机视觉算法——基于深度学习的高精地图算法&#xff08;HDMapNet / VectorMapNet / MapTR / VectorNet&#xff09;计算机视觉算法——基于深度学习的高精地图算法&#xff08;HDMapNet / VectorMapNet / MapTR / VectorNet&#xff09;1. HDMapNet1.1 网络结构及特点1.1.1…

SAP SD 自定义销售订单审批状态

自定义销售订单审批状态 销售订单可以在其抬头或者项目中定义审批状态&#xff0c;一般在抬头定义的话就相当于针对整单的审批&#xff0c;可以实现多级审批&#xff0c;每级审批设置能进行何种操作&#xff0c;这里就需要在IMG中定义审批状态参数文件。 一、定义状态参数文件…

[精] MySQL和Oracle下Mybatis批量操作示例和获取影响行数介绍

手打不易&#xff0c;如果转摘&#xff0c;请注明出处&#xff01; 注明原文&#xff1a;https://zhangxiaofan.blog.csdn.net/article/details/117933877 目录 前言 Mybatis 执行器 表结构定义 Mybatis批量新增 批量新增——Mysql写法 批量新增——Oracle写法 Mybatis批…

【甄选靶场】Vulnhub百个项目渗透——项目五十四:jarbas-1(类git反弹shell,计划任务提权)

Vulnhub百个项目渗透 Vulnhub百个项目渗透——项目五十四&#xff1a;jarbas-1&#xff08;类git反弹shell,计划任务提权&#xff09; &#x1f525;系列专栏&#xff1a;Vulnhub百个项目渗透 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; …

SpringMvc源码分析(四) 请求执行过程之执行MethodHandler

在上文SpringMvc源码分析&#xff08;三&#xff09;中我们分析了DispatcherServlet类中的doDispatcher方法&#xff0c; 并通过分析方法1和方法2了解了请求执行时是怎么获取MethodHandler链的&#xff0c;本文接上文继续分析方法3、方法4和方法5了解MethodHandler是如何执行的…

springboot rabbitmq 非阻塞重试机制实现

重试的应用场景 比如&#xff0c;系统之间同步数据&#xff0c;A系统发送数据给B系统&#xff0c;因为网络原因或者B系统正在重启&#xff0c;可能收不到信息&#xff0c;为了确保B能收到消息就得重试几次&#xff1b;经典的比如&#xff0c;微信支付回调 对后台通知交互时&am…

VScode远程连接Linux

文章目录一、下载安装二、使用三、连接四、基本操作五、VScode内置命令行六、推荐插件一、下载安装 下载的问题就不用多说了把&#xff0c;可能存在的问题就是下载的速度比较慢 前往官网进行下载&#xff1a;前往官网找到适合自己的版本&#xff1a; 但是由于官网是国外的&am…

DT-6_TTL-WiFi透传模块介绍

DT-6_TTL-WiFi透传模块简介TTL-WiFi模块基于ESP-M2WiFi 模块研发&#xff0c;引出串口TTL、EN、STATE等引脚。产品内置我司最新版本的串口透传固件可完成设备TTL 端口到WiFi/云的数据实时透传&#xff0c;具备低功耗控制&#xff0c;状态指示等功能。本模块可直接取代原有的有线…

【手写 Vue2.x 源码】第三十二篇 - diff算法-乱序比对

一&#xff0c;前言 上篇&#xff0c;diff算法-比对优化&#xff08;下&#xff09;&#xff0c;主要涉及以下几个点&#xff1a; 介绍了儿子节点比较的流程介绍并实现了头头、尾尾、头尾、尾头4种特殊情况比对 本篇&#xff0c;继续介绍 diff算法-乱序比对 二&#xff0c;乱…

MATLAB | 全网最全边际图绘制模板(直方图、小提琴图、箱线图、雨云图、散点图... ...)

如标题所言&#xff0c;这应该是全网最全的边际图绘制模板&#xff0c;中心图有8种格式&#xff0c;边际图有11种格式&#xff0c;共计88种组合&#xff0c;另外模板中给了8款配色&#xff0c;我愿称其为888组合&#xff0c;只需要更换一下数据就能绘制出各种类型的边际图: 甚至…

中国机器视觉市场研究报告

目录 机器视觉行业概述机器视觉行业发展现状机器视觉行业典型企业分析机器视觉行业未来发展趋势 机器视觉行业概述 机器视觉定义 机器视觉&#xff08;Machine Vision&#xff0c;MV&#xff09;是人工智能正在快速发展的一个分支。根据美国制造工程师协会&#xff08;SME&…

数字孪生虚拟电厂负荷控制系统可视化

随着国家“双碳”及“构建以新能源为主体的新型电力系统”等目标的提出&#xff0c;清洁化、数字化越来越成为电力系统面临的迫切需求&#xff0c;负控系统的发展对电力营销现代化建设具有重要的意义。负控管理系统是一个着眼于全面加强电力信息管理的&#xff0c;集负荷控制、…