【Servlet API详解】

news2024/12/23 4:05:40

🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!

欢迎志同道合的朋友一起加油喔🤺🤺🤺


目录

1. HttpServlet类

2. HttpServletRequest

2.1 前后端交互

1. 获取query String 

2.获取body (数据格式与query String一致)

3. .获取body (json数据格式) 

3. HttpServletResponse

3.1 设置状态码  

 3.2 ⾃动刷新

 3.3 重定向


Servlet API中包含了很多的内容,但我们主要用到的是以下三个类,HttpServlet,HttpServletRequest,HttpServletResponse

1. HttpServlet类

在写Servlet代码的时候,第一步是创建一个类,继承HttpServlet,并重写其中的方法

方法调用时机
init在HttpServlet实例化之后被调用一次
destroy在HttpServelet实例不再使用时调用一次
service收到HTTP请求时调用 (由service调用)
doGet收到GET请求时调用 (由service调用)
doPost收到POST请求时调用 (由service调用)
doPut / doDelete…收到对应请求时调用 (由service调用)

init方法: 该方法是在tomcat首次收到了该类相关联(访问/hello路径的请求)的请求时,就会调用到HelloServlet,就需要先对HelloServlet进行实例化,后续在收到请求时,不必再实例化了,直接复用之前的HelloServlet实例即可,只执行一次

destroy方法: 当HttpServlet实例不再使用时调用该方法,啥时候该实例就不再使用了?服务器只要不停止,该实例就一直被使用,只有当服务器停止后了,才会调用该方法,只执行一次
这里的destroy能否被执行到,是存在争议的:
如果是通过停止按钮,这个本质操作是通过tomcat的8005端口,主动停止,才能触发destroy
如果是直接杀死进程,此时就来不及执行destroy
所以不建议在destroy内执行有效代码

service: 收到HTTP请求就会调用 (进到父类 HttpServlet 里面查看)

Service中根据请求的类型不同,调用不同的方法,doGet,doPost方法等等,会执行多次,每收到一次HTTP请求就执行一次

Servlet的生命周期:

  1. 开始的时候执行init
  2. 每次收到请求后,执行service
  3. 销毁之前执行destroy

处理GET请求

  1. 直接在浏览器中,通过URL就能构造(GET请求最常用用法)
  2. 通过postman构造GET请求 (最简单)
  3. 通过ajax构造GRT请求
  • 下面演示ajax构造Get请求,首先创建MethodServlet.java类, 创建 doGet 方法
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("/method")
public class HelloServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("这是一个 doGet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("这是一个doPost");
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("这是一个doPut");
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("这是一个doDelete");
    }
}

创建  TestMethod.html, 放到 webapp 目录中,与WEB-INF处于同级关系

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
        $.ajax({
            type: 'get',
            url: 'method',
            success: function (body, status) {
                console.log(body);
            }
        });
    </script>
</body>
</html>

启动smart Tomcat一键打包部署后结果如下:

 注意路径匹配:

我们还需要注意是否加 / 的问题

我们想要处理其他方法也是同理,在html中将type类型修改,HelloServlet2方法中重写对应方法即可,我们每次修改完代码之后都需要重启服务器


2. HttpServletRequest

当 Tomcat 通过 Socket API 读取 HTTP 请求(字符串), 并且按照 HTTP 协议的格式把字符串解析成
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()返回请求body的长度
InputStream getInputStream()用于读取请求的 body 内容. 返回一个 InputStream 对象
  • query string 是键值对结构,我们可以通过getParameter根据key获取到value
  • 接下来就使用这些方法来将请求信息返回到浏览器上
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 {
        resp.setContentType("text/html;charset=utf-8");
        // 此处返回一个 HTML, 在 HTML 里面显示刚才看到的这些 API 的接口
        // 把这些 API 的返回结果往这个 StringBuilder 里面来拼
        StringBuilder html = new StringBuilder();
        html.append(req.getProtocol());     // HTTP版本号
        html.append("<br>");
        html.append(req.getMethod());       // 方法
        html.append("<br>");
        html.append(req.getRequestURI());   // 请求路径
        html.append("<br>");
        html.append(req.getContextPath());  // 上下文路径
        html.append("<br>");
        html.append(req.getQueryString());  // QueryString
        html.append("<br>");
        html.append("<br>");
        html.append("<br>");
        html.append("<br>");
        // 获取到请求的 header 头
        Enumeration<String> headers = req.getHeaderNames();
        // 请求中的 header 是一组键值对结构,循环相当于拿到键值对中所有的 key
        while (headers.hasMoreElements()) {
            String headerName = headers.nextElement();
            html.append(headerName);
            html.append(":");
            html.append((req.getHeader(headerName)));   // 根据 key 来获取 value
            html.append("<br>");
        }
 
        resp.getWriter().write(html.toString());
    }
}

