- HttpServlet类是专门为HTTP协议准备的。比GenericServlet更加适合HTTP协议下的开发。
HttpServlet在哪个包下?
jakarta.servlet.http.HttpServlet
到目前为止我们接触了servlet规范中哪些接口?
- jakarta.servlet.Servlet 核心接口(接口)
- jakarta.servlet.ServletConfig Servlet配置信息接口(接口)
- jakarta.servlet.ServletContext Servlet上下文接口(接口)
- jakarta.servlet.ServletRequest Servlet请求接口(接口)
- jakarta.servlet.ServletResponse Servlet响应接口(接口)
- jakarta.servlet.ServletException Servlet异常(类)
- jakarta.servlet.GenericServlet 标准通用的Servlet类(抽象类)
http包下都有哪些类和接口呢?jakarta.servlet.http.*;
- jakarta.servlet.http.HttpServlet (HTTP协议专用的Servlet类,抽象类)
- jakarta.servlet.http.HttpServletRequest (HTTP协议专用的请求对象)
- jakarta.servlet.http.HttpServletResponse (HTTP协议专用的响应对象)
HttpServletRequest对象中封装了什么信息?
- HttpServletRequest,简称request对象。
- HttpServletRequest中封装了请求协议的全部内容。
- Tomcat服务器(WEB服务器)将“请求协议”中的数据全部解析出来,然后将这些数据全部封装到request对象当中了。
- 也就是说,我们只要面向HttpServletRequest,就可以获取请求协议中的数据。
- HttpServletResponse对象是专门用来响应HTTP协议到浏览器的。
Servlet生命周期:
- 用户第一次请求
- Tomcat服务器通过反射机制,调用无参数构造方法。创建Servlet对象。(web.xml文件中配置的Servlet类对应的对象。)
- Tomcat服务器调用Servlet对象的init方法完成初始化。
- Tomcat服务器调用Servlet对象的service方法处理请求。
- 用户第二次请求
- Tomcat服务器调用Servlet对象的service方法处理请求。
- 用户第三次请求
- Tomcat服务器调用Servlet对象的service方法处理请求。
- ....
- Tomcat服务器调用Servlet对象的service方法处理请求。
- 服务器关闭
- Tomcat服务器调用Servlet对象的destroy方法,做销毁之前的准备工作。
- Tomcat服务器销毁Servlet对象。
-
public class HelloServlet extends HttpServlet { // 用户第一次请求,创建HelloServlet对象的时候,会执行这个无参数构造方法。 public HelloServlet() { } //override 重写 doGet方法 //override 重写 doPost方法 } public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { // 用户第一次请求的时候,HelloServlet对象第一次被创建之后,这个init方法会执行。 public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } // 用户第一次请求的时候,带有参数的init(ServletConfig config)执行之后,会执行这个没有参数的init() public void init() throws ServletException { // NOOP by default } } // HttpServlet模板类。 public abstract class HttpServlet extends GenericServlet { // 用户发送第一次请求的时候这个service会执行 // 用户发送第N次请求的时候,这个service方法还是会执行。 // 用户只要发送一次请求,这个service方法就会执行一次。 @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { // 将ServletRequest和ServletResponse向下转型为带有Http的HttpServletRequest和HttpServletResponse request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException(lStrings.getString("http.non_http")); } // 调用重载的service方法。 service(request, response); } // 这个service方法的两个参数都是带有Http的。 // 这个service是一个模板方法。 // 在该方法中定义核心算法骨架,具体的实现步骤延迟到子类中去完成。 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求方式 // 这个请求方式最终可能是:"" // 注意:request.getMethod()方法获取的是请求方式,可能是七种之一: // GET POST PUT DELETE HEAD OPTIONS TRACE String method = req.getMethod(); // 如果请求方式是GET请求,则执行doGet方法。 if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince; try { ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); } catch (IllegalArgumentException iae) { // Invalid date header - proceed as if none was set ifModifiedSince = -1; } if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { // 如果请求方式是POST请求,则执行doPost方法。 doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ // 报405错误 String msg = lStrings.getString("http.method_get_not_supported"); sendMethodNotAllowed(req, resp, msg); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 报405错误 String msg = lStrings.getString("http.method_post_not_supported"); sendMethodNotAllowed(req, resp, msg); } } /* 通过以上源代码分析: 假设前端发送的请求是get请求,后端程序员重写的方法是doPost 假设前端发送的请求是post请求,后端程序员重写的方法是doGet 会发生什么呢? 发生405这样的一个错误。 405表示前端的错误,发送的请求方式不对。和服务器不一致。不是服务器需要的请求方式。 通过以上源代码可以知道:只要HttpServlet类中的doGet方法或doPost方法执行了,必然405. 怎么避免405的错误呢? 后端重写了doGet方法,前端一定要发get请求。 后端重写了doPost方法,前端一定要发post请求。 这样可以避免405错误。 这种前端到底需要发什么样的请求,其实应该后端说了算。后端让发什么方式,前端就得发什么方式。 */
步骤总结:
-
- 第一步:编写一个Servlet类,直接继承HttpServlet
-
第二步:重写doGet方法或者重写doPost方法,到底重写谁,javaweb程序员
-
第三步:将Servlet类配置到web.xml文件当中
-
第四步:准备前端的页面(form表单),form表单中指定请求路径即可