Servlet —— Servlet API

news/2023/6/9 18:12:19
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 {@Overrideprotected 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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取 query string 中的键值对// 假设浏览器的请求形如 ?studentId=17&studentName=gujiuString 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//约定, 浏览器 query string 传个参数//形如 type = 1//如果 type为 1, 返回200; 为 2, 返回 404; 为 3, 返回 500String 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 {@Overrideprotected 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 {@Overrideprotected 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.exyb.cn/news/show-4557381.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

2018年小结

2018年小结 戊戌年很快要过去&#xff0c;看着钟表上的秒针一下一下的移动&#xff0c;每移动一下就是表示我们的寿命已经缩短一部分&#xff0c;是令人怵目惊心的一件事。 又一年过去了&#xff0c;梁实秋说过&#xff1a;‘没有人不爱惜他的生命&#xff0c;但很少人珍视他的…

我在博客园的这一年小记

启程的日子 今天是2018年2月24日&#xff0c;戊戌年春节后的第一个工作日(前两天请了假)&#xff0c;貌似还没有完全把心收住&#xff0c;对假日依然存有诸多的留恋&#xff0c;上午的时间都花在聊天、开会、整理和打扫上了&#xff0c;并没有做实际的开发工作&#xff0c;也没…

史蒂芬霍金于2018年3月14日离世,我用我的方式纪念他

微博和微信满屏的刷出霍金教授&#xff0c;得知伟大物理学家霍金离世,很多人可能和我一样&#xff0c;一定不相信&#xff1b; 在我们心里他不是应该一直都在的么&#xff0c;何来离世的说法&#xff1b; 我用我的方式记住了这一天&#xff08;2018年3月14日 戊戌狗年正月二十七…

社交向左,AI当立;岁在戊戌,腾讯大急!

躺着赚钱的日子过去了&#xff0c;腾讯结构大调整&#xff0c;好饭真的不怕晚&#xff1f; “认为阿凡达时代才能实现云计算”的马化腾变了。 马上要20周岁的腾讯&#xff0c;在时隔6年后迎来新一轮的优化调整&#xff0c;并在此次调整正将云业务从社交网络事业群(SNG)划分出…

学习TinyRenderer

1图形学图形学&#xff0c;简单来讲是将3D数据以各个视觉效果呈现在2D画布&#xff08;屏幕&#xff09;上&#xff1b;2 TinyRendererTinyRenderer从零开始实现了一个渲染器&#xff1b;TinyRenderer代码地址&#xff1a;https://github.com/ssloy/tinyrenderer内容介绍在&…

中计播客 | 戊戌年的第一篇播客,价值6000亿~

Hi~今天是播客陪你的第15天Number6790亿元 银联网络交易再创春节黄金周新高中国银联发布的春节消费数据显示&#xff0c;2018年春节假日期间&#xff08;2月15号至21号&#xff0c;除夕至初六&#xff09;&#xff0c;银联网络交易再创春节黄金周新高&#xff0c;交易总金额达到…

给程序员的 2018 新年计划清单

贰零壹捌戊戌狗年一日之计在于晨&#xff0c;一年之计在于春&#xff0c;对于程序员来讲&#xff0c;挑战自我很重要。有创造力的以及技术性的休整是可行的。给自己的新年列个计划清单&#xff0c;一起在新的一年更好地成长吧&#xff01;每个月都是一个每年可更新的技术性的或…

戊戌再见,己亥你好!

▲点击上方公众号名称&#xff0c;置顶或星标永伦的小屋这是永伦的小屋的第 21 期分享。作者 l 花永伦来源 l 永伦的小屋&#xff08;ID: yonglun_house&#xff09;转载请联系授权&#xff08;微信ID: yonglun_1994&#xff09;我一直觉得&#xff0c;元旦并不是新的一年的开始…