javaEE初阶 — Servlet API 详解

news2024/11/16 21:24:05

文章目录

  • HttpServlet
    • 1 Servlet 的生命周期
    • 2 代码示例
    • 3 使用 postman 构造请求
    • 4 使用 ajax 构造请求
  • HttpServletRequest
    • 1 代码示例
  • 前端如何给后端传参
    • 1 通过 GET 里的 query string 传参
    • 2 通过 POST 借助 form 表单传参
    • 3 通过 json 格式传参
  • HttpServletResponse
    • 1 代码示例
      • 1.1 设置字符集
      • 1.2 重定向

HttpServlet


在 HttpServlet 中 有三个核心的方法,是 init、destory、service

init 方法

@WebServlet("/method")
public class servletMethond extends HttpServlet {

    @Override
    public void init() throws ServletException {
        // 重写 inti 方法
        System.out.println("init");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("doGet");
    }
}


init 方法与 doGet 都是 HttpServlet 类里的方法,也是 tomcat 调用的, 同样都是可以重写的。

tomcat 收到了 /method 这样的路径的请求,就会调用到 servletMethond
于是就需要先对 servletMethond 进行实例化,这个实例化只进行一次。
后续再收到 /method 此时就不必在重复实例化了,直接复用之前的 servletMethond 实例即可。

这个方法在 HttpServlet 实例化之后只会被调用一次
也就是说,即使是多次请求也只会出现一个init。
\



开启服务器,可以看到此时只有一个 init,下面来多次刷新页面观察效果。



可以看到 doGet 会随着刷新次数增加,但是 init 只会在最开始的时候出现一次。



destroy 方法

在服务器终止的时候就会调用这个方法。

下面重写这个来演示一下。

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



可以看到启动服务器的时候,并没有调用 destroy 这个方法,所以就没有显示出这个方法里的内容。

点击红色的矩形终止服务器。



可以看到终止服务器之后,就成功的调用了这个方法。


会不会出现 destroy 是不确定的。

如果是通过 smart tomcat 停止按钮,这个操作本质上是通过 tomcat 的 8005 端口主动停止,
是能够调用 destroy 这个方法,触发 destroy 的。
如果是直接杀进程,此时就可能来不及执行,此时 destroy 就没了。


service 方法

在收到路径匹配的 http 请求就会调用这个方法。

service 这个方法里包含了一个 doGet 方法,也就是说 doGet 方法就是在 service 方法中调用的。

接下来重写 service 方法观看底层代码。

 @Override
 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     super.service(req, resp);
 }




可以看到有一个 diGet 方法。

1 Servlet 的生命周期


这是一个比较频繁的面试题,生命周期就是在什么阶段,做什么事了。

比如一个人的生命周期:

1.小时候,要做的就是上学。
2.长大了之后,要参加工作。
3.再大一点,要结婚生娃。
4.年纪再大,娃要上学了。
5.年纪再大,娃娃要结婚了。
6.年纪再大一点,帮娃带娃。
7.ji了。


Servlet 的生命周期就是:

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

2 代码示例


先来重写 doGet、doPost、doPut、doDelete 方法。

@WebServlet("/methods")
public class MyMethod extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("doGet");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost");
        resp.getWriter().write("doPost");
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPut");
        resp.getWriter().write("doPut");
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("doDelete");
    }
}




可以看到此时只显示出了一个 doGet,那其他的请求怎么办呢?
这个时候就可以使用 postmanajax 来构造请求。

3 使用 postman 构造请求


输入路径,选择 GET 请求,点击 send 就构造好了一个 GET 请求,就出现了一个 doGet。



如果要构造其他的请求,可以更改即可。

4 使用 ajax 构造请求


在 webapp 目录下创建一个 .html 的文件。

绝对路径的写法:

<!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>ajax</title>
</head>
<body>
    <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
    <script>
        $.ajax({
            type: 'get',
            url: 'methods',
           success: function(body, status) {
               console.log(body);
           }
        });
    </script>
</body>
</html>


