JavaWeb-Servlet(一)

 一 Servlet(Server Applet)是Java Servlet的简称,是服务器小应用程序
  1)用来完成B/S架构下,客户端请求的响应处理
 
  2)平台独立,性能优良,能以线程方式运行
  3)Servlet API为Servlet提供了通用的编程接口
  4)Servlet一般在容器中运行,对外统一接口,由容器来调用。
    常见的Servlet容器:Tomcat
       
 二  TomcatServlet的关系
  上面说过,Servlet需要对外统一接口,那么谁来统一这些接口呢?这个时候就需要容器来调用。
  Tomcat是一个Web应用轻量级服务器,同时也是一个ServletJSP容器。其作为Servlet容器,有三种工作模式:独立的Servlet容器、进程内的Servlet容器和进程外的Servlet容器。

    web服务器收到客户端的Servlet访问请求后,若是服务器装载并创建了Servlet的实列对象

  1) Tomcat将http请求文本进行解析,然后封装称为HttpServletRequest类型的Requset对象

  2) Tomcat将要响应的信息封装为HttpServletResponse类型的response对象进行返回

 
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
     request;
    HttpServletResponse response;
    try {
        request = (HttpServletRequest)req;
        response = (HttpServletResponse)res;
    } catch (ClassCastException var6) {
        throw new ServletException("non-HTTP request or response");
    }

    this.service(request, response);
}

 三  创建一个Servlet

  3.1 Servlet的执行流程

    首先,如果浏览器由这样一个输入:http://localhost:8080/demo/MyServlet

  http:http协议 

      统一资源定位符URL。

        格式:<协议>://<主机>:<端口>/<路径>

  localhost:域名

  8080:Tomcat端口号

            

  demo:   web应用的名称,在webapps下找是否存在demo的目录。

  MyServlet:web资源,在demoweb的应用的应用下查找是否存在此资源。

    /MyServlet资源就是我们的一个Servlet 

        ->   得到/MyServlet字符串

        ->   使用/MyServlet到web.xml文件中查找每一个<servlet-mapping>下的<url-pattern>标签里的内容,然后得到sevlet-name

        ->   使用sevlet-name去servlet标签中找到对应的相同名称的servlet配置。

        ->   得到servlet配置中的servlet-class内容。     

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

   3.2 DIEA开发Servlet

    1 新建JAVA EE Web Appication工程。

    2 新建一个Servlet类。

    3 导入需要依赖的tomcat目录下的servlet-api.jar包

          

  4  编写FirstServlet的代码.

  

package javademo;

import java.io.IOException;
import java.io.PrintWriter;

public class FirstrServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter pw = response.getWriter();
        pw.write("<h1> hello first servlet!</h1>");
    }
}
   

    5 编写web,xml配置文件 dom4j才能正确解析

<servlet>
    <servlet-name>FirstrServlet</servlet-name>
    <servlet-class>javademo.FirstrServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>FirstrServlet</servlet-name>
    <!-- 响应所有请求-->
    <url-pattern>/FirstrServlet</url-pattern>
</servlet-mapping>


  3.3 详解Servlet实现原理

    3.3.1  servlet的生命周期是什么?

     服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf)

          该servlet对象去处理所有客户端请求,在service(ServletRequest req,ServletResponse res)方法中执行

          最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。

            

      

   3.3.2 为什么创建的servlet是继承自httpServlet,而不是直接实现Servlet接口?

  Servlet是一个接口,如果实现了这个接口,那么就必须实现接口里面定义的所有方法。

  我们来看HttpServlet源码:

   继承了HttpServlet实际上也就实现了Servlet接口,没有必要再去实现Servlet中的方法。HttpServlet在实现servlet接口时,已经实现了Servlet里面的所有方法,所以不用再去覆写对应的生命周期等方法。

      

   Servlet接口:

public interface Servlet {
        
    //由Servlet容器调用,以指示将servlet放入服务器的servlet
    void init(ServletConfig var1) throws ServletException;
    //返回一个servlet对象,其中包含这个servlet初始化和启动参数。
    ServletConfig getServletConfig();
    //由servive调用,以允许servlet对请求做出响应
    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    //返回有关servlet的信息,如作者,版本和版权
    String getServletInfo();
    //由servlet容器调用,以只是servlet将排除在服务器之外
    void destroy();
}

  ServletConfig接口:

 interface ServletConfig {
    String getServletName();

    ServletContext getServletContext();

    String getInitParameter(String var1);

    Enumeration<String> getInitParameterNames();
}

  其中servletContext接口是Servlet中最大的一个接口,呈现了web应用的Servlet视图。获得ServletContext对象也就能得到我们需要的大部分信息。

  GenericServlet中有两个Init函数,一个有参数一个无参 。这样做是为什么呢?

  

  博主 一杯凉茶解释的很好:通过这几个方法一起来讲解,首先看init(ServletConfig config)方法,因为只有init(ServletConfig config)中带有ServletConfig对象,为了方便能够在其他地方也能直接使用ServletConfig对象,而不仅仅局限在init(ServletConfig config)方法中,所以创建一个私有的成员变量config,在init(ServletConfig config)方法中就将其赋值给config,然后通过getServletConfig()方法就能够获取ServletConfig对象了,这个可以理解,但是在init(ServletConfig config)中,158行,还调用了一个init()方法,并且这个init()方法是空的,什么读没有,这是为什么呢?这个原因是为了防止一件事情,当我们需要在init方法中做一点别的事情,我们想到的方法就是继承GenericServlet并且重写了init(ServletConfig config)方法,这样依赖,就破坏了原本在GenericServlet类中init(ServletConfig config)写的代码了,也就是在GenericServlet类中的成员变量config会一直是null,无法得到赋值,因为被重写了,就不会在执行GenericServlet中init(ServletConfig config)方法中的代码。要想赋值,就必须在重写的init(ServletConfig config)方法中调用父类的init(ServletConfig config)方法,也就是super.init(ServletConfig config),这样一来,就很不方便,怕有时候会忘了写这句代码,所以在GenericServlet类中增加一个init()方法,以后需要在init方法中需要初始化别的数据,只需要重写init()这个方法,而不需要去覆盖init(ServletConfig config)这个方法,这样设计,就好很多,不用在管    init(ServletConfig config)这个其中的内容了。也不用出现其他的问题。

  四  关于ServletConfig对象,ServletContext对象、request对象,response对象的学习。

   ServletConfig对象

      1)通过getServletConfig()获得。

      2)通过继承父类(GenericServlet)的方法得到一个ServletConfig对象

      

    功能:获取servletname context parameter initparameternames

