文章目录
Servlet Api详解
Servlet有很多的Api,这里只介绍HttpServlet中的内容,尤其是三个核心类及其方法的使用,分别是HttpServlet
、HttpServletRequest
、HttpServletResponse
.
下面是这三个类的继承关系:
HttpServlet类
由上图可知,HttpServlet类是继承自GenericServlet抽象类而来。
在使用HttpServlet类的时候,一般都需要借助两个对象的使用,分别是HttpServletRequest
和HttpServletResponse
.
这两个对象,一个代表请求,一个代表响应。
当HttpServlet有了上面的两个对象后,就会调用service方法,service方法逻辑如下:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if (ifModifiedSince < lastModified) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{
method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
service方法会先解析两个对象的参数,然后调用doGet、doPost、doHead、doPut、doTrace、doOptons和doDelete这7种方法中的某一个,来具体的处理请求。
这里面的doXXX方法一般都是由开发者重新实现的逻辑。
所以我们在写处理请求的类的时候,都需要继承HttpServlet类,继承的目的是为了能重写这个类中的一些方法,将我们的代码“插入”到Tomcat这个“框架”中,然后Tomcat执行的时候方便调用。
类似的操作,我们之前也学习过,如继承
Comparable
接口,目的是为了重写Comparator
方法,按照我们自己的逻辑进行比较。
还有在多线程中,继承Thread
类,目的是为了重写run
方法,然后在其他线程中调用start
,创建线程时,就会调用重写后的run方法,来执行我们自己的一些逻辑。
像这种 继承+重写 将我们的代码插入带某一个框架体系来处理一些事情的操作是比较经典的 一种做法,也有其他很多的做法。像Js中,为了处理一个事件,我们只需要简单的 赋值一个函数过去即可。
核心方法:
方法名 | 调用 |
---|---|
init | 在HttpServlet实例化之后被调用一次 |
destory | 在HttpServlet实例不再使用的时候调用一次 |
service | 收到HTTP请求的时候调用 |
doGet | 收到GET请求的时候调用(在service方法中) |
doPost | 收到Post请求的时候调用(在service方法中) |
doPut | 收到Put请求的时候调用(在service方法中) |
doDelete | 收到Delete请求的时候调用(在service方法中) |
doOptions | 收到Options请求的时候调用(在service方法中) |
HttpServletRequest类
核心方法
方法 | 描述 |
---|---|
String getProtocol() | 返回请求协议的名称和版本 |
String getMethod() | 返回请求的HTTP方法的名称,例如,GET、POST或PUT |
String getRequestURL() | 从协议名称直到HTTP请求的第一行的查询字符串中,返回该请求的URL的一部分 |
String getContextPath() | 返回指示请求上下文路径。 |
String getQueryString() | 返回请求中的查询字符串。 |
Enumeration getParameterNames() | 枚举的返回String对象,请求正文中所有的“键”的名称 |
String getParameter(String name) | 以字符串形式返回请求参数的“值”,或者如果值不存在则返回null。 |
String[] getParameterValues(Stringname) | 返回一个字符串对象的数组,包含请求正文中所有的值,如果值不存在则返回 null。 |
Enumeration getHeaderNames() | 返回一个枚举,包含在该请求中包含的所有的头名。 |
String getHeader(String name) | 以字符串形式返回指定的请求头的值。 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果类型未知则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。 |
InputStream getInputStream() | 用于读取请求的 body 内容. 返回一个 InputStream 对象. |
代码举例:打印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;
import java.util.Enumeration;
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//把生成的body给放到respBody中
StringBuilder respBody=new StringBuilder();
//设置body数据类型
resp.setContentType("text/html;charset=UTF-8");
//获取当前对象的版本号
respBody.append(req.getProtocol());
respBody.append("<br>");
//获取请求方法
respBody.append(req.getMethod());
respBody.append("<br>");
//获取请求路径
respBody.append(req.getRequestURI());
respBody.append("<br>");
//获取指定的路径
respBody.append(req.getContextPath());
respBody.append("<br>");
//获取查询字符串
respBody.append(req.getQueryString());
respBody.append("<br>");
//获取header
respBody.append("<h3>headers:</h3>");
//枚举类型获得
Enumeration<String> headerNames=req.getHeaderNames();
//遍历枚举
while(headerNames.hasMoreElements()){
String headerName=headerNames.nextElement();
respBody.append(headerName+": ");
respBody.append(req.getHeader(headerName));
respBody.append("<br>");
}
resp.getWriter().write(respBody.toString());
}
}
在浏览器中输入具体的URL,就可以直接访问。
小结:
通过上面的 几个案例,主要是演示了HttpServletRequest这个类的基本用法~
结合HTTP协议的格式,来理解HttpServletRequest类中提供 的方法。
在平时使用这个HttpServletRequest类的时候,最常用的就是用来获取请求中的具体参数。
1.通过query String .getParameter方法
2.通过body正文中的数据格式 application/x-www-form-urlencoded 的getParameter 方法
3.通过body正文中的数据格式 application/json 把整个body取出来,然后再使用json库来解析。
HttpServletResponse类
代码举例:设置状态码
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 中带一个参数,就表示状态码
//根据用户的输入,返回不同的状态码响应
String statusString=req.getParameter("status");
if(statusString==null || statusString.equals("")){
resp.getWriter().write("当前的请求参数 status 缺失");
}
resp.setStatus(Integer.parseInt(statusString));
resp.getWriter().write("status :"+statusString);
}
}
代码举例:自动刷新
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("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf8");
resp.setHeader("Refresh","1");
//获取到毫秒级时间戳并返回
long timestamp=System.currentTimeMillis();
resp.getWriter().write("timestamp: "+timestamp);
}
}
代码举例:重定向
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.setStatus(302);
resp.setHeader("Location","https://www.sogou.com");
}
}
也可直接重定向。
resp.sendRedirect("https://www.sogou.com");
Postman工具
在上面几个案例中,构造HTTP请求都是自己写一个页面,使用form 或者ajax来构造请求,这种构造请求的方式是比较麻烦的,可以使用一些专门的第三方工具来构造请求。
对于HTTP
请求来说,构造请求的工具有很多,
这里介绍一个第三方工具Postman
搜索postman,点击下载。
登录后可以输入对应的URL,选择请求方法,和查询字符串等等内容即可构造请求。
Servlet的生命周期
在HttpServlet类中有三个方法:init
、service
、destory
。这三个方法也是Servlet的生命周期方法,代表了Servlet从“出生”到“工作”再到“死亡”的过程。
Servlet容器会根据以下规则来调用这三个方法:
- init()方法,当Servlet第一次被请求的时候,Servlet容器就会开始调用这个方法来初始化生成一个Servlet对象,但这个方法在后续的请求中不再调用,就像人只能“出生”一次一样。我们可以利用
init()
方法来执行一些初始化工作。调用这个方法的时候,Servlet容器会传入一个ServletConfig
对象来帮助Servlet对象进行初始化。 - service()方法,根据字面意思,就是“服务/工作”方法,当Serlet第一次被请求后,就会调用init方法来初始化生成一个Servlet对象,然后会调用它的service方法进行工作,让service方法来处理请求,在后续的请求中,Servlet容器只会调用service方法。在service方法中,根据请求方法的不同,进而又会调用开发者重写的方法(像
doGet
、doPost
等)来执行核心的处理逻辑。 - destory()方法,当需要销毁Servlet时,Servlet容器就会调用这个方法,就像人一样,到期了就得死亡。在这个方法中,一般写一些清除代码。一般用在卸载应用程序或者关闭Servlet容器的时候.
简单验证生命周期
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
public class TestServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("Servlet此时正在初始化..");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//在这个方法中,是处理请求的核心逻辑
System.out.println("Servlet正在处理请求...");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("Servlet正在销毁中..");
}
}