目录
一、HttpServlet
1.1 HttpServlet的核心方法
1.2 Servlet的生命周期
1.3 代码示例:通过postman来发送请求
1.4 代码示例:通过ajax来发送请求
二、HttpServletRequest
2.1 代码示例:打印请求信息:
2.2 代码示例:获取Get请求中的参数
2.2 代码示例:通过form表单获取POST请求中的参数
2.3 代码示例:通过json获取POST请求中的参数
三、HttpServletResponse
3.1 代码示例: 设置状态码
3.2 代码示例: 重定向
虽然Servlet提供的类和方法很多,但是最主要的其实也就三个:HttpServlet、HttpServletRequest、HttpServletResponse。
一、HttpServlet
1.1 HttpServlet的核心方法
写servlet代码时,创建的类往往都继承自HttpServlet,并重写其中的方法。
方法名称 | 调用时机 |
init | 在 HttpServlet 实例化之后被Tomcat调用一次 |
destory | 在 HttpServlet 实例不再使用的时候调用一次 |
service | 收到 HTTP 请求的时候调用 |
doGet | 收到 GET 请求的时候调用(由 service 方法调用) |
doPost | 收到 POST 请求的时候调用(由 service 方法调用 |
doPut/doDelete/doOptions/... | 收到其他请求的时候调用(由 service 方法调用) |
我们实际开发的时候主要重写 doXXX 方法, 很少会重写 init / destory / service
需要注意的是:
1) init方法是在HttpServlet首次实例化的时候被Tomcat调用(非自己调用)。
HttpServlet什么时候被实例化呢?
当Tomcat首次收到和该类相关联的请求的时候(这种模式类似于懒汉模式)
举个例子:
2) destory是不一定能够执行到的。
因为如果是通过直接杀死进程的方式,那么destroy就可能来不及执行就没了
如果是通过smart tomcat的停止按钮(本质是通过控制tomcat上的8005这个端口进行主动停止),是可以的。
3)Tomcat每次收到请求后(收到的前提是路径得匹配),实际上是先调用service 。
在service中再根据方法,调用不同的doXXX方法。实际开发的过程中很少重写service,基本是重写doXXX方法。
1.2 Servlet的生命周期
Servlet 生命周期可被定义为:从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- 当一个请求从Http服务器转发给Servlet容器的时候,容器检查对应的Servlet是否创建,没有创建就实例化该Servlet,并调用init()方法,init()方法只调用一次,之后的请求都是从第二步开始。
- Servlet 调用 service() 方法,根据请求类型转发给对应的方法来处理,如doGet,doPost等等。
- Servlet 销毁前调用 destroy() 方法,该方法只调用一次。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
1.3 代码示例:通过postman来发送请求
1.4 代码示例:通过ajax来发送请求
什么是Ajax?
Ajax即”Asynchronous JavaScript and XML“(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。
传统的Web应用允许用户端填写表单(form),当提交表单时就向网页服务器发送一个请求。服务器接收并处理传来的表单,然后送回一个新的网页,但这个做法浪费了许多带宽,因为在前后两个页面中的大部分HTML码往往是相同的。由于每次应用的沟通都需要向服务器发送请求,应用的回应时间依赖于服务器的回应时间。这导致了用户界面的回应比本机应用慢得多。
与此不同,AJAX应用可以仅向服务器发送并取回必须的数据,并在客户端采用JavaScript处理来自服务器的回应。因为在服务器和浏览器之间交换的数据大量减少,服务器回应更快了。同时,很多的处理工作可以在发出请求的客户端机器上完成,因此Web服务器的负荷也减少了。
二、HttpServletRequest
在 Servlet API 中,定义了一个 HttpServletRequest 接口,它继承自 ServletRequest 接口。HttpServletRequest 对象专门用于封装 HTTP 请求消息,简称 request 对象。
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() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果 长度未知则返回 -1。 |
InputStream getInputStream() | 用于读取请求的 body 内容. 返回一个 InputStream 对象. |
2.1 代码示例:打印请求信息:
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 {
// 这里给响应的数据类型设置Content-type
resp.setContentType("text/html");
// 定义一个StringBuilder,把这些操作api结果拼起来,统一写到响应中
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>");
resp.getWriter().write(stringBuilder.toString());
resp.getWriter().write("<br>");
// 获取header的所有键值对
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
resp.getWriter().write(headerName+" :"+req.getHeader(headerName));
resp.getWriter().write("<br>");
}
}
}
响应界面:
2.2 代码示例:获取Get请求中的参数
Get请求中的参数一般是通过query string 传递给服务器的,形如;
http://127.0.0.1:8080/hello_servlet2/getParameter?classId=2&name=22
此时的浏览器是通过query string 给服务器传递两个参数,classId和name,分别为2和22.
这时候服务器端可以通过getParameter的方式来获取数据打印到页面上:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/getParameter")
public class GetParameterServlet extends HelloServlet{
// 假设前端传来的数据是classId和name
// 我们可以通过req里面的getParameter(返回的对象是String)来解决
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String classId = req.getParameter("classId");
String name = req.getParameter("name");
//需要注意的是这里的setContentType需要写在resp.getWriter().write()的上面
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("班级Id = "+classId + " 姓名 = "+name);
}
}
当然 如果query string里没有对应的值的时候,返回的对象是null:
2.2 代码示例:通过form表单获取POST请求中的参数
2.3 代码示例:通过json获取POST请求中的参数
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;
import java.io.InputStream;
class Student {
public int studentId;
public int classId;
}
@WebServlet("/postParameter2")
public class PostParameter2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用jackson所涉及到的核心对象
ObjectMapper objectMapper = new ObjectMapper();
//readValue就是把json格式的字符串转化成java对象
Student student = objectMapper.readValue(req.getInputStream(),Student.class);
System.out.println(student.studentId + " , " + student.classId);
}
}
三、HttpServletResponse
Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到
HttpServletResponse 对象中.
然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过Socket 写回给浏览器
核心方法
方法 | 描述 |
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 中写入二进制格式数据 |
3.1 代码示例: 设置状态码
实现一个程序, 用户在浏览器通过参数指定要返回响应的状态码:
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 {
String status = req.getParameter("status");
if (status != null) {
resp.setStatus(Integer.parseInt(status));
}
resp.getWriter().write("status: " + status);
}
}
3.2 代码示例: 重定向
实现一个程序, 返回一个重定向 HTTP 响应, 自动跳转到另外一个页面:
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("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.sendRedirect("https://www.sogou.com");
resp.setStatus(302);
resp.setHeader("Location","https://www.sogou.com");
}
}
以下为fiddler抓包结果: