• Servlet


    1、Servlet概述

      Servlet是Java Web的三大组件(Servlet,Filter,Listener)之一,属于动态资源 ,运行在 Web 服务器或应用服务器上的程序作用为处理请求,服务器会把接收的请求交给Servlet来处理,在Servlet中通常需要:

    • 接收请求数据;
    • 处理请求;
    • 完成响应。

      例如:客户端发出登录请求,或输出注册请求,这些请求都应该有Servlet来完成处理。每个Servlet都必须实现javax.servle.Servlet接口。

    2、实现Servlet的方式

      三种实现方式:

      • 实现javax.servlet.Servlet接口
      • 继承javax.servlet.GenericServlet类
      • 继承javax.servlet.http.HttpServlet类

      通常会去继承HttpServlet类来完成Servlet。

    3、Servlet生命周期方法:

    • void init(ServletConfig servletConfig):Servlet对象创建之后马上执行的初始化方法,只执行一次;
    • void service(ServletRequest servletRequest, ServletResponse servletResponse):每次处理请求都是在调用这个方法,它会被调用多次;
    • void destroy():在Servlet被销毁之前调用,负责释放Servlet对象占用的资源的方法;

      特性:

    • 单例,一个类只有一个对象,当然可能存在多个Servlet类
    • 线程不安全的,所以它的效率高。

      Servlet类由自己编写,但对象由服务器来创建,并由服务器来调用相应的方法。

    /**
     * Servlet接口方法介绍
     * 类由我们自己创建(可变部分),Servlet中的方法大多数由Tomcat来调用,并且Servlet对象也由Tomcat来创建。
     */
    public class AServlet implements Servlet {
        /*
        * 它是生命周期方法
        * 它会在Servlet对象创建之后马上执行,并只执行一次。
        * 负责Servlet初始化工作。
        */
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
            System.out.println("init()...");
        }
        /*
        * 用来获取Servlet的配置信息
        */
        @Override
        public ServletConfig getServletConfig() {
            System.out.println("getServletConfig()...");
            return null;
        }
        /*
        * 它是生命周期方法
        * 它会被调用多次
        * 每次处理请求都是在调用这个方法
        */
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) 
          throws ServletException, IOException { System.out.println("service()..."); } /* * 获取Servlet的信息 */ @Override public String getServletInfo() { System.out.println("getServletInfo()..."); return null; } /* * 它是生命周期方法 * 它会在Servlet被销毁之前调用,负责释放Servlet对象占用的资源,并且它只会被调用一次。 */ @Override public void destroy() { System.out.println("destroy()..."); } }
    Servlet细节:
    1、Servlet与线程安全
    一个类型的Servlet只有一个实例对象,那么就有可能会出现一个Servlet同时处理多个请求,线程不安全,但Servlet工作效率高。
    解决方法:
    • 不要在Servlet中创建成员,创建局部变量变量即可!
    • 可以创建无状态成员!
    • 可以创建有状态的成员,但状态必须位为只读的!
     1 public class Servlet extends HttpServlet {
     2     //无状态成员
     3     /*public class User {
     4         public void hello() {
     5             System.out.println("Hello");
     6         }
     7     }*/
     8     //创建有状态的成员,但状态必须位为只读的
     9     /*public class User {
    10         private String name = "zhangsan";
    11         public String getName() {
    12             return name;
    13         }
    14     }*/
    15     private User user = new User();
    16 
    17     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    18         System.out.println("doPost()...");
    19     }
    20     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    21         System.out.println("doGet()...");
    22     }
    23 }

    2、让服务器在启动时就创建Servlet对象

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     5          version="3.1">
     6     <servlet>
     7         <servlet-name>Servlet</servlet-name>
     8         <servlet-class>web.servlet.Servlet</servlet-class>
     9         <load-on-startup>0</load-on-startup>
    10     </servlet>
    11     <servlet-mapping>
    12         <servlet-name>Servlet</servlet-name>
    13         <url-pattern>/Servlet</url-pattern>
    14     </servlet-mapping>
    15     <servlet>
    16         <servlet-name>Servlet2</servlet-name>
    17         <servlet-class>web.servlet.Servlet2</servlet-class>
    18         <load-on-startup>1</load-on-startup>
    19     </servlet>
    20     <servlet-mapping>
    21         <servlet-name>Servlet2</servlet-name>
    22         <url-pattern>/Servlet2</url-pattern>
    23     </servlet-mapping>
    24 </web-app>

    第9、18行作用:用于指定Servlet被加载的时机和顺序,值必须为一个整数。如果这个值是一个负数或没有设定这个元素,Servlet容器将在客户端首次请求这个Servlet时加载它。如果设置此元素,值越小,越先被加载。

    3、<url-pattern>

    用来指定Servlet的访问路径,即URL。必须以“/”开头。

    1)可以在<servlet-mapping>中给出多个<url-pattern>,即一对多,如

        <servlet-mapping>
            <servlet-name>Servlet2</servlet-name>
            <url-pattern>/Servlet2</url-pattern>
            <url-pattern>/Servlet3</url-pattern>
        </servlet-mapping>

    此功能已被Filter替代。

    2)还可以在<url-pattern>中使用通配符“*”,可以匹配任何URL前缀或后缀。

    • <url-pattern>/servlet/*</url-pattern>:/servlet/a、/servlet/b,都匹配/servlet/*;
    • <url-pattern>*.do</url-pattern>:/abc/def/gif.do、/a.do,都匹配*.do;
    • <url-pattern>/*</url-pattern>:匹配所有URL;

    注意:通配符不能出现URL中间位置,也不能只有通配符且只能出现一个,如“/*.do”、"*.*"都是错误的

        优先匹配更具体的路径。

    二、web.xml文件的继承(了解)

      每个完整的JavaWeb应用中都需要有web.xml,但我们不知道所有的web.xml都有一个共同的父文件,他在Tomcatd的conf/web.xml中。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     5          version="3.1">
     6     <servlet>
     7         <servlet-name>default</servlet-name>
     8         <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
     9         <init-param>
    10             <param-name>debug</param-name>
    11             <param-value>0</param-value>
    12         </init-param>
    13         <init-param>
    14             <param-name>listings</param-name>
    15             <param-value>false</param-value>
    16         </init-param>
    17         <load-on-startup>1</load-on-startup>
    18     </servlet>
    19 </web-app>

    第7行,表示它的优先级最低,如果一个请求没有人处理,那么它来处理,显示404。

    第8行,当访问路径不存在时,会执行该Servlet!我访问index.html时也执行这个Servlet。

    三、ServletContext接口

    1)ServletContext接口概述

      服务器会为每个应用(项目)创建一个ServletContext对象:

      • ServletContext对象的创建是在服务器启动时完成的。
      • ServletContext对象的销毁是在服务器关闭时完成的。

      ServletContext对象的作用是在整个Web应用的动态资源之间共享数据。例如在AServlet中向ServletContext对象中保存一个值,然后再BServlet中就可以获取这个值,这就是共享数据了。

    2)获取ServletContext

    • ServletConfig#getServletContext();
    • GenericServlet#getServletContext();
    • HttpSessin#getServletContext();
    • ServletContextEvent#getServletContext();

      在Servlet中获取ServletContext对象:

    •   在void init(ServletConfig config)中:ServletContext context = config.getServletContext();

       ServletConfig类的getServletContext()可以获取ServletContext对象;

        在GenericeServlet或HttpServlet中获取ServletContext对象;

    •   GenericServlet类有getServletContext()方法,所以可以直接使用this.getServletContext()来获取;

    3)域对象的功能

    • 域对象就是用来在多个Servlet中传递数据。
    • 域对象必须有存数据功能。
    • 域对象必须要有取数据功能。

      ServletContext是JavaWeb四大域对象之一:PageContext、ServletRequest、HttpSession、ServletContext;

      所有域对象都有存取数据的功能,因为域对象内部都有一个Map,用来储存数据,下面是ServletContext对象用来操作数据的方法:

    • void setAttribute(String name, Object value):用来储存一个对象,也称之为存储一个域属性,例如:servletContext.setAttribute("xxx","XXX"),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并使用相同的name,那么会覆盖上一次的值,与Map特性相同。
    • Object getAttribute(String name):用来获取ServletContext中的数据,当前在获取之前需要先去存储才行。例如:String value = (String) servletContext.getAttribute("xxx"),获取名为xxx的域属性。
    • void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么方法什么都不做;
    • Eumeration getAttributeNames():获取所有域属性的名称。

    4)获取应用初始化参数

      Servlet也可以获取初始化参数,但它是局部的参数;也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备。

      可以配置公共的初始化参数,为所有Servlet而用,这需要ServletContext才能使用。

    web.xml文档

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
        <servlet>
            <servlet-name>CServlet</servlet-name>
            <servlet-class>web.servlet.CServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>CServlet</servlet-name>
            <url-pattern>/CServlet</url-pattern>
        </servlet-mapping>
        <context-param>
            <param-name>context-param</param-name>
            <param-value>context-value</param-value>
        </context-param>
    </web-app>
    Java文档
    public
    class CServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /*1、得到ServletContext * 2、调用它的getInitParameter(String)得到初始化参数 * */ ServletContext application = this.getServletContext(); String value = application.getInitParameter("context-param"); System.out.println(value); } }

    启动Tomcat,访问localhost:8080/CServlet,控制台输出“context-value”。

    5)获取相关资源

     1 /*
     2 *使用ServletContext获取资源路径
     3 * */
     4 @WebServlet(name = "DServlet")
     5 public class DServlet extends HttpServlet {
     6     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     7         /*
     8         * 得到的是绝对路径
     9         * /Users/Shared/练习/day_03/out/artifacts/day_03_war_exploded/index.jsp
    10         * */
    11         String path = this.getServletContext().getRealPath("index.jsp");
    12         System.out.println(path);
    13         /*
    14         * 获取资源的路径后,再创建出输入流对象
    15         * */
    16         InputStream input = this.getServletContext().getResourceAsStream("index.jsp");
    17         /*
    18         *获取当前路径下所有资源的路径
    19         * */
    20         Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF");
    21         System.out.println(paths);
    22     }
    23 }

    6)访问量统计小练习

      一个项目中所有的资源被访问都要对访问量进行累加。

      创建一个int类型的变量,用来保存访问量,然后把它保存到ServletContext的域中,这样可以保存所有的Servlet都可以访问到。

    • 最初时,ServletContext中没有保存访问量相关的属性
    • 当本站第一次被访问时,创建一个变量,设置其值为1;保存到ServletContext中;
    • 当以后的访问时,就可以从ServletContext中获取这个变量,然后再其基础上加1.
    • 获取ServletContext对象,查看是否存在名为count的属性,如果存在,说明不是第一次访问,如果不存在,说明是第一次访问。

    1、第一次访问:调用ServletContext的setAttribute()传递一个属性,名为count,值为1;

    2、第2~n次访问,调用ServletContext的getAttribute()方法获取原来的访问量,给访问量加1,再调用ServletContext的setAttribute()方法完成设置。

    /**
     * 统计访问量
     */
    @WebServlet(name = "Servlet")
    public class Servlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            ServletContext app = this.getServletContext();
            Integer count = (Integer) app.getAttribute("count");
            if (count==null){
                app.setAttribute("count",1);
            }else {
                app.setAttribute("count",count+1);
            }
            /*
            * 向浏览器输出
            * 需要使用响应对象
            * */
            PrintWriter pw = response.getWriter();
            pw.print("<h1>"+count+"</h>");
        }
    }

    注:当服务器关闭,计数重新开始。

    7、获取类路径下的资源

      获取类路径资源,类路径对一个JavaWeb项目而言,就是/WEB-INF/classes和/WEB-INF/lib每个jar包。

      Class、ClassLoader

    /*
    * 演示获取类路径下的资源
    * */
    @WebServlet(name = "Servlet",urlPatterns = "/Servlet")
    public class Servlet extends HttpServlet {
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            /*
            * 1、得到ClassLoader
            * 先得到Class,再得到ClassLoader
            * 2、调用器getResourceAsStream(),得到一个InputStream
            * */
    //        ClassLoader c1 = this.getClass().getClassLoader();
            //相对/class
    //        InputStream input = c1.getResourceAsStream("a.txt");
            Class c = this.getClass();
            //相对当前.class文件所在目录
            InputStream input = c.getResourceAsStream("a.txt");
            String str = IOUtils.toString(input,"utf-8");//问题所在之处,如何解决?
            System.out.println(str);
        }
    }

      

  • 相关阅读:
    新认识:SDF数据库
    捆绑(Bundle)
    VirtualBox-4.3.0启动报错及解决办法
    File.Exists(Application.StartupPath + \Settings\Settings.xml)
    C# [method Modifiers] abstract virtual override new
    360打补丁后系统无法启动的解决办法
    String.Compare 方法 (String, Int32, String, Int32, Int32)
    hdu4277 USACO ORZ
    Java实现 蓝桥杯 算法训练 最小乘积
    Java实现 蓝桥杯 算法训练 最小乘积
  • 原文地址:https://www.cnblogs.com/gdwkong/p/7440279.html
Copyright © 2020-2023  润新知