浏览器响应结果如下:

2.1 前后端交互

  1. GET请求传参通过query string
  2. POST请求传参通过form表单
  3. POST请求传参通过json

我们下来演示一下上述三种方法,前端给后端传参,我们后端获取请求中传来的参数

1. 获取query String 

  • 前端直接通过地址栏构造一个URL发送给后端
  • 请求参数(useId = 10 & classId = 001)放在url的query string中
  • 后端重新doGET()使用getParameter()方法获取key (used / classld)对应的value (10 / 001)
  • 然后将数据返回给浏览器
@WebServlet("/getParameter")
public class GetParameterServelet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用getParameter获取前端query string的数据 useId = 10 & classId = 001
        String userId = req.getParameter("useId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write(userId +", " + classId);
    }
}

 浏览器响应结果如下:

这里请求中的query string键值对会被tomcat处理成形似map结构的数据,我们就可以通过key去获取value了,需要注意的是我们这里的value都是String类型的,如果我们getParameter的参数前端并没有传递,那么我们的value就是null

2.获取body (数据格式与query String一致)

  • 通过form表单构造post请求
  • 请求的参数(useId = 10 & classId = 001)放在body 中
  • 后端重写doPost()使用getParameter()方法获取key (used / classld)对应的value (10 / 001)
  • 然后将数据返回给浏览器

 通过表单构造 get/post请求 详解可参考我上一篇博客(【HTTP协议】)

  text.html里面使用form表单构造请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>使用form表单构建一个请求</title>
</head>
<body>
    <form action="postParameter" method="post">
        <input type="text" name="useId">
        <input type="text" name="classId">
        <input type="submit" value="提交">
    </form>
</body>
</html>

 后端接收请求并返回结果

@WebServlet("/postParameter")
public class PostParameterServelet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用getParameter获取前端body的数据 useId = 10 & classId = 001
        String userId = req.getParameter("useId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write(userId +", " + classId);
    }
}

 浏览器响应结果如下:

3. .获取body (json数据格式) 

  1. postman构造出一个指定的post请求,body就是josn数据
  2. 请求到达tomcat,tomcat解析成req对象
  3. 在servlet代码中,req.getInputStream()读取body的内容
  4. 又把body内容构造成一个响应结果返回给浏览器(postman)
@WebServlet("/JsonParameter")
public class JsonParameterServelet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过这个方法处理body为json格式的数据
        //直接把req对象里的body完整的读出来
        // 1.先拿到body的长度,单位是字节
        int length = req.getContentLength();
        // 2.准备一个字节数组,来存放body的内容
        byte[] buffer = new byte[length];
        // 3.获取到InputStream对象
        InputStream inputStream = req.getInputStream();
        // 4. 读取数据,从InputStream对象中,读到数据,放到buffer这个数组中
        inputStream.read(buffer);
        //把这个数组构造成String,打印出来
        String body =  new String(buffer,0,length,"utf8");
        System.out.println("body = "+body);
        resp.getWriter().write(body);
    }
}

 通过postman构造请求(body为josn格式),服务器返回body给postman

 

当前通过 json 传递数据, 服务器这边只是把整个 body 读出来, 没有按照键值对的方式来处理.(还不能根据 key 获取 value),如果响应通过key获取value此时需要借助第三方库来处理。

引入依赖Jackson这个库在在中央仓库中获取(Jackson地址)。

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.1</version>
        </dependency>

  将这段代码复制到pom.xml里面就可了。

  JsonParameterServlet.java 文件 

class Student {
    public String userId;
    public String classId;

    @Override
    public String toString() {
        return "Student{" +
                "userId='" + userId + '\'' +
                ", classId='" + classId + '\'' +
                '}';
    }
}

@WebServlet("/JsonParameter")
public class JsonParameterServelet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过这个方法处理body为json格式的数据
        //直接把req对象里的body完整的读出来
        // 1.先拿到body的长度,单位是字节
//        int length = req.getContentLength();
//        // 2.准备一个字节数组,来存放body的内容
//        byte[] buffer = new byte[length];
//        // 3.获取到InputStream对象
//        InputStream inputStream = req.getInputStream();
//        // 4. 读取数据,从InputStream对象中,读到数据,放到buffer这个数组中
//        inputStream.read(buffer);
//        //把这个数组构造成String,打印出来
//        String body =  new String(buffer,0,length,"utf8");
//        System.out.println("body = "+body);

        //使用json涉及到的核心对象
        ObjectMapper objectMapper = new ObjectMapper();
        //readValue 就是把一个 json 格式的字符串 转成java对象
        Student student =  objectMapper.readValue(req.getInputStream(),Student.class);
        resp.getWriter().write(student.toString());
        System.out.println(student.userId+", "+student.classId);;
    }
}

