zoukankan      html  css  js  c++  java
  • jsp- servlet篇(一)

    1.Servlet的执行流程

    1. 从浏览器输入地址(发起请求)开始分析: http://localhost:80/xx/hello

    1. localhost   也可能是ip 或者域名  ---》定位服务器主机
    2. 80 定位到tomcat
    3. xx  上下文路径,tomcat/conf/server.xml  中的

             <Context  docBase=”F:workspaceday11-servletwebapp” path=”xx” />  中的path 

                通过上面的步骤找到了 docBase后面的项目的真实路径

                                根据约定去找到项目中的配置文件 web.xml

    2. web.xml内容分析:

    1. 找到url-pattern的值为 /hello
    2. 通过上一步中对应servlet-name 找到对应的servlet标签
    3. 找到对应的Servlet的全限定类名(包名+类名), com.gs.controller.HelloServlet
       仅仅是一个字符串而已,交给Tomcat进行处理, 并通过反射来创建对象并调用方法

    3. Tomcat对Servlet的创建:

    1. 通过上获得 servlet的完全限定名为参数使用反射来创建一个对象

        Class clz  =  Class.forName(“com.gs.controller.HelloServlet”)

        Clz.newInstance()  要求自己的Servlet类必须有公共的无参数的构造方法,否则会包NoSuchMethodException异常

       2.如果是第一次访问,就会创建一个Servlet的对象,并缓存起来

      3. 如果是第二次访问 (或者 n 次访问) 直接先从缓存中看有没有,有直接使用调用service方法

    <welcome-file-list>
           <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
      </welcome-file-list>
      
      
      <servlet>
          <!-- 给servlet可以任意取名,一般类名相同 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- servlet的全限定类名,也就是servlet的位置 -->
        <servlet-class>com.gs.controller.HelloServlet</servlet-class>
      </servlet>
      <servlet-mapping>
          <!-- 跟上面的servlet名字相同 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- 浏览器通过该url找到servlet,斜杠别丢 -->
        <url-pattern>/helloServlet</url-pattern>
      </servlet-mapping>

    Servlet的生命周期

    javax.servlet.Servlet接口中的方法:

      public void init(ServletConfig config):  初始化方法

      public void service(ServletRequest req, ServletResponse res):服务方法

      public void destroy():销毁方法

      public ServletConfig getServletConfig():返回当前Servlet的配置信息对象.

      public String getServletInfo():该方法返回Servlet的信息(作者,版权等).

    --------------------------------------------------------------------

    Servlet的生命周期方法:

      public void init(ServletConfig config):初始化方法,在第一次请求时调用,只在最初的时候调用一次.

      public void service(ServletRequest req, ServletResponse res):服务方法

      public void destroy():销毁方法

    Servlet生命周期可分为5个步骤

    1. 加载Servlet。当Tomcat第一次访问Servlet的时候,Tomcat会负责创建Servlet的实例
    2. 初始化。当Servlet被实例化后,Tomcat会调用init()方法初始化这个对象
    3. 处理服务。当浏览器访问Servlet的时候,Servlet 会调用service()方法处理请求
    4. 销毁。当Tomcat关闭时或者检测到Servlet要从Tomcat删除的时候会自动调用destroy()方法,让该实例释放掉所占的资源。一个Servlet如果长时间不被使用的话,也会被Tomcat自动销毁
    5. 卸载。当Servlet调用完destroy()方法后,等待 jvm 垃圾回收。如果有需要再次使用这个Servlet,会重新调用init()方法进行初始化操作

    细节注意点:

                 1:Servlet类必须使用public修饰,Servlet的构造器,必须是公共无参数的。(上面执行流程提到过)

         构造器先执行,创建Servlet对象:init,service,destory方法,都是非static方法,都得使用对象调用.

                 2:一个Servlet类在整个生命周期中最多只有一个对象

    Servlet什么时候初始化?

    1. 之前我们学习过,Servlet的生命周期:

    构造 -> init方法 -> [service](循环) -> distory(正常关闭)  .  也就是说只有在访问的时候servlet才创建

    2. 启动的时候就创建Servlet

    <load-on-startup>1</load-on-startup>     注意中间的数据越小启动越早。

    配置一个普通的servlet 
    
      <servlet> 
    
        <servlet-name>AServlet</servlet-name> 
    
        <servlet-class>com.servlet.AServlet</servlet-class> 
    
        <load-on-startup>4</load-on-startup><!--加这个标签,tomcat启动时会自动加载
    
    指定的servlet     值是servlet的加载顺序!!!   数字越小代表加载的优先级越高--> 
    
      </servlet>
    

      

    2. get方式和post方式有何区别

    1.请求参数的位置上:

    • GET方式:请求参数放在URL地址后面,以?的方式来进行拼接
    • POST方式:请求参数放在HTTP请求包中

    2. 数据长度上:

    • GET方式:在URL地址后附带的参数是有限制的,其数据容量通常不能超过1K。
    • POST方式:可以在请求的实体内容中向服务器发送数据,传送的数据量无限制。

    3.用途和安全上

      • GET方式提交的数据在地址栏可见,所以不安全。一般用来获取数据,多用于超链接请求。
      • POST方式提交的数据在地址栏不可见,安全。一般用来提交数据,多用于HTML的表单提交(处理订货表单、在数据库中加入新数据行)。

    3、Servlet的继承结构:

    • Servlet接口:定义了Servlet应该具有的基本方法
    • GenericServlet抽象类,实现了Servlet接口的同时,也实现了ServletConfig接口和Serializable这两个接口 。运用装饰者模式,为自己附加了ServletConfig装饰身份。ServletConfig接口中直接提供了getServletContext方法,所以当我们在实现Servlet时直接继承GenericServlet这个抽象类,就可以直接使用getServletContext方法来获取ServletContext对象了。
    • HttpServlet也是一个抽象类,但是他内部没有抽象方法(有抽象方法的类一定是抽象类,但抽象类中不一定有抽象方法),在通用Servlet的基础上基于HTTP协议进行了进一步的强化:继承了GenericServlet类,复写了GenericServlet中的Service方法,Service方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要继承HttpServlet,然后覆写doGet或doPost方法,而不要去覆写service方法。

     总结一句话:FirstServlet(自定义servlet)继承于抽象类HttpServlet,HttpServlet继承于抽象类GenericServlet,GenericServlet实现了Servlet接口

    实现Servlet的三种方式
      方式一:编写一个类去实现Servlet接口(必须重写Servlet接口里面所有的抽象方法)

      方式二:编写一个类去继承GenericServlet抽象类(重写生命周期的service方法(抽象方法))GenericServle抽象类它实现了Servlet接口,还实现了ServletConfig接口(这个接口中提供了

          一个getServletContext方法)可以在编写一个类中直接调用getServletContext方法就可以获得ServletContext对象。(开发中不常用)

      方式三:编写一个类去继承HttpServlet抽象类(没有抽象方法!根据页面的提交方式决定重写doGet或者doPost方法)

    4.   HttpServletRequest是ServletRequest接口的子接口,表示HTTP协议的请求对象

          HttpPServletResponse是ServletResponse的子接口,表示HTTP协议的响应对象

     /*  	 1. String getContextPath():获取项目的上下文路径,<Context path="上下文" ../>
        	 2. String getHeader(String headName):根据指定的请求头获取对应的值.
        	 3. String getRequestURI():返回当期请求的资源路径名称.  上下文路径/资源名
        	 4. StringBuffer getRequestURL():返回当前浏览器地址栏的数据
        	 5. String getRemoteAddr():返回请求服务器的客户端所在主机的IP地址    
        	   
        	 6. String getParameter(String name):根据参数名称,获取对应参数的值.
       		 7. String[] getParameterValues(String name):根据参数名称,获取该参数的多个值.
       		 8. Enumeration<String> getParameterNames():获取所有请求参数的名字
       		 9. Map<String,String[]> getParameterMap():返回请求参数组成的Map集合. key:参数名称  , value:参数值,封装在String数组中
    		 10. request.setCharacterEncoding("utf-8");
      */
    
        	request.setCharacterEncoding("utf-8");
        	response.setContentType("text/html;charset=utf-8");
    
        	String path = request.getContextPath(); //获取项目的上下文路径
    		System.out.println(path);             //  "/TestServlet111"
    		
    		String host = request.getHeader("host");  //根据请求头的名称查找对应的值
    		System.out.println(host);              // "localhost:8080"
    		
    		String uri = request.getRequestURI(); //获取请求的资源路径名称
    		System.out.println(uri);              //  "/TestServlet111/helloServlet"
    		
    		StringBuffer url = request.getRequestURL();//返回当前浏览器的地址栏数据
    		System.out.println(url);             //  "http://localhost:8080/TestServlet111/helloServlet"
    		
    		String ip = request.getRemoteAddr();//返回发起请求的客户端的所在主机的ip地址
    		System.out.println(ip);              //  "127.0.0.1"    也有可能     "0:0:0:0:0:0:0:1"
    		
    		System.out.println(request.getParameter("username"));   //根据参数名称,获取对应参数的值
    		String[] hobbys = request.getParameterValues("hobby");  //根据参数名称,获取该参数的多个值.
    		for (String h : hobbys) {
    			System.out.println(h);   
    		}
    		
    		Enumeration<String> names = request.getParameterNames(); //获取所有请求参数的名字
    		while(names.hasMoreElements()) {
    			System.out.println(names.nextElement());  //比如: username password gender等
    		}
    		//返回请求参数组成的Map集合. key:参数名称  , value:参数值,封装在String数组中
    		Map<String, String[]> params = request.getParameterMap();
    		System.out.println(params.get("password")[0]);         // "张三"
    		System.out.println(Arrays.toString(params.get("hobby")));   //  "[看电影, 打游戏]"	
    		
    /*		response.setContentType("text/html;charset=utf-8");
    		OutputStream getOutputStream():	获取字节输出流.  :文件下载
        	Writer getWriter():				获取字符输出流. :输出内容
        	注意:以上两个方法不能共存,只能使用其中一个。否则,报错
     */   	
    		response.getOutputStream().print("hello world");     //  hello world
    	}
    

      

    5:请求中文乱码问题

    1. 第一种解决乱码的问题:

    request.setCharacterEncoding("UTF-8");        只支持POST,不支持GET

    2. 第二种:

    在server.xml中修改编码:URIEncoding="UTF-8"    只支持GET,不支持POST

     推荐第一种和第二种同时使用

    3. 第三种:

    String name = req.getParameter("name");

    //将原来的码给转成二进制

    byte[] nameBytes = name.getBytes("ISO-8859-1");

    //再通过UTF-8的编码把这个数据转成相应的字符串

    String nameStr = new String(nameBytes,"UTF-8");

    GET与POST都支持

    注:第二种与第三种在GET的情况下是冲突的,不能同时存在

    6. servlet初始化参数

    1、servlet初始化参数,在web.xml中配置

    一、ServletConfig:代表当前Servlet在web.xml中的配置信息.

    • String getServletName()  -- 获取当前Servlet在web.xml中配置的名字
    • String getInitParameter(String name) -- 获取当前Servlet指定名称的初始化参数的值
    • Enumeration getInitParameterNames()  -- 获取当前Servlet所有初始化参数的名字组成的枚举
    • ServletContext getServletContext()  -- 获取代表当前web应用的ServletContext对象

    在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。

    当servlet配置了初始化参数后,web容器在创建servlet实例对象时,自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。

    这样做的好处是:如果将数据库信息、编码方式等配置信息放在web.xml中,如果以后数据库的用户名、密码改变了,则直接很方便地修改web.xml就行了,避免了直接修改源代码的麻烦

    代码举例:

    新建一个名为ServletConfigTest的Servlet,然后在web.xml中的<servlet>标签下,通过<init-param>标签为这个servlet配置两个初始化参数:

    <servlet>
            <servlet-name>ServletConfigTest</servlet-name>
            <servlet-class>com.vae.servlet.ServletConfigTest</servlet-class>
            <init-param>
                <param-name>name1</param-name>
                <param-value>value1</param-value>
            </init-param>
            <init-param>
                <param-name>encode</param-name>
                <param-value>utf-8</param-value>
            </init-param>
        </servlet>
    

      

    12 public class ServletConfigTest extends HttpServlet {
    13 
    14     public void doGet(HttpServletRequest request, HttpServletResponse response)
    15             throws ServletException, IOException {
    16 
    17         ServletConfig config = this.getServletConfig();  //拿到init方法中的ServletConfig对象
    18 
    19         // --获取当前Servlet 在web.xml中配置的名称(用的不多)
    20          String sName = config.getServletName();
    21          System.out.println("当前Servlet 在web.xml中配置的名称:"+sName);
    22          
    23         // --获取当前Servlet中配置的初始化参数(只能获取一个)经常用到
    24         // String value = config.getInitParameter("name2");
    25         // System.out.println(value);
    26 
    27         // --获取当前Servlet中配置的初始化参数(全部获取)经常用到
    28          Enumeration enumration = config.getInitParameterNames();
    29          while(enumration.hasMoreElements()){
    30          String name = (String) enumration.nextElement();
    31          String value = config.getInitParameter(name);
    32          System.out.println(name+":"+value);
    33          }
    34     }
    35 
    36     public void doPost(HttpServletRequest request, HttpServletResponse response)
    37             throws ServletException, IOException {
    38         doGet(request, response);
    39     }
    40 }

     2、使用注解完成servlet初始化参数。

    注意web.xml中:  metadata-complete="true":     值为true 时不扫描类上的WebServlet注解.     值为false 时要扫描,默认缺省。

    @WebServlet(
            name = "servletParameterServlet",
            urlPatterns = {"/servletParameter"},
            initParams = {@WebInitParam(name = "server", value = "mysql")
                    , @WebInitParam(name = "database", value = "user")}
    )
    public class ServletParameterServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //使用servletConfig类进行获取
            ServletConfig sc = this.getServletConfig();
            String server = sc.getInitParameter("server");
            String database = sc.getInitParameter("database");
            resp.getWriter().println("server : [" + server + "] database : [" + database + "]");
        }
    }

    相当于使用注解如下:

    7. ServletContext对象

    1. 什么是ServletContext对象

    ServletContext代表的是一个web应用的环境(上下文)对象,ServletContext对象内部封装是该web应用的信息,ServletContext对象 一个web应用只有一个。

    2. ServletContext对象的生命周期?

    创建:该web应用被加载(服务器启动或发布web应用(前提,服务器启动状态))
    销毁:web应用被卸载(服务器关闭,移除该web应用)

    3. 怎样获得ServletContext对象的三种方法

    1)Servlet类中有个init(ServletConfig config)方法,可以通过该方法获得ServletContext对象;

            例:ServletContext servletContext=config.getServletContext();

     2)可以通过this关键字来获得ServletContext对象;

            例:ServletContext servletContext=this.getServletContext();

    注意:

    super.getServletContext()               this.getServletContext()              getServletContext()

    这三个方法都是一样的,都是相当于从父类中的获取的方法。

     3)用过session对象来获取:ServletContext sc =  request.getSession().getServletContext();

     4.ServletContext的作用

    2)获得web应用中某个资源的绝对路径(重要 )

    String getRealPath(String path)       例如获得 F:workspaceservlet_jspwebapp

    (3)获取当前应用的上下文路径.     String getContextPath():     也就是 Tomcat/conf/server.xml中的path

    (4)ServletContext是一个域对象(重要)
    什么是域对象?   存储数据的区域就是域对象

    域:域对象在不同的资源之间来共享数据,保存数据,获取数据。

    ServletContext域对象的作用范围:整个web应用(所有的web资源都可以随意向servletcontext域中存数据,数据可以共享

    域对象的通用的方法:
    保存共享数据: setAtrribute(String name, Object obj);    //第一个参数为字符串,第二个是Object(也就是任意类型)
    获取共享数据: getAtrribute(String name);
    删除共享数据: removeAtrribute(String name);

    8.获取资源文件的三种方法. 

    1.采用ServletContext对象获取  。 特征:必须有web环境,任意文件,任意路径。

    public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            //拿到全局对象
            ServletContext sc = this.getServletContext();
            //获取p1.properties文件的路径
            String path = sc.getRealPath("/WEB-INF/classes/p1.properties");
            System.out.println("path=" + path);
            //创建一个Properties对象
            Properties pro = new Properties();
            pro.load(new FileReader(path));
            
            System.out.println(pro.get("k"));
        }
    

     

    2.采用resourceBundle获取。 只能拿取properties文件,非web环境。

    //采用resourceBundle拿取资源文件,获取p1资源文件的内容,专门用来获取.properties文件
            ResourceBundle rb = ResourceBundle.getBundle("p1");
            System.out.println(rb.getString("k"));
    

      

    3.采用类加载器获取: 任意文件,任意路径。

    public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            //通过类加载器
            //1.通过类名 ServletContext.class.getClassLoader()
            //2.通过对象 this.getClass().getClassLoader()
            //3.Class.forName() 获取  Class.forName("ServletContext").getClassLoader
            InputStream input = this.getClass().getClassLoader().getResourceAsStream("p1.properties");
            //创建Properties对象
            Properties pro = new Properties();
            
            try {
                pro.load(input);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //拿取文件数据
            System.out.println("class:" + pro.getProperty("k"));
        }
    

      

    9. Servlet线程安全问题

    由于Servlet容器是多线程单实例的模型(一个Servlet类在整个生命周期中最多只有一个对象),当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。

    1. 解决servlet线程安全问题:

    1. 把全局变量改为局部变量。
    2. 使用synchronized对doGet进行同步, protected synchronized  void doGet(HttpServletRequest request, HttpServletResponse response) 

            采用这种方式明显不合适,因为这样T2必须要等T1执行完毕以后才可以执行,大大的影响了效率。

          3.如果是静态资源则加上final表示这个资源不可以改变。比喻 final static String url="jdbc:mysql://localhost:3306/blog";

       4. 实现 SingleThreadModel 接口,和同步差不多,影响性能,已经过时。

    参考:https://www.cnblogs.com/LipeiNet/p/5699944.html

    https://www.cnblogs.com/tanjian/articles/1633162.html

     参考文献 :

    https://blog.csdn.net/qq_38353993/article/details/83277339

    https://www.jianshu.com/p/fb574ba6f1a9

    https://www.cnblogs.com/smyhvae/p/4140877.html

    https://blog.csdn.net/qq_29132907/article/details/80390792

    https://blog.csdn.net/qq_15096707/article/details/71081313

  • 相关阅读:
    html5——拖拽
    html5——多媒体(四)
    html5——多媒体(三)
    html5——多媒体(二)
    html5——全屏滚动
    html5——web字体
    html5——伸缩比例案例(携程)
    html5——伸缩比例
    html5——伸缩布局
    html5——多列布局
  • 原文地址:https://www.cnblogs.com/gshao/p/10293837.html
Copyright © 2011-2022 走看看