servlet原理与web请求机制

                                                     前言

                                                     
1. html :标记语言,遵守一定的web标准,主要的作用,是静态的显示一些web内容/

servlet = java  + html
jsp = html + java

jsp 是 servlet的轻量级封装.

2.    w3c 是一个web标准的制定者,非盈利性组织;     www.w3c.org   
      jdon 框架;
      
3. 动态网页技术:
    cgi:公共网关接口,主要是在服务器使用,一定的语法动态构建客户端的显示,主要的特点是多语言支持,vb,c,
       asp: 微软对于cgi的替代品,语法及开发都比cgi简单
       php : 结合asp 以及cgi的特点,自行开发的一套语言,集成了c ,java,c++,asp 等动态网页技术的特点
       servlet: java体系对于cgi的替代

       jsp:是对servlet的封装但不是替代

4. socket 技术

     web容器是实际上是java对于servlet 按照java web规范的服务封装,本质上是一个socket服务,客户端通过发起http请求访问web服务,而web服务是一个socket 按照http的封装。具体查看例子:http://www.songwie.com/articlelist/35

       

                            servlet 

                                  
  c/s :  客户端/服务器
         代表:QQ
         必须有客户端和服务器软件完成多有的逻辑操作.
         缺陷:  服务升级维护方面极为不方便
         优势: 在一定的环境下可以减轻服务器压力.速度比较快,效率加大
  b/s :  浏览器/服务器
         优势: 无缝升级.客户成本低.
         缺点: 对网络有要求
         
   服务器: web容器或者web服务器,
    本质上都是一个软件,主要负责,接收客户端的请求(request),然后解析,
    根据具体的内容执行相应的业务操作,最后返回给客户,
    客户想要在浏览器中访问应用,必须借助于web容器或者web服务器
   
      广义: 凡是可以部署在web工程,供客户在浏览器中操作业务的软件都成为web服务器
      狭义: web服务器包括web容器和ejb容器
      
      常见的web服务器:
      apache tomcat  
      jboss
      商用:  BEA weblogic , IBM websphere 
      
   客户端: 浏览器
   
   部署: 将web工程放置在服务器固定目录,客户就可以通过浏览器访问
   
   请求(request): 客户端浏览器发出url请求,根据所带有的数据查找服务器及相应的业务处理相应,
                  服务器将处理的结果放在response中返回给客户端浏览器,获得之后显示结果
   
   相应(response):
   
   2. response的状态:
        200: 处理成功
        404: 表示请求的url没有找见
        500:服务器内部程序逻辑错误 
         
   3. tomcat 的目录结构:(端口修改:conf/server.xml)
   
    bin  :tomcat 的脚本目录,主要放置在tomcat的命令文件
        common ;主要放置tomcat 以及所有部署的web工程共享的文件                 
        conf :放置tomcat 的配置文件,如,用户角色,端口,域名绑定....
        logs :存放tomcat的多有的日志文件,一天为单位
        server :tomcat 的主管理页面,
        shared :存放的是web工程共享的内容
        temp: 临时文件目录.
        webapps : tomcat 中默认的工程部署目录
        work: 将jsp文件翻译成servlet 以及将翻译好的servlet编译成二进制文件的存放目录
        
        
   4. servlet的概念:
    广义: servlet是一个javeEE的规范 , 由sun 公司制定规范,所有的开发者在符合规范的基础上实现具体的业务逻辑
         servlet是运行在web服务器上的java程序
    具体上讲:
        sun 基于网络协议以及服务器的特征,将java进行封装,提供给开发人员接口,
        开发人员只需要按照一定的流程进行处理,将本地的java程序应用在网络中
             对于开发人员来说.servlet 实际上和操作java类没有任何区别,使得实例化,内存管理等等就和java一样
   5. cgi : 公共网关接口,跨语言的web处理组件(语言)
            
      cgi 操作流程:
         客户访问具体的url ----1--> httprequest到达服务器,查找相应的脚本,然后启动相应的线程执行逻辑
         ------2-----> 脚本执行将结果返回----3------>服务器接收处理的结果------4------->客户接受response,显示结果给客户
        
   6. servlet 的执行流程:
    客户端发起请求--------->
    服务器接收到请求,
            1  查看访问的资源,检查是否实例化,如果实例化,直接进入下一步启动服务线程
            2. 如果没有实例化,显实例化servlet对象,然后进入下一步,整个生命周期,中servlet只实例化一次
    调用服务器方法,执行业务逻辑
    将结果返回给服务器,包装封装
    将结果返回给客户端,显示结果 
     
   7. web 工程的结构:
      pro
      |
      |
      src    java源文件
      |
      webRoot/webContent        (放置web工程的内容,web的部署部分) 
             |
             |
             META-INF   
             |
             WEB-INF   ( .jsp文件, .html文件. css文件  , js文件,  图片  , doc 文档)
                |
                |
                web.xml   (服务器查找工程以及资源的依据)
                |
                lib       (第三方的jars)
                |
                classes   (src 中 源文件的编译文件)
    8.servlet 的操作流程
      1. 实现(构建)servlet类
       方式:
        1. 继承父类(HttpServlet抽象类)  自动调用server() 方法;
          推荐的实现方式,一般我们实现重写父类的doPost(),或doGet()方法
          而不去重写server() 方法,原因httpServer将service()进行完整的封装
          会根据客户的请求方式,选择调用具体的业务方法.  
          调用   参见源码
             2.继承父类(GenericServlet抽象类) 
               但是必须需要父类实现server方法,主要是客户没有任何自己的数据传输到服务器端得请求
               一般用于servlet 处理流操作或者多媒体操作等需求
             3. 实现server 接口,
                主要是在servlet 生命周期的各个环节中有业务操作的时候 
               
      2. 配置web.xml 实现servlet的容器管理
         客户书写url---->发出请求---->找到服务器----->找到web应用(找到了web.xml的实例)
         --->根据具体的url查找servlet--mapping------>servlet---->实例化启动线程,调用方法
         
         配置语法:
         <servlet>
    <servlet-name> 和servletmapping中标签中的一致</servlet-name>
    <servlet-class> servlet类的全称(包名.类名)</servlet-class>
  </servlet>

         <servlet-mapping>
    <servlet-name>和servletmapping中标签中的一致 </servlet-name>
    <url-pattern>进入web应用时候查找指定资源的路径 </url-pattern>
         </servlet-mapping>
        
      3.书写servlet类的服务管理,调用时有服务线程完成调用
       
      根据不同的servlet构建方式,选择业务书写的方法
       
      4.部署servlet
          1.使用IDE工具
          2. 手动部署
              1.在服务器上指定目录下监理工程目录,里面放入WebRoot或者
              WebContent下的所有内容
          3. 打包部署.
              将工程的webRoot下的内容达成.war包,放入服务器制定目录,服务器启动将会自动解压
                   
      5.启动服务器
        1. 使用IDE工具启动.
        2. 手动启动
      6.请求servlet
        在浏览器输入url.请求资源
        -----------------------------------------------------------------------------------------------
       
                                          第二章(问题:线程不安全,那么什么时候线程开始结束)
      1.  LoginFormServlet();    使用servlet构建登陆页面 ,连接注册页面
        --------->LoginServlet() 接收浏览器的数据,和数据库交互,验证用户)                                 
                                         
         register.html     接收客户信息.调交给服务器,
         ------------->   RegisterServlet   接收静态页面信息进行入库持久化操作
         资源流程通过,----->获得数据---->处理业务(确定表--->映射类-->使用数据构建对象---->将对象插入数据库)
         
      2   (注意乱码问题)
         1. 后台正常,返回给客户乱码.是由于response所带数据的编码格式和浏览器不一致
            (浏览器不确定那个用什么格式显示,默认用iso8859-1来显示)
            在获得流之前:
           response.setCharacterEncoding("utf-8");
         2. 前台正常送到后台之后乱码,以pose方式提交,使用在后台获得request中数据前制定编码格式
          request.setCharacterEncoding("utf-8");
          
         3.前台正常,以get方式提交数据,后台乱码,需要修改服务器server.xml 中conntentor标签,在其里面加上属性
           在修改端口的位置添加上:URIEncoding="utf-8"
           
         
         修改: 配置文件不能保存中文问题
            General ---->contentType---->Text---->javaProperties(修改编码方式)(utf-8)
            
            
     3.  注意:
        在servlet中处理业务逻辑:
          1. servlet处理业务逻辑和以前没有任何区别
          2. 要注意和以前不同的地方在于编程者要感受体会客户感受(乱码问题)
          3.业务处理必须位于servlet的servece方法中
          4.servlet和html的结合,
             当用户界面不会由于不同的条件动态生成的时候建议使用html和服务器的servlet交互
          5. servlet中也可以使用jdbc 的中间件进行资源访问
      
      
     4.  hilo 算法: 主要用于生成数据库主键, high值  :存储在数据库中,并且存储的表是单值单列
                                         , low值  :在内存中产生
                 当向数据库中插入数据时,先从数据库中获得high值,在和内存中的low值拼接成新的数值作为主键
                 同时马上将high更新写回数据库,为了保证数据的完整性,需要在在实现的时候加锁
                 
                 eg:
                   create table h1_tbl (
                    NEXT_val number);
                   
                   insert into h1_table values(100);
                   commit;
                   
                   Integer.parseInt(high+""+low);
        ---------------------------------------------------------------               
                                                    第三章:(资源访问)
                                                    
                                                jdbc,hibernate,JNDI,服务器跳转    
                                                
           
           servlet编程要点:   首先要保证跳转流程正确------>处理数据流-------->针对数据作具体的操作
           
      1. servlet 的生命周期: 
              主要讨论servlet的构建,初始操作,及主要讨论servlet的调用,销毁
        1. 加载并初始化
        
           由容器发起,对于应用的web.xml进行处理
           容器启动的时候确定应用读取web.xml构建其实例对象(ServletContext)(context)(全局变量),然后读取解析xml,将全局参数加入到ctx中
           然后解析servlet标签,构建ServletConfig对象,然后将局部参数加入到ServletConfig对象实例(config)中,再将ctx对象加入到config,保证每个
           servlet都能使用全局变量.
           
           初始化servlet类,并且进入第二步(可选的)
           当前servlet版本都是默认使用延迟加载,
           程序员可以再servlet标签中配置是否随服务器启动加载具体的servlet
            <load-on-startup>num</load-on-startup>
           num>0 :表示延迟加载多少时间
           num=0 :表示最晚加载,(所有的事情加载完了才加载)
           num<0 :默认配置,延迟加载,访问时实例化
           
           本操作在启动服务的时候完成,整个生命周期只执行一次,在一个线程正完成,不涉及线程安全问题;
           
        2. 初始化(调用init())
        创建servlet实例同时马上调用init(), 方法
        init()       ;主要用具在servlet构建的时候书写业务操作,
        init(config) ;先被调用,web容器调用此方法再调用无参的init(),
       
        此步骤由容器完成,整个生命周期中,只调用一次
       
        3. 调用service() 执行业务
        当servlet实例构建成功之后,所有的请求将会由分配的线程自动调用服务方法完成
       
        线程安全问题:
        解决方式:
        1. 尽量不要使用实例变量(成员变量),
        2. 可以使用单线程模式(不推荐)
        3. 给服务加锁
       
        4. 销毁servlet     destory(); 
               servlet组件并没有直接去销毁对象,交给垃圾回收机制,
               周期中的desory主要作用是,在servlet销毁的时候释放资源由程序员完成.
               
               此方法激发的时候:
               1. 显示调用 destory()
               2. 正常停止服务器:
                      1.正常停止   使用脚本文件或者ide工具正常关闭
                      2.强制停止 断电,或其他服务器崩溃异常,或者ide继承的强制关闭按钮
                      3.杀死进程  kill -9 pid(linux)
          
      
         2.  form表单:
          1. form表单的构建
          2. form表单的提交(action="" method="post/get(区别)")
          
          路径处理:
         3.  web工程的相对路径:
             对于servlet按照web.xml中 url-pattern 来作为参考,对于webRoot下的目录结构和此配置是一致的
      
         4. 程序架构:
         
            两层架构:cs架构.
            三层架构:
                   dao :数据处理层:数据库操作
                   service :负责接收view层 的数据,并且调用dao层的数据库操作,实现业务逻辑
                   view  :显示层,主要负责和客户交流
            多层架构: 一般在三层的基础上级一步加强程序的可维护性从而加入一些服务层
      
         5. JNDI:java 命名目录接口(待解决)
           作用:
            主要是对于应用中的对象进行重用,统一管理以达到重用的目的
            由sun制定的一套规范,我们的使用者只需要按照一定得规则操作即可达到预知的效果
           
            jndi 时位于网络上的某一指定位置的资源
            命名:  网络上的资源必须有自己独立的名称
           
            目录:  网络上的指定位置
                  1 .本地磁盘
                  2. web 服务器
                  3. 分布式开发或者应用
                  
            接口:  规范
           
            当前使用的是数据源(数据源是指将数据库连接对象使用连接池机制统一管理)
           
            数据源: sun 提供的一套 api 将数据库的信息和制定的目录按照具体的名称绑定,用户使用的时候调用api即可调用conneiontion 对象,
            使用以及使用完毕的对象都由数据源统一管理
           
            作用:主要给用户提供数据库的连接对象,并且使用连接池机制来管理,
           
            连接池机制:   构建一个池(集合) ,指定其最大的,最小的链接值,用户请求链接对象,将从池中分配到一个,使用完毕后,收回连接池,一共其他用户使用
                      连接池维持一个最小的连接池对象,当某一时刻需求比较大,会在创建一部分对象,但不能超过最大连接对象,当比较空闲的时候
                      将会销毁一部分,维持最小连接对象
              使用:
                 java:comp/env
                 
                 1. 获得上下文环境  
                    Context ctx = new InitialContext();
                     
                     上下文环境: 
                 2. 根据上下文环境,再指网络上的目录次根据名称查找资源
                   Datesource ds = ctx.loopup("java:comp/env/名称");
                 3, 获得使用的对象
                   connection  conn = ds.getConnecion();

         6. 服务器跳转:
            <1>. 服务器内部跳转:
            当客户发起请求到达服务器处理完客户请求的资源,此资源可能直接到达服务器另一个资源,然后将服务器另一个资源的内容返回给客户
           
            服务器内部跳转,地址栏没有改变,隐藏了资源的路径
           
               怎么跳转:
                1. 获得分发器:
                    1. 使用request获得
                    //RequestDispatcher dispatcher = request.getRequestDispatcher("");
                       在使用的过程中可以使用绝对路径或者相对路径
                    2. 使用servletcontext
                    //RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/resource/DispatchServlet");
                    注:获得的路径必须是绝对路径  ./表示当前工程
                       
                2. 调用的方法:
                    1. forward 
                       表示将先前的结果传递给第二个servlet,并且返回给客户的只是最后一个servlet
                       //dispatcher.forward(request, response);

                    2, include
                 表示在服务器内部跳转,返回给客户的是所有的处理结果
                 dispatcher.include(request, response);*/
               
            <2>........外部跳转:
                 使用response将请求转发,也成为资源重定向,之前的资源处理结果不显示给客户,客户只能得到后面资源,的处理结果,由于回到过客户端
                 所以地址栏栏发生变化
                 //response.sendRedirect("Dispatch2Servlet");