此处所写的 methods 就相当于是在 http://127.0.0.1:8080/Servlet 基础上再拼上一个 methods。
也就是 http://127.0.0.1:8080/Servlet/methods




在地址栏输入路径,打开控制台就可以看到构造好的 GET 请求了。


相对路径的写法:

 url: '/Servlet/methods',


接下来使用 ajax 构造 POST 请求。

<body>
    <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
    <script>
        $.ajax({
            type: 'post',
            url: 'methods',
            success: function(body, status) {
               console.log(body);
           }
        });
    </script>
</body>
</html>




Put、Delete…和上面的是一样的构造方法。

HttpServletRequest


Request 表示的是 HTTP 请求,HttpServlet 这个对象是 tomcat 自动创造的。
tomcat 其实会实现监听端口,接受连接,读取请求,解析请求,构造请求对象等一系列的工作。

核心方法

  • 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

1 代码示例

@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 使用 StringBuilder 把这些 api 结果拼接起来,统一写响应中
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(req.getProtocol());
        stringBuilder.append(req.getMethod());
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append(req.getContextPath());
        stringBuilder.append(req.getQueryString());
        
        // 写回到响应中
        resp.getWriter().write(stringBuilder.toString());
    }
}




getProtocol 得到的是 HTTP/1.1、getMethod 得到的是 GET
getRequestURI 得到的是 /Servlet/showRequest、getContextPath 得到的是 /Servlet
getQueryString 得到的是 null

前端如何给后端传参

1 通过 GET 里的 query string 传参


在前端给后端传两个数字,一个是同学的 studentId,一个是 classId
发送一个 ?studentId=10&classId=20 这样的请求。

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 预期浏览器会发一个形如 /getParameter?studentId=10&classId=20 请求
        // 借出 req 里的 getParameter 方法就能拿到 query string 中的键值对内容了
        // getParameter 得到的是 string 类型的结果
        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html");
        resp.getWriter().write("studentId = " + studentId + "classId = " + classId);
    }
}


在地址栏中输入路径访问。
我这里的路径是 127.0.0.1:8080/Servlet/getParameter?studentId=10&classId=20



通过 getParameter 方法,?studentId=10&classId=20 这个键值对会自动被 tomcat 处理成
形如 Map 这样的结构,后续就可以直接通过 key 获取 value 了。

如果 key 在 query string 中不存在,此时返回的就是 null。

2 通过 POST 借助 form 表单传参


如果前端是 form 表单格式的数据,后端还是使用 getParameter 来获取。

这里的 form 表单格式的数据也是键值对,和 query string 的格式是一样的,只是这部分内容在 body 中。

 <form action="postParameter" method="post">
     <input type="text" name="studentId">
     <input type="text" name="classId">
     <input type="submit" value="提交">
 </form>



在输入框中输入以下的数据。





当前显示 404 是因为 postParameter 还没有实现,但是不影响,打开 fiddler 抓包观察即可。



当前代码中的 action 属性里的 postParameter 得到的就是抓包结果中的 postParameter 这个路径。
method 属性 得到的就是抓包结果中的 POST 。

input 标签里的 name 属性里的 studentId 和 classId 实现的就是最下方的 studentId=10&classId=20。
而在输入框中输入的内容及决定了它们两个的值。


使用 getParameter 既可以获取到 query string 中的键值对,也可以获取到 form 表单构造的 body 中的键值对。

@WebServlet("/getparameter")
public class PostGetParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html");
        resp.getWriter().write("studentId = " + studentId + "classId = " + classId);
    }
}


抓包即可得到与之前相同的结果。



3 通过 json 格式传参


json 是一种非常主流的数据格式,也是键值对结构。

{
  classId: 20,
  studentId: 10
}


可以把 body 按照上面的格式来组织。

前段可以通过 ajax 的方式来构造出这个内容,也可以使用更简单的 postman 的方式。



打开 postman,勾选上述的选项,之后点击发送即可,由于还没有实现 getparameter2 的代码,
所以此时发送后,会报一个 404 错误。




接下来实现 getparameter2 的代码。