public interface ServletConfig {
    //获取web.xml中配置的Servlet-name
    String getServletName();
    //获取ServletContext对象 其中内容非常多
    ServletContext getServletContext();
    //获取在servlet中初始化参数的值。
    String getInitParameter(String var1);
    //返回类型是枚举型,获取在Servlet中所有初始化参数的名字。相当于有多个<init-param>
    Enumeration<String> getInitParameterNames();
}
    

 

  Web.xml配置如下:

 运行结果如下:

 

  ServletContext对象

    获取:

      1)getServletContext()

      2)getServletConfig().getServletContext();

    功能:tomcat为每个web项目都创建一个ServletContext实列,主要是为了方便数据共享,让每个Servlet都可以访问到它。

   4.1 web项目中共享数据

  在一定范围内(当前应用),使多个Servlet共享数据

    setAttribute(String name, Object obj) 在web项目范围内存放内容,放入对应的key和value,以便让在web项目中所有的servlet读能访问到

    getAttribute(String name) 通过指定名称获得内容

    removeAttribute(String name) 通过指定名称移除内容 

    实例如下:

    

 getServletContext().setAttribute("name1","value1");

  4.2 获取全局配置信息

    整个web项目初始化参数 (这个就是全局初始化参数,每个Servlet中都能获取到该初始化值)

    getInitPatameter(String name)  //通过指定名称获取初始化值

    getInitParameterNames()  //获得枚举类型 上面说过的,多个servlet-name

  4.3 获取web项目资源

     4.3.1 获取web项目下指定资源的路径:getServletContext().getRealPath("/WEB-INF/web.xml")

        String  getRealPath(String path);//根据资源名称得到资源的绝对路径

        4.3.2 获取web项目下指定资源的内容,返回的是字节输入流。InputStream getResourceAsStream(java.lang.String path)

  

 public  void  test()throws IOException{
        InputStream in  = getServletContext().getResourceAsStream("/WEB-INF/web.xml");
        //统一编码才能正确进行输出
        InputStreamReader is = new InputStreamReader(in,"UTF-8");
        BufferedReader br = new BufferedReader(is);
        String s = null;
        while ((s = br.readLine())!=null)
        {
            System.out.println(s);
        }

    }

    结果如下,正是web.xml里面的配置内容

    4.3.4 实现Servlet的转发

    

ServletContext sc = this.getServletContext();
RequestDispacher rd = sc.getRequestDispacher("/转发页面");
rd.forward(request,response);

  4.4 Request、Response

    4.4.1 request和response是什么?

    request就是将请求文本封装而成的对象,所以通过request能获得请求文本中的所有内容,请求头、请求体、请求行 。

    response是服务器根据请求进行的响应

      request

       包含:请求头,请求行,请求体。

    下面是一个实际的请求报文:

①是请求方法,HTTP/1.1 定义的请求方法有8种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常的两种GET和POST,如果是RESTful接口(需要在WEB.XML中进行filter配置)的话一般会用到GET、POST、DELETE、PUT。
②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL
③是协议名称及版本号。
④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。
⑤是报文体,它将一个页面表单中的组件值通过param1=value1&param2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1&param2=value2”的方式传递请求参数。
  请求报文具有固定的结构格式:
  Request Headers
  设置::response.setHeader(java.lang.String name, java.lang.String value) 设置指定的头

  Accept:告诉服务器,客户机支持的数据类型

  Accept-Encoding:告诉服务器,客户机支持的数据压缩格式

  Cache-Control:缓存控制,服务器通过控制浏览器要不要缓存数据

  Connection:处理完这次请求,是断开连接还是保持连接

  Cookie:客户机通过这个可以向服务器带数据

  Host:访问的主机名

  Upgrade-Insecure-Requests:参考http://www.cnblogs.com/hustskyking/p/upgrade-insecure-requests.html

  User-Agent:告诉服务器,客户机的软件环境


  response也有与之对应的响应报文

   

 Response Headers响应头

  Connection:处理完这次请求后,是断开连接还是继续保持连接

    Content-Encoding:服务器通过这个头告诉浏览器数据的压缩格式

    Content-Length:服务器通过这个头告诉浏览器回送数据的长度

    Content-Type:服务器通过这个头告诉浏览器回送数据的类型

    Date:当前时间值

    Server:服务器通过这个头告诉浏览器服务器的类型

    Vary:Accept-Encoding ——明确告知缓存服务器按照 Accept-Encoding 字段的内容,分别缓存不同的版本;参考:https://imququ.com/post/vary-header-in-http.html

    X-Powered-By:服务器告知客户机网站是用何种语言或框架编写的。

     总结:搞懂基础性的东西才能让未来的路走的更远!

原文地址:https://www.cnblogs.com/zqoceean/p/9343491.html