response.sendRedirect("/servlet/resource/Dispatch2Servlet");
                 
                 可以使用相对路径,也可以使用绝对路径   
            
            跳转选择:
               能使用内部跳转则不使用外部跳转,内部跳转不需要频繁和客户通信,并且隐藏url,相对效率和安全都比较高
         
               //路径跳转(内部)(地址不会变化)
//1. get 分发器
   //1. request方式 (路径都可以):
        //路径方式: 注:   (路径参考为webRoot开始)
 //绝对路径
//RequestDispatcher disp = request.getRequestDispatcher("/chat/chat.html");
 //相对路径
//RequestDispatcher disp = request.getRequestDispatcher("../chat/chat.html");
//2. servercontext 方式(路径只能为绝对方式):
//RequestDispatcher disp = getServletContext().getRequestDispatcher("/chat/chat.html");
 //路径方式:
        //2. 处理方法
   //方式1
//disp.forward(request, response); //内容 不包括 以前提交内容
//方式2
//disp.include(request, response); //内容 包括 以前提交内容
        //路径跳转(外部)(地址会变化)
               //可以使用相对路径,也可以使用绝对路径 注:  (路径参考为工程名servlet开始)
//相对
//response.sendRedirect("../chat/chat.html");
//绝对
response.sendRedirect("/servlet/chat/chat.html");
      
       7.   路径处理:
          .  web工程的相对路径:
             对于servlet按照web.xml中 url-pattern 来作为参考,对于webRoot下的目录结构和此配置是一致的
         
         1. web应用
            1. 服务器内部跳转:
              绝对路径:绝对路径的根以工程作为参考,即 / 表示工程
              相对路径:以web.xml的url-pattern以及webRoot下的目录作为参考为参考
            2. 外部跳转:
             绝对路径: 和服务器为根,所以需要明确标识servlet工程应用名称
             ex: /servlet/form/login
             
             相对路径:和内部跳转的参考一致
            
            3. 非web应用在web工程的路径
               绝对: 按照磁盘地址查找
               
               相对: 1 .资源放在webRoot下,以WEB-INF为相对目录,从classes 文件到web-inf 即可查找文件,与资源所在目录无关
                        (与操作环境有关)
                     2. 将资源放置在class所在目录使用反射获得资源,与webroot 没有关系
                     
                     3. 得到真实实际部署环境路径
                        ex  : getServletContext().getRealPath("/")+"image/clouds.jpg"
                     
                //绝对路径
