Servlet

Servlet

  • Servlet是Java提供的一门动态web资源开发技术,其实就是一个接口(规范),将来我们需要自定义Servlet类实现Servlet接口即可,并由web服务器运行Servlet。

快速入门

  • 创建Web项目,导入Servlet依赖坐标
    •         
              
                  javax.servlet
                  javax.servlet-api
                  3.1.0
                  provided
              
  • 定义一个类,实现Servlet接口,并重写其中的方法,并在service方法中输出一句话
  • 使用注解方式配置@WebServlet,配置该Servlet的访问路径(就是这个Servlet处理哪些请求)
    • Servlet_第1张图片
  • 访问,启动tomcat,输入url地址,访问对应的Servlet类
    • 通过maven插件的方式来启动tomcat服务器,然后在浏览器中输入对应的url地址
      • Servlet_第2张图片

Servlet执行流程

  • Servlet由web服务器创建,其中的方法也由web服务器来调用

Servlet生命周期

  • Servlet运行在web服务器中(Servlet容器)、其生命周期由容器管理,分为四个阶段
    • 加载实例化:默认情况下,在Servlet第一次被访问时,有容器创建Servlet对象
      • loadStartup
        • 负整数:Servlet对象第一次被访问是创建
        • 正整数或0:服务器启动时,创建Servlet对象,数字越小优先级越高
    • 初始化:在Servlet实例化之后,容器调用其中的init()方法初始化Servlet对象,完成加载配置文件、创建连接等功能,该方法只调用一次
    • 处理请求每当请求Servelt时,Servlet容器都会调用Servlet的service()方法对请求进行处理
    • 服务终止:当释放内存或容器关闭的时候,容器都会调用Servlet中的destroy()方法,完成资源的释放,在destroy()方法调用之后,容器会释放这个Servlet实例对象,该实例对象随后会被Java的垃圾回收器所回收。