注意:Jackson库的核心类为ObjectMapper。 


3. HttpServletResponse

核心方法:

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

3.1 设置状态码  

@WebServlet("/state")
public class StateServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf8");
        int status=404;
        resp.setStatus(status);
        //resp.getWriter().write("响应状态码是"+status);
        //返回tomcat自带的错误页面
        //resp.sendError(404);
    }
}

 3.2 ⾃动刷新

@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //告诉浏览器1秒刷新一次
        resp.setHeader("Refresh", "1");
        resp.getWriter().println("" + LocalDateTime.now());
    }
}

 下面浏览器每秒钟会自动刷新一次:

 3.3 重定向

实现一个程序, 返回一个重定向 HTTP 响应, 自动跳转到另外一个页面.

@WebServlet("/redirect")
public class RediractServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //实现重定向,让浏览器自动跳转到百度浏览器
        resp.setStatus(302);
        resp.setHeader("Location","https://www.baidu.com");
        //另一种更简单的重定向写法
        //resp.sendRedirect("https://www.baidu.com");
    }
}

输入敲下回车之后,跳转到百度主页

 fiddler抓包结果如下:

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

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

相关文章

【JUC基础】10. Atomic原子类

1、什么是Atomic Atomic英译为原子的。原子结构通常称为不可分割的最小单位。而在JUC中&#xff0c;java.util.concurrent.atomic 包是 Java 并发库中的一个包&#xff0c;提供了原子操作的支持。它包含了一些原子类&#xff0c;用于在多线程环境下进行线程安全的原子操作。使…

Apache Doris

Apache Doris教程 1.Doris 简介 1.1 Doris 概述 Apache Doris 由百度大数据部研发&#xff08;之前叫百度 Palo&#xff0c;2018 年贡献到 Apache 社区后&#xff0c; 更名为 Doris &#xff09;&#xff0c;在百度内部&#xff0c;有超过 200 个产品线在使用&#xff0c;…

一次简单的问题排查背后蕴含的巨大的知识量

现象 所有的请求都卡住。堆dump正常。有一段时间内存占用高&#xff0c;GC频繁且耗时长&#xff0c;过了那段时间后监控上恢复正常。日志有OutOfMemory的异常 结论 在这段代码OOM之前&#xff0c;它会导致JVM不停 fullGC 与 stopWorld&#xff0c;从而导致了程序卡死。&#…

【Linux】线程同步/生产消费模型/线程池/读写锁

目录 1.Linux线程同步 1.1.条件变量 1.1.1.同步概念与竞态条件 1.1.2.条件变量函数 初始化和销毁 1.1.3.等待条件满足 1.1.5.为什么 pthread_cond_wait 需要互斥量? 1.1.6.条件变量使用规范 2.生产者消费者模型 2.1.模型概念 2.2.模型优点 2.3.基于Blocking Queue的…

[入门必看]数据结构6.1:图的基本概念

[入门必看]数据结构6.1&#xff1a;图的基本概念 第六章 图6.1 图的基本概念知识总览6.1.1 图的基本概念 6.1.1 图的基本概念图的定义图逻辑结构的应用无向图、有向图简单图、多重图顶点的度、入度、出度顶点-顶点的关系描述连通图、强连通图研究图的局部——子图连通分量强连通…

西门子物联网网关 IOT2050 杭州乐芯生态合作版 LX-IOT2050

西门子物联网网关 IOT2050 乐芯生态合作版 LX-IOT2050 •基于 IOT2050 硬件基础上安装了乐芯科技数据采集引擎&#xff0c; 提供开箱即用的物联网解决方案。 •硬件&#xff1a;基于西门子工业的高品质硬件&#xff0c;完善的国际认证资质 &#xff0c; 欧盟CE、UL、CCC认证。…

零基础小白怎么入门网络安全(黑客)?看这篇就够啦

前言 我刚入门网络安全&#xff0c;该怎么学&#xff1f;要学哪些东西&#xff1f;有哪些方向&#xff1f;怎么选&#xff1f; 不同于Java、C/C等后端开发岗位有非常明晰的学习路线&#xff0c;网路安全更多是靠自己摸索&#xff0c;要学的东西又杂又多&#xff0c;难成体系。…

会话跟踪cookie和session

什么是会话跟踪技术 会话&#xff1a;用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff0c;直到有一方断开连接&#xff0c;会话结束。在一次会话中可能包含多次请求和响应。 会话跟踪&#xff1a;一种维护浏览器状态的方法&#xff0c;服务器需…

【无标题】 Vue 路由库Router 【重点】 - 安装 - 基本使用 - 路由配置 - 路由模式 - 路由传递参数 - 路由内置对象 - 路由守卫

0.0 课程介绍 Vue 路由库Router 【重点】 安装基本使用路由配置路由模式路由传递参数路由内置对象路由守卫 Vue的内置API 【掌握】 ref Vue.set Vue.nextTick Vue.filter Vue.component Vue.use Vue.directive 1.0 Vue的路由Router 【重点】 1.1 路由作用 进行页面…

Doris---数据表设计

表的基本概念 1 Row & Column 一张表包括行&#xff08;Row&#xff09;和列&#xff08;Column&#xff09;&#xff1b; Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。 doris中的列分为两类&#xff1a;key列和value列 key列在doris中有两种作用&…

【Android】【Java】播放多段视频切换时出现的短暂黑屏现象处理

逻辑描述 当A视频正在播放中&#xff0c;点击A视频跳过A视频剩余内容并加载B视频 Bug描述 在切换视频时&#xff0c;显示短暂黑屏&#xff0c;如下图所示&#xff1a; 解决思路 当看到这个bug出现时&#xff0c;第一反应是第二段视频在初始化视频时有一定的延时&#xff…

关于C语言杂记7

文章目录 关于数组二级指针字符串字符串的输入与输出字符串函数1、字符数组的输入和输出&#xff1a;2、5种相关函数&#xff1a; 关于数组 char *fruits[LEN] { // 定义一个字符指针数组&#xff0c;包含LEN个元素"apple", // 初始化第1个元素为字符串"a…

【C++】unordered_map和unordered_set的使用

文章目录 前言一、unordered_map的使用及性能测试二、unordered_set的使用 1.习题练习总结 前言 unordered 系列关联式容器 &#xff1a; 在 C98 中&#xff0c; STL 提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到O&#xff08;logN&#xff09; &a…

SDN — Google B4 SDN WAN 网络架构

目录 文章目录 目录Google B4 SDN WAN 网络B4 网络架构物理设备层局部网络控制层全局控制层Hybrid SDN 模式Google B4 SDN WAN 网络 Google 的 WAN 有 2 张网络(Two Backbones): B2(I-Scale Network):数据中心互联 Internet(POP)的网络,用于面向 Internet 用户访问,…

大象转身只需点点鼠标,爆火 DragGAN 原理浅析

出品人&#xff1a;Towhee 技术团队 作者&#xff1a;张晨 DragGAN介绍 合成满足用户需求的视觉内容往往需要对生成对象的姿势、形状、表情和布局进行灵活和精确的控制。 现有方法通过手动注释的训练数据或先前的 3D 模型获得生成对抗网络 (GAN) 的可控性&#xff0c;这通常缺乏…

保姆级教程:手把手教你拿下雅思写作7分

在留学路上&#xff0c;雅思考试是绕不开的一道坎。然而&#xff0c;众所周知&#xff0c;雅思学习热度高&#xff0c;学习难度大&#xff0c;而且很多人找不到合适的学习方法。在这里&#xff0c;我们以雅思写作中的大作文为例&#xff0c;从大作文的结构拆解、学习的任务拆分…

SSM编程---Day 02

目录 一、核心配置文件 二、junit介绍 三、自定义java注解 四、自定义注解 五、添加log4j的支持 六、sql映射文件的介绍 一、核心配置文件 1、核心配置文件中需要注意顺序 2、根节点 <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN"…

数据结构-最小生成树Prim算法的实现

目录 一、前言 二、最小生成树 三、Prim算法 四、Prim算法的实现 一、前言 在计算机科学中&#xff0c;数据结构是一种组织和存储数据的方式&#xff0c;以便于访问和修改。数据结构是计算机科学的基础&#xff0c;它是算法的基础。在数据结构中&#xff0c;最小生成树是一…

Python调用腾讯云函数传递json数据

前言 有些时候有一些公共的方法&#xff0c;需要放在服务器上&#xff0c;在不同的电脑上使用。但是我们有没有自己的服务器&#xff0c;所以考虑将公共的方法放在腾讯云、华为云、阿里云、百度云等云平台上&#xff0c;方便在不同的电脑上复用。 我们这里使用的是腾讯云&#…

AMD Software Adrenalin Edition 23.5.1驱动发布,快速获取驱动

AMD新驱动赶在五月天发布&#xff01;AMD Software Adrenalin Edition 23.5.1驱动 &#xff0c;为部分游戏带来支持&#xff0c;以及为重要的软件带来修复。驱动人生带大家一览AMD WHQL 23.5.1驱动的优化内容。 游戏方面&#xff0c;AMD WHQL 23.5.1主要为游戏《指环王&#x…