//FileInputStream fis = new FileInputStream(new File("F:/学习相关/java/java学习/java学习总结/html&servlet&jsp/css/clouds.jpg"));
//相对;
//方式一:(资源放在webRoot下,以WEB-INF为相对目录,从classes 文件到web-inf 即可查找文件,与资源所在目录无关)
//FileInputStream fis = new FileInputStream(new File("../../../../clouds.jpg"));
//方式二: 将资源放置在class所在目录使用反射获得资源,与webroot 没有关系
//InputStream fis = ImageTest.class.getResourceAsStream("clouds.jpg");
//方式三:
//通过真实的物理路径得到
FileInputStream fis = new FileInputStream(new File(getServletContext().getRealPath("/")+"image/clouds.jpg"));

                     
        2. 非web工程:
        
          相对路径:
          a.以工程为参考,准确的说是按照classpath环境变量为参考
            ex: src/com/briup/a.jpg   
          
          b,将资源放置在class文件所在目录,然后使用反射获得资源,与webRoot没有关系(要手动放置)
          
          绝对路径: 磁盘的地址:
             ex: d:java/a.jpg
    
        8 .HTTP协议:
          HTTP的无状态性是指,通过HTTP协议出数据的时候,并不能直观的跟踪以及保留数据内容
            
          优势: HTTP无状态性促使bs架构的无缝升级的实现  ,数据可以随时更新变化并且不会造成资源浪费,
                                  
          解决方案:
            1. cookies :
                cookies 是一种浏览器机制,主要用于处理HTTP无状态兴的缺陷
                Cookies存储在浏览器端,以键值成对的形式存在,其构建在服务器端,保存在浏览器端,通过request,response分别获取和保存
                Cookies的键值是一个字符串,由编程者制定,值保存具体的数据,获取的时候,使用key值查找,所有客户端所有的Cookies维持
                       在一个集合中,而request到达服务器的时候,会带上此域下的所有Cookies的集合,
                
                
                Cookies的path 属性: 表示服务器的什么路径下的资源可以访问到的锁构建Cookies,默认为构建资源所在位置
                                   一般为:/, 表示服务器下的所有资源都可以获得Cookies
                Cookies的过期时间:表示Cookies创建之后再客户端浏览器保存的时间,默认为当前会话结束,浏览器关闭,在实际中,
                                 一旦使用Cookies不会给默认过期时间
                                 
            2. session :
            
              hibernate的sessions 源于通话,当一方发起请求,另一方发起应答,到通信结束,这个过程叫做session
              
              web中的session指的是当用户发起请求,创建对象之后,每次访问,都可以获得session中的对象,直到session过期,
                或者服务器结束.
                
              session对象的构建发起在服务器端,并且由request对象构建,构建好的对象存储在服务器端,以后每次客户发起请求,都会找到session
              
              session构建之后,第一次返回客户端,将系统分配的 JSESSIONID 以Cookies的形式存储在客户端,以后请求,服务器会自动查找session
              根据id 找到对应的session,从而获得数据;
              
              如果客户端Cookies禁用,我们的服务器端对于路径需要使用重写的形式,将id维护在url中
              
              SessionServlet(分别向我们的request,response以及ctx放入数据,)----->内部跳转/外部跳转,--->Session2Servlet(获取数据)
              
              session的创建: 使用request.getSession() 获得,其中可以传入Boolean类型参数,默认为true,表示当客户端jsessionID不存在的
                             时候,新建一个新的Session,如果设置为FALSE,那么在操作的时候,尤其是在获得Session中的数据的时候,如果没有id
                             那么不会创建一个新的Session,于是超出空指针异常
              
              Session的生命周期:
                 程序中调用方法设置,单位为妙,web.xml中设置单位为分钟,都设置了就选择就近原则
               1. 程序中:
                javax.servlet.http.HttpSession session = request.getSession(true);