@WebServlet("/getparameter2")
public class PostParameter2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过 getInputStream 把 req 对象里的 body 完整读取出来
        // 在流对象中读取多少个字节,取决于 Content-Length
        int length = req.getContentLength(); // 这是 body 实际的长度
        // 创建一个相同长度的字节数组
        byte[] buffer = new byte[length];
        // 借出 inputStream 来读取 body 的内容
        InputStream inputStream = req.getInputStream();
        inputStream.read(buffer);

        // 把这个字节数组转成 String,然后打印出来
        String body = new String(buffer, 0, length, "utf8");
        System.out.println("body =" + body);
        resp.getWriter().write(body);
    }
}


通过 Content-Length 得到 body 的长度,然后再按照这个长度从请求对象中读取数据,
于是就把 body 给读取出来了。





可以看到服务器与客户端都有了结果。

服务器这里打印的结果就是,从 请求 body 里读取的内容。


接下来使用 fiddler 抓包观察结果



理解它的流程



json 与 form 的区别:

json 格式代码的执行流程与上面通过 form表单传参的流程是类似的,只不过是传参的数据格式不同。

form 表单是形如 classId=20&studentId=10

json 格式则是形如:

{
  classId: 20,
  studentId: 10
}



当前通过 json 传递数据,服务器只是把整个 body 读出来了,但是没有按照键值对的的方式来处理,
也就是说,目前还不能根据 key 获取 value。

此时建议使用 第三方库 —— jackson

1、通过 https://releases.jquery.com/ 打开 maven 仓库


2、搜索 jackson,点击第一个


3、选择 2.14.1 版本


4、将 Maven 里的代码复制到 pom.xml 文件里的 dependency 标签里




接下来尝试更改代码的写法。

class Student {
    public int studentId;
    public int classId;
}

@WebServlet("/getparameter2")
public class PostParameter2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 使用 jackson 涉及到的核心对象
        ObjectMapper objectMapper = new ObjectMapper();
        // readValue 可以把一个 jackson 格式的字符串转成 java 对象
        Student student = objectMapper.readValue(req.getInputStream(), Student.class);
        System.out.println(student.studentId + "," + student.classId);
    }
}


Student student = objectMapper.readValue(req.getInputStream(), Student.class);

这条语句中的 readValue 方法,会执行下面的流程。

1、从 body 中读取 json 格式的字符串

{
  classId: 20,
  studentId: 10
}



2、根据第二个参数类对象,创建 Student 实例


3、解析上述的 json 格式的字符串,处理成 map 键值对结构


4、遍历所有的键值对,看键的名字和 Student 实例的哪个属性名字匹配,
就把对应的 value 设置到该属性中



5、返回该 Student 实例


启动服务器再点击发送,会在服务器上得到下面这样的结果。

HttpServletResponse


1 代码示例

1.1 设置字符集


如果想让下面的代码显示出中文,此时就需要设置字符集 为 utf-8

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 预期浏览器会发一个形如 /getParameter?studentId=10&classId=20 请求
        // 借出 req 里的 getParameter 方法就能拿到 query string 中的键值对内容了
        // getParameter 得到的是 string 类型的结果
        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.setContentType("text/html");
        resp.getWriter().write("学生Id = " + studentId + "班级Id = " + classId);
    }
}




在设置之前会出现以上的结果。



接下来开始调用 setCharacterEncoding 设置字符集。

 resp.setCharacterEncoding("utf-8");


将上述的代码中添加上这条语句即可。


刷新页面可以看到正确的显示出来了。

需要注意的是 设置字符集那条语句必须是在 getWriter().write() 的上面。
如果写在了下面是不会生效的。


也可以把字符集和 ContentType 一起设置

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

1.2 重定向


以 3 开头的状态码,浏览器会自动跳转到指定的新地址。

@WebServlet("/redirectServlet")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("https://www.sogou.com");
    }
}


在地址栏中输入地址后,会跳转到指定的新地址。以上就是会跳转到搜狗的页面。


打开 fiddler 抓包并观察结果。




代码实现的第二种方式

 resp.setStatus(302);
 resp.setHeader("Location", "https://www.sogou.com/");


