d一、HttpServlet 是专门为 HTTP 协议服务的,比 GenericServlet 更适合在 HTTP 协议下开发
二、HttpServlet 在 javax.servlet.http.HttpServlet 包下
三、到目前为止我们接触到了哪些接口?
- javax.servlet.Servlet 核心接口
- javax.servlet.ServletConfig Servlet配置信息接口
- javax.servlet.ServletContext Servlet上下文环境接口
- javax.servlet.GenericServlet 标准通用的Servlet类【抽象类】
- javax.servlet.ServletRequest Servlet 请求接口
- javax.servlet.ServletResponse Servlet 响应接口
- javax.servlet.ServletException Servlet 异常【类】
四、http 包下有哪些接口和类?javax.servlet.http.*
- javax.servlet.HttpServletServlet
- javax.servlet.HttpServletRequst
- javax.servlet.HttpServletResponse
五、HttpServletRequest 对象中封装什么信息 ?
HttpServletRequest 简称 Request对象
HttpServletRequest 封装了请求协议的全部内容。
Tomcat 服务器(WEB服务器)将 "请求协议" 中的数据全部解析出来,然后将这些数据全部封装到 request 对象当中。
也就是说,我们只要面向 HttpServletRequest ,就可以获取请求协议中的数据。
六、HttpServletResponse 对象是专门用来响应HTTP 协议到浏览器的
HttpServlet源码分析:
public class HelloServlet extends HttpServlet {
//用户发送第一次请求时,Tomcat服务器会通过这个无参方法构造Servlet对象,看不见的
// public HelloServlet(){}
//构建完对象,通过 init 方法 初始化。HttpServlet 中没有init 方法。继续调用父类 GenericServlet 类中的 init 方法
// 下面不带参数的init 方法可供用户重写的 init 方法。
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
//HttpServlet 是一个模板类。
public abstract class HttpServlet extends GenericServlet {
//用户发送第一次请求时,Tomcat 会调用 service 方法,处理用户的请求。HttpServlet类中有俩个service方法。
//首先会执行这个 service 方法。
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
//强转成带有 Http 类型的 Request 和 Response 。
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
//然后调用重载之后的service方法
this.service(request, response);
}
//重载之后service 方法。
//模板类中的核心算法。
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//getMethod 返回的是:七种请求方式中的一种。注意:返回的是大写的
String method = req.getMethod();
long lastModified;
//如果是GET 就执行doGet方法,是POST 就执行 doPost方法
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
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);
}
}
}
}
HttpServlet 类中的service方法并不是抽象的,由此可见我们是可以重写service方法的,但是享受不到 405 的错误提示。下面举例看看什么是 405 错误?
提供一个发送请求的 html 页面:
重写doGet 和 doPost方法:
当前端发送的是 GET 请求,但是后端重写的是 doPost方法,所以他会执行父类HttpServlet 中的doGet方法。所以它会报 405 错误。
当前端发送的是 POST 请求,但是后端重写的是 doGet方法,也会报 405 错误。
以下是 HttpServlet 类中的doGet和doPost方法:通过源码可以看出来,只要一执行HttpServlet 中的doGet 或者 doPost 就会报405 错误
怎么避免 405 呢?
前端发送 GET 请求,后端重写 doGet 方法
前端发送 POST 请求,后端重写 doPost方法
有的人可能会同时重写 doGet 和 doPost 方法,但是完全没有必要。还不如直接重写 service 方法。
当继承HttpServlet类时,重写 doGet 还是重写 doPost 由程序员说了算。