session.setAttribute("session", "sessionTest");
session.setMaxInactiveInterval(1);
                 
               2. web.xml配置:
                  <!-- 配置Session失效时间(单位分钟),都设置了,依程序为主 -->
                 <session-config>
         <session-timeout>5</session-timeout>
          </session-config>
  
       解决方式Cookies禁用问题:
       
                 如果客户端Cookies禁用,我们的服务器端对于路径需要使用重写的形式,将id维护在url中在url中追加  jsessionid =.......,从而查找
        
       关闭浏览器只是说明Session的 jsessionid 丢失,不不能说明Session的生命周期结束,生命周期由程序设定或默认的30分钟
       要想要Session立即失效,可以调用其销毁方法

   9 .监听器:
      定义: web 工程的一个组件,实现一定接口既可以观测servlet或者其他的web 工程的各个常见对象的活动,比如stx  ,Session ,requeswt
         等等都可一见到,对可观测
         
      监听对象: 常见的web 对象,监听的动作比如,常见,销毁,添加数据获得数据,更新数据,删除数据等.....
      
  10 . 过滤器:
     定义: 位于客户端与所请求资源之间的对象,在访问资源之前,需要数据进行过滤,只有符合条件才能通过,当处理完了之后,同样还要进行过滤
     
   配置: 主要是指: filter类的配置和mapping的配置,而mapping可以配置多个对应一个filter类,路径表示他的资源  
   
   <filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>com.briup.filter.EncodingFilter</filter-class>
  </filter>
  <filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/filter/*</url-pattern><!-- /*表示所有文件都过滤 -->
        </filter-mapping>
  <filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/*</url-pattern><!-- /*表示所有文件都过滤 -->
  </filter-mapping>
   
  filter 中chain.doFilter() 主要作用是转发请求,期之前的内容是在请求到达资源之前处理,之后是在结果返回之后处理,不调用此方法,请求将被切断
   filter的调用顺序有web.xml 中mapping的顺序决定即写在前面的则先处理过滤
  login.html---->loginServlet(用户名密码固定)---?>返回User 对象 ,并且保存在Session中,直接掉转到loginServlet
  loginServlet访问的前提是User 对象存在,并且经过过滤