Servlet体系结构

  • 方法
    • 除了上述三个必须执行的方法之外,还有两个方法
      •     // 获取ServletConfig对象
            public ServletConfig getServletConfig() {
                return null;
            }
        
            // 获取Servlet信息
            public String getServletInfo() {
                return null;
            }
        
  • 体系结构
    • Servlet_第3张图片
    • GenericServlet类实现类Servlet接口,HttpServlet类(对HTTP协议封装的Servlet类)继承GenericServlet类
    • 我们将来开发B/S框架的web项目,都是针对HTTP协议,所以我们自定义Servlet,继承HttpServlet即可,在自定义的Servlet类中编写处理get/post请求的方法即可。
    • Servlet_第4张图片
  • HttpServlet中为什么要根据请求方式的不同,调用不同的方法,以及如何调用
    • 在接口Servlet的Service方法中,会对请求的参数信息进行处理,但是不同请求的参数位置不同,get请求的请求参数就在请求行中,post请求的请求参数在请求体中,所以要使用不同的请求逻辑。而这些逻辑被封装到HttpServlet类中,我们创建的Servlet类直接继承HttpServlet类即HttpServlet类的源码如下()
      • //
        // Source code recreated from a .class file by IntelliJ IDEA
        // (powered by FernFlower decompiler)
        //
        
        package javax.servlet.http;
        
        import java.io.IOException;
        import java.lang.reflect.Method;
        import java.text.MessageFormat;
        import java.util.Enumeration;
        import java.util.ResourceBundle;
        import javax.servlet.GenericServlet;
        import javax.servlet.ServletException;
        import javax.servlet.ServletOutputStream;
        import javax.servlet.ServletRequest;
        import javax.servlet.ServletResponse;
        
        public abstract class HttpServlet extends GenericServlet {
            private static final String METHOD_DELETE = "DELETE";
            private static final String METHOD_HEAD = "HEAD";
            private static final String METHOD_GET = "GET";
            private static final String METHOD_OPTIONS = "OPTIONS";
            private static final String METHOD_POST = "POST";
            private static final String METHOD_PUT = "PUT";
            private static final String METHOD_TRACE = "TRACE";
            private static final String HEADER_IFMODSINCE = "If-Modified-Since";
            private static final String HEADER_LASTMOD = "Last-Modified";
            private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
            private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
        
            public HttpServlet() {
            }
        
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                String protocol = req.getProtocol();
                String msg = lStrings.getString("http.method_get_not_supported");
                if (protocol.endsWith("1.1")) {
                    resp.sendError(405, msg);
                } else {
                    resp.sendError(400, msg);
                }
        
            }
        
            protected long getLastModified(HttpServletRequest req) {
                return -1L;
            }
        
            protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                NoBodyResponse response = new NoBodyResponse(resp);
                this.doGet(req, response);
                response.setContentLength();
            }
        
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                String protocol = req.getProtocol();
                String msg = lStrings.getString("http.method_post_not_supported");
                if (protocol.endsWith("1.1")) {
                    resp.sendError(405, msg);
                } else {
                    resp.sendError(400, msg);
                }
        
            }
        
            protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                String protocol = req.getProtocol();
                String msg = lStrings.getString("http.method_put_not_supported");
                if (protocol.endsWith("1.1")) {
                    resp.sendError(405, msg);
                } else {
                    resp.sendError(400, msg);
                }
        
            }
        
            protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                String protocol = req.getProtocol();
                String msg = lStrings.getString("http.method_delete_not_supported");
                if (protocol.endsWith("1.1")) {
                    resp.sendError(405, msg);
                } else {
                    resp.sendError(400, msg);
                }
        
            }
        
            private Method[] getAllDeclaredMethods(Class c) {
                Class clazz = c;
        
                Method[] allMethods;
                for(allMethods = null; !clazz.equals(HttpServlet.class); clazz = clazz.getSuperclass()) {
                    Method[] thisMethods = clazz.getDeclaredMethods();
                    if (allMethods != null && allMethods.length > 0) {
                        Method[] subClassMethods = allMethods;
                        allMethods = new Method[thisMethods.length + allMethods.length];
                        System.arraycopy(thisMethods, 0, allMethods, 0, thisMethods.length);
                        System.arraycopy(subClassMethods, 0, allMethods, thisMethods.length, subClassMethods.length);
                    } else {
                        allMethods = thisMethods;
                    }
                }
        
                return allMethods != null ? allMethods : new Method[0];
            }
        
            protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                Method[] methods = this.getAllDeclaredMethods(this.getClass());
                boolean ALLOW_GET = false;
                boolean ALLOW_HEAD = false;
                boolean ALLOW_POST = false;
                boolean ALLOW_PUT = false;
                boolean ALLOW_DELETE = false;
                boolean ALLOW_TRACE = true;
                boolean ALLOW_OPTIONS = true;
        
                for(int i = 0; i < methods.length; ++i) {
                    String methodName = methods[i].getName();
                    if (methodName.equals("doGet")) {
                        ALLOW_GET = true;
                        ALLOW_HEAD = true;
                    } else if (methodName.equals("doPost")) {
                        ALLOW_POST = true;
                    } else if (methodName.equals("doPut")) {
                        ALLOW_PUT = true;
                    } else if (methodName.equals("doDelete")) {
                        ALLOW_DELETE = true;
                    }
                }
        
                StringBuilder allow = new StringBuilder();
                if (ALLOW_GET) {
                    allow.append("GET");
                }
        
                if (ALLOW_HEAD) {
                    if (allow.length() > 0) {
                        allow.append(", ");
                    }
        
                    allow.append("HEAD");
                }
        
                if (ALLOW_POST) {
                    if (allow.length() > 0) {
                        allow.append(", ");
                    }
        
                    allow.append("POST");
                }
        
                if (ALLOW_PUT) {
                    if (allow.length() > 0) {
                        allow.append(", ");
                    }
        
                    allow.append("PUT");
                }
        
                if (ALLOW_DELETE) {
                    if (allow.length() > 0) {
                        allow.append(", ");
                    }
        
                    allow.append("DELETE");
                }
        
                if (ALLOW_TRACE) {
                    if (allow.length() > 0) {
                        allow.append(", ");
                    }
        
                    allow.append("TRACE");
                }
        
                if (ALLOW_OPTIONS) {
                    if (allow.length() > 0) {
                        allow.append(", ");
                    }
        
                    allow.append("OPTIONS");
                }
        
                resp.setHeader("Allow", allow.toString());
            }
        
            protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                String CRLF = "\r\n";
                StringBuilder buffer = (new StringBuilder("TRACE ")).append(req.getRequestURI()).append(" ").append(req.getProtocol());
                Enumeration reqHeaderEnum = req.getHeaderNames();
        
                while(reqHeaderEnum.hasMoreElements()) {
                    String headerName = (String)reqHeaderEnum.nextElement();
                    buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName));
                }
        
                buffer.append(CRLF);
                int responseLength = buffer.length();
                resp.setContentType("message/http");
                resp.setContentLength(responseLength);
                ServletOutputStream out = resp.getOutputStream();
                out.print(buffer.toString());
            }
        
            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);
                }
        
            }
        
            private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {
                if (!resp.containsHeader("Last-Modified")) {
                    if (lastModified >= 0L) {
                        resp.setDateHeader("Last-Modified", lastModified);
                    }
        
                }
            }
        
            public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
                if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
                    HttpServletRequest request = (HttpServletRequest)req;
                    HttpServletResponse response = (HttpServletResponse)res;
                    this.service(request, response);
                } else {
                    throw new ServletException("non-HTTP request or response");
                }
            }
        }
        
      • 我们可以看到其中对于Http中的其中不同的请求方式都进行了判断,并且进行了封装,我们自定义的Servlet类继承HttpServlet类就可以,然后重写其中的不同的方法来处理不同类型的请求即可,简单讲就是HttpServlet类帮我们完成了url请求的类型的判断,我们只需要完成对于不同请求类型的处理逻辑即可。

Servlet urlPattern配置

  • urlParttern就是设置Servlet类访问路径,即该请求被哪一个Servlert来进行逻辑处理,在实际的开发过程中,前后端应该是通过需求文档来确定访问路径的(产品经理提供好)
  • 一个Servlet可以配置多个访问路径
  • urlParttern配置规则
    • 精确匹配
    • 目录匹配
    • 拓展名匹配
    • 任意匹配
    • Servlet_第5张图片
    • /和/*的区别(这两个在以后的servlet访问路劲中尽量不要使用)
      • 当我们的项目中的Servlet配置了“/”,会覆盖掉tomcat中的DefaultServlet,当其他的url-pattern都匹配不上的时候,就会调用该默认的servlet,该默认Servlet会处理项目中静态资源的访问,如果覆盖掉就无法范文静态资源(html页面等.)。
      • 当我们项目中的配置了“/*“,意味该Servlet匹配任意访问路径
    • 优先级
      • 精确路径》目录路径》拓展名路径》/*》/
      • 精确度来划分(在一个项目应该指挥只会使用一种方式来进行配置)

xml配置方式编写Servlet

  • 以后学习框架很多都是全注解开发,就是用注解来讲xml配置方式给替代掉,使用起来非常方柏霓,但学习xml配置方式也有助于我理解注解配置方式,要理解xml配置方式,就需要学习Spring的原理了,可以参考我在Spring专栏的相关文章。
  • 编写好Servlet类之后,我们需要在web.xml配置文件中,进行对应的映射
  • Servlet_第6张图片

你可能感兴趣的:(JavaWeb基础,servlet)