zoukankan      html  css  js  c++  java
  • springWeb——Servlet

    6.1、Servlet简介
    1. servlet是sun公司开发动态web的一门技术

    2. sum在这些API中提供了一个接口叫做:Servlet.开发的两个步骤:

      • 编写一个类,实现Servlet接口
      • 把开发好的Java类部署到web服务器中

      把实现了Servlet接口的Java程序叫做Servlet

    6.2、Hello Servlet
    1. 构建普通的Maven工程,删除src目录

    2. 建立子工程

      • 这个子工程选取Maven模板中的webapp

      • 父工程:

        <modules>
            <module>demo-01</module>
        </modules>
        
      • 子工程:

        <parent>
            <artifactId>JavaWebLearning</artifactId>
            <groupId>org.example</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        
      • 父工程与子工程间依赖的关系类似于java的继承关系

    3. Maven环境优化:

      • 修改web.xml

        注:web.xml中的内容可以参考对应的Tomcat中的样例并与之相匹配

        <!DOCTYPE web-app PUBLIC
         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
         "http://java.sun.com/dtd/web-app_2_3.dtd" >
        
        <web-app>
          <display-name>Archetype Created Web Application</display-name>
        </web-app>
        
      • 将maven的结构搭建完整:添加java和resources目录(注意Mark As)

    4. 编写一个Servlet程序

      • 编写一个普通类并继承Http

        package com.guan.servlet;
        
        import javax.servlet.http.HttpServlet;
        
        public class TestServlet extends HttpServlet {
        }
        

        注:这里遇到找不到HttpServlet的问题需要导入相关的依赖,可以Alt+Enter,选择Add Maven dependency,将javax.servlet.http依赖导入(前提本地的Maven仓库里有,否则需要到Maven的中央仓库下载.补充一下查找应该下载什么的思路:我们已经安装了Tomcat,而Tomcat是java开发的,既然javaweb能在里面跑肯定是由对应的jar,因此我们直接点开Tomcat的文件夹看看即可)

      • 实现Servlet接口ctrl+o选择override两个方法:doGet+doPost

        注:通常两个方法的基本逻辑是一样,所以我们可以选择直接在doPost方法中调用doGet方法

        public class TestServlet extends HttpServlet {
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                //响应的类型:html
                resp.setContentType("text/html");
                //获取响应的输出流
                PrintWriter writer = resp.getWriter();
                writer.println("<html>");
                writer.println("<head>");
                writer.println("<title>Hello World!</title>");
                writer.println("</head>");
                writer.println("<body>");
                writer.println("<h1>12哈哈</h1>");
                writer.println("</body>");
                writer.println("</html>");
            }
        
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                doPost(req, resp);
            }
        }
        
    5. 在web.xml中注册servlet的实现类,编写Servlet的映射

      为什么要用映射:我们写的Java程序要通过浏览器访问,而浏览器要通过web服务器访问,所以我们要在web服务器中注册我们写的Servlet,还需要给它一个浏览器能访问的路径

      <!--  注册-->
        <servlet>
          <servlet-name>hello</servlet-name>
          <servlet-class>com.guan.servlet.TestServlet</servlet-class>
        </servlet>
      
      <!--  映射-->
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello</url-pattern>
        </servlet-mapping>
      
    6. 此时你会发现程序还无法run(相关的标记是灰色的),配置Tomcat:,直接在模板中选择,有的话直接可以选择,没有的话创建一个,详见之前的博文,注意两点:

      • 点击+才是往里面添加东西
      • 需要fix一下deployment
    7. 测试

      在浏览器中查看相应的链接,发现/hello下的内容有乱码无法正常显示:12??,这是因为Java中默认的字符集是ISO8859-1,我们需要将其改为utf-8

      public class TestServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              //响应的类型:html
              resp.setContentType("text/html");
              //将输出的编码格式改为utf-8
              resp.setCharacterEncoding("utf-8");
              //获取响应的输出流
              PrintWriter writer = resp.getWriter();
              writer.println("<html>");
              writer.println("<head>");
              writer.println("<title>Hello World!</title>");
              writer.println("</head>");
              writer.println("<body>");
              writer.println("<h1>12哈哈</h1>");
              writer.println("</body>");
              writer.println("</html>");
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doPost(req, resp);
          }
      }
      
    6.3、分析servlet源码:主要查看post/get方法的运作
    1. 结构:

      • 点开HttpServlet:

        public abstract class HttpServlet extends GenericServlet

        我们可以看到它继承了GenericServlet这个类

      • 继续点开GenericServlet:

        public abstract class GenericServlet implements Servlet, ServletConfig, Serializable

        我们可以看到这是一个抽象类,继承了三个接口,其中servletConfig显然是用于配置的,Seralizable是用于实体序列化的接口,所以我们重点看Servlet这个接口

      • 继续点开Servlet

        public interface Servlet {
            void init(ServletConfig var1) throws ServletException;
        
            ServletConfig getServletConfig();
        
            void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
        
            String getServletInfo();
        
            void destroy();
        }
        

        好家伙,终于到底了!分析一下几个方法:

        • init:显然是用于初始化的
        • ServletConfig:显然是用于配置的
        • servic:没错和post/get应该就是这个,我们后面回溯主要就看这个方法
        • getServletInfo:显然是用于获得Servlet信息的
        • destory:显然是用于销毁的
    2. 回溯:

      • 查看GenericServlet抽象类:

        public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

        service方法没有被实现

      • 查看HttpServlet类:

        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;
                        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);
                }
        
            }
        

        可以看到正是这个方法完成了Post/Get等方法的实际处理

    3. 总结:

      • HttpServlet继承了GenericServlet抽象类,而GenericServlet又是继承了Servlet接口

      • HttpServlet中的Post/Get方法实际是对Servlet接口的Service方法的扩充

    6.3 Servlet原理

    Servlet是由服务器调用,web服务器在收到浏览器请求之后,会:

    1. 浏览器直接访问的对象是web容器(Tomcat),浏览器发起请求,web容器响应
    2. 相关的Servlet的class文件只会生成一次,后面会直接调用(所以初始化较慢
    3. web容器会产生两个对象:请求(Request)和响应(Response)
    4. 这两个对象会调用2中生成的Servlet对象的doPost/doGet方法,当然本质上是service方法
    5. Request会从service(请求)拿到请求并且把请求之后的响应交给Response
    6. 我们重写了doGet/doPost方法,web容器通过调用service方法间接地调用doGet/doPost方法

    6.4、Mapping
    1. 一个Servlet可以指定一个映射路径

      <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello</url-pattern>
      </servlet-mapping>
      
    2. 一个Servlet可以指定多个映射路径

      <!--  映射-->
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello</url-pattern>
        </servlet-mapping>
      
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello1</url-pattern>
        </servlet-mapping>
      
    3. 一个Servlet可以指定通用映射路径

      <!--  映射-->
      <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello/*</url-pattern>
      </servlet-mapping>
      
    4. 默认请求路径

      <!--  映射-->
      <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/*</url-pattern>
      </servlet-mapping>
      
    5. 指定一些后缀

      注:此时*前面不能加映射的路径

      <!--  无法使用-->
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/*.hello</url-pattern>
        </servlet-mapping>
      
      <!--  无法使用-->
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>/hello/*.hello</url-pattern>
        </servlet-mapping>
      
      <!--  可以使用-->
        <servlet-mapping>
          <servlet-name>hello</servlet-name>
          <url-pattern>*.hello</url-pattern>
        </servlet-mapping>
      
    6.5、拦截器

    优先级的区别:一对一的最高,通配的其次

    1. 写好相应的Error类

      public class Test extends HttpServlet {
      
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              resp.setCharacterEncoding("utf-8");
              resp.setContentType("text/html");
              PrintWriter writer = resp.getWriter();
              writer.write("<h1>404</h1>");
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
    2. 在web.xml中注册

      <servlet>
          <servlet-name>error</servlet-name>
          <servlet-class>com.guan.servlet.Test</servlet-class>
      </servlet>
      
    3. 映射

      <servlet-mapping>
          <servlet-name>error</servlet-name>
          <url-pattern>/*</url-pattern>
      </servlet-mapping>
      
    6.6、ServletContext

    架构:

    获得:this.getServletContext():获得Servlet上下文

    web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用:

    1. 数据共享

      注:这里我们最好用一个全新的module进行演示.但是deployment有需要注意设置的地方:每一个module的deployment应该是独立的,否则如果一个deployment中有多个module,很可能会造成打包的时候把其它module也打包了.显然项目一多,打包就会显得很慢

      我们在这个Servlet中保存的数据,可以在另一个Servlet中拿到

      public class setContext extends HttpServlet {
      
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              resp.setCharacterEncoding("utf-8");
              resp.setContentType("text/html");
              ServletContext context = req.getServletContext();
              String username = (String) context.getAttribute("username");
              System.out.println(username);
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      
      public class getContext extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              //响应的类型:html
              resp.setContentType("text/html");
              //将输出的编码格式改为utf-8
              resp.setCharacterEncoding("utf-8");
              //获得上下文
              ServletContext context = req.getServletContext();
              context.setAttribute("username","guan");
          }
      
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doPost(req, resp);
          }
      }
      
        <servlet>
          <servlet-name>set</servlet-name>
          <servlet-class>com.guan.servlet.getContext</servlet-class>
        </servlet>
        
        <servlet>
          <servlet-name>get</servlet-name>
          <servlet-class>com.guan.servlet.setContext</servlet-class>
        </servlet>
      
      <!--  映射-->
        
        <servlet-mapping>
          <servlet-name>set</servlet-name>
          <url-pattern>/set</url-pattern>
        </servlet-mapping>
        
        <servlet-mapping>
          <servlet-name>get</servlet-name>
          <url-pattern>/get</url-pattern>
        </servlet-mapping>
      
  • 相关阅读:
    <img/>标签onerror事件在IE下的bug和解决方法
    IIS启用Gzip压缩造成OpenFlashChart不能正常显示问题及解决方法
    小心枚举陷阱
    "动软.Net代码生成器"的一次扩展经历
    旁听面试杂想
    .NET Remoting学习点滴(二):基本概念
    十字路口
    表变量和临时表
    动态创建WebService
    拼接SQL造成的意想不到的后果
  • 原文地址:https://www.cnblogs.com/Arno-vc/p/13529193.html
Copyright © 2011-2022 走看看