将代码修改为以上两句即可,这种写法是将上面的步骤给拆分成两步了。


下期来介绍服务器版本的表白墙案例!!!




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

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

相关文章

ChatGPT会取代RPA?ta自己可不是这么说的!

先说一个AI热知识&#xff1a;ChatGPT 的推出在科技界引发了一场狂潮。 聊天机器人ChatGPT以及其背后的AI大模型GPT&#xff0c;在2023年引爆全球。GPT 全称为 Generative Pre-trained Transformer&#xff0c;是一种使用人工神经网络的深度学习技术&#xff0c;能够使机器像人…

Transformer and Self-attention

一谈到 NLP&#xff0c;大家都听说过 Transformer&#xff0c; Self-attention 这些词汇&#xff0c;以及 Attension is all you need 这篇论文。 大家可能多多少少看过这类博客&#xff0c;对这些概念有一些了解&#xff0c;什么 QKV呀&#xff0c; encoder&#xff0c; decod…

贪心-刷杂技的牛

题意 农民约翰的 N 头奶牛&#xff08;编号为 1..N&#xff09;计划逃跑并加入马戏团&#xff0c;为此它们决定练习表演杂技。 奶牛们不是非常有创意&#xff0c;只提出了一个杂技表演&#xff1a; 叠罗汉&#xff0c;表演时&#xff0c;奶牛们站在彼此的身上&#xff0c;形成一…

Revit中如何绘制轴线?CAD图纸转轴网操作

一、如何用revit来制作这么一个简单的轴线呢? 01 、新建项目 绘制轴线&#xff0c;首先新建项目建筑样板 02 、轴线快捷键 绘制轴线的快捷键需要牢记&#xff0c;因为经常使用GR 03 、编辑轴线类型 当你画好第一条轴线&#xff0c;需要对轴线类型属性进行调节&#xff0c;一般…

基于vivado(语言Verilog)的FPGA学习(5)——跨时钟处理

基于vivado&#xff08;语言Verilog&#xff09;的FPGA学习&#xff08;5&#xff09;——跨时钟处理 1. 为什么要解决跨时钟处理问题 慢时钟到快时钟一般都不需要处理&#xff0c;关键需要解决从快时钟到慢时钟的问题&#xff0c;因为可能会漏信号或者失真&#xff0c;比如&…

基于HTML5智慧监所三维可视化安防管控系统

前言 物联网技术的发展使云计算技术得到了迅猛的发展及广泛的应用&#xff0c;智能体系的创建已经成为监狱发展的必然趋势。 智慧监狱的创建、智能化管理的推行是监狱管理的创新&#xff0c;也是监狱整体工作水平提升的具体体现。 建设背景 近年来&#xff0c;司法部不断加大…

jumpserver设置密码强度

1、点击系统设置 – 点击安全设置 2、设置密码强弱规则

【SVN】window SVN安装使用教程(服务器4.3.4版本/客户端1.11.0版本)

介绍 这里是小编成长之路的历程&#xff0c;也是小编的学习之路。希望和各位大佬们一起成长&#xff01; 以下为小编最喜欢的两句话&#xff1a; 要有最朴素的生活和最遥远的梦想&#xff0c;即使明天天寒地冻&#xff0c;山高水远&#xff0c;路远马亡。 一个人为什么要努力&a…

为什么建企业网站对企业来说非常重要?

随着互联网的飞速发展&#xff0c;建企业网站已经成为了企业重要的一部分。企业网站是企业与外界沟通的重要渠道&#xff0c;对于企业的品牌形象、市场推广和销售业绩都有着不可替代的作用。本文将从以下几个方面&#xff0c;阐述为什么建企业网站对企业来说非常重要&#xff0…

Spring5学习总结(五)Spring5的新特性Log4j2@Nullable注解支持函数式风格支持JUnit5

Spring5学习总结&#xff08;五&#xff09;Spring5的新特性/Log4j2/Nullable注解/支持函数式风格/支持JUnit5 整个 Spring5 框架的代码基于 Java8&#xff0c;运行时兼容 JDK9&#xff0c;许多不建议使用的类和方法在代码库中删除 一、支持整合Log4j2 Spring 5.0 框架自带了…

【Java笔试强训】day26编程题

目录 编程题快到碗里来跳台阶问题 编程题 快到碗里来 import java.math.BigDecimal; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);while (sc.hasNext()) {BigDecimal n sc.nextBigDecimal();B…

【leetcode速通java版】04——哈希表

前 言 &#x1f349; 作者简介&#xff1a;半旧518&#xff0c;长跑型选手&#xff0c;立志坚持写10年博客&#xff0c;专注于java后端 ☕专栏简介&#xff1a;代码随想录leetcode速通训练营java版本 &#x1f330; 文章简介&#xff1a;哈希表理论&#xff0c;leetcodeT242,T3…

jekyll+GithubPage搭建一个免费的个人网站

文章目录 Jekyll环境搭建windows安装RUBY、gem、Jekyll用Jekyll搭建本地博客 用jekyll模板搭建githubpage Jekyll环境搭建 windows安装RUBY、gem、Jekyll 安装ruby RUBY安装包下载地址&#xff1a;https://rubyinstaller.org/downloads/&#xff0c;一路默认选项next即可。 最…

热闻丨ChatGPT会替代你我吗?让它写了封情书后,我得到答案

ChatGPT毕竟不是人 2023年的科技圈儿被ChatGPT占据&#xff0c;上线仅仅两个月&#xff0c;活跃用户就突破一亿。上知天文下知地理&#xff0c;ChatGPT以它的强大功能让许多人生出疑问&#xff1a;ChatGPT会替代你我吗&#xff1f; 记者挑选了一些尖锐问题进行询问&#xff0…

【碳达峰碳中和】高校用电智慧监管平台的构建

摘 要&#xff1a;介绍了当前高校用电存在的问题&#xff0c;进行了原因分析&#xff0c;由此提出建立高校用电智慧监管平台。对高校用电智慧监管平台的构架进行设计&#xff0c;运用物联网技术&#xff0c;实现各回路实时自主控制&#xff0c;并细化管理权限&#xff0c;实现…

【5天打卡】学习Lodash的第一天——初体验

大家好&#xff0c;最近&#xff0c;我在学习Lodash这个工具库。Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。一款优秀的 JavaScript 工具库&#xff0c;里面包含了大量的工具函数。适用于常见浏览器以及 Node.js 等。 所以我们一起来学习Lodash&#xff0c…

7. 堆的简单学习

7. 堆 7.1 堆的定义 堆是计算机科学中一类特殊的数据结构的统称&#xff0c;堆通常可以被看做是一棵完全二叉树的数组实现。 堆的特性&#xff1a; 它是完全二叉树&#xff0c;除了树的最后一层结点不需要是满的&#xff0c;其它的每一层从左到右都是满的&#xff0c;如果最…

持续集成 在 Linux 上搭建 Jenkins,自动构建接口测试

本篇把从 0 开始搭建 Jenkins 的过程分享给大家&#xff0c;希望对小伙伴们有所帮助。 文章目录 在 Linux 上安装 Jenkins 在 Linux 上安装 Git 在 Linux 上安装 Python 在 Linux 上安装 Allure 配置 Jenkins jenkins 赋能 - 使用邮箱发送测试报告 jenkins 赋能 - 优化测试报告…

比ChatGPT更好用的Claude来了

比ChatGPT更好用的Claude来了&#xff0c;不需要魔法上网&#xff01;&#xff01;&#xff01; claude官网 点击 add to slack slack跟discord有点类似&#xff0c;先要去slack注册账号 登录之后就添加创建一个工作区 添加 不过现在已经停止添加了&#xff0c;会出现App u…

mySQL1(4/17)

目录 1. 2.字符集 3. 4.update搭配order by 和limit 5.drop table 和delete from 表名 6.主键 primary key 7.修改表 8.外键的父与子的约束关系 9.案例 10.把一个表的内容完全复制到另一个空表中去 11.更复杂的查询 12.group by 分组 13.联合查询 14.内连接和外连…