⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 day02.txt

📁 servlet上课内容2.
💻 TXT
字号:
Servlet_day02   langna  2007-9-24   星期一
    回顾:
    1,   JAVA_HOME
         CATALINA_HOME
    2,  目录结构:
      webapps:(tomcat 的发布目录)
          serv-app |- WEB-INF |--classes
                                           |-- web.xml
                        |- 静态页面                   
    3,  servlet, 直接实现Servlet接口,覆盖service方法 
                    实现HttpServlet类,覆盖doGet 或 doPost 
                    不覆盖的话,报405的错误;
                    如果服务一样在一个里面调用另一个就行;
                    如果服务不一样的话,分别实现就行;
        http://ip:port/应用路径/虚拟路径
    4,  生命周期:
        
        创建loading;  由服务器创建的;
        初始化;init();
        服务方法;service();doGet();doPost();
        销毁:destroy();
        把 servlet 放到 servlet容器里, 替你管理 ;都有自己的生命周期;
        
    不一定是关闭服务器时才销毁, 规范没有规定死;
    正常情况下一定会调用destroy方法;特殊情况下(如 掉电)不调;
    释放一些线程,关闭一些文件;但不能过分依赖;
    
 一,  servlet的生命周期:    
 
   1,  servlet的创建时机:
        1)第一个请求来的时候,判断servlet实例是否存在,不存在的话创建一个实例;
          启动服务器是没有servlet实例被创建的;  这是默认的;
        2)在配置文件web.xml的<servlet>标签中; 
           <load-on-startup>正数</load-on-startup>,表示服务器启动时创建,并依照数字大小按顺序创建,
           只用重要的Servlet才会是用这个设置。1, 2 , 3 ; 1先被创建;但不要相互依赖;
           为什么服务器启动时创建:
           如:发现文件不存在的业务, 启动服务器时看,不能等第一个请求到来时才发现;  
               或者是解析xml文件是否合法时;这些业务逻辑放在init()方法中;不存在时可以抛异常;
               凡是对外界有依赖时或者重要的复杂的servlet , 用这种初始化方法;
               Tomcat用的是SAX解析;
             
                 如果web.xml 写错了,或不合法的话,应用就会发布失败;连静态页面也不能访问; 
                 打开控制台可以看到出错信息:  catalina.sh  run 
                 
   2, init()方法是工作在单线程情况下的;  
        log.txt 记录访问用户的ip地址: 
        log.txt文件放到哪里? 绝对路径;c:\  或  /home/soft  都不跨平台;
        跨平台: 不改 .java源文件 , 不改xml文件 或 属性文件;
        一般只能满足第一个要求; 把 xml 文件再配置一下;
        
        servlet 初始化参数在<servlet>标签中配置 : 可以用ServletConfig对象的
                                             getInitParameter(String name)方法来得到参数。
        <init-param>
            <param-name>file</param-name>
            <param-value>c:\log.txt</param-value>
        </init-param>
      
       public void init(ServletConfig config)throws ServletException{
            this.config = config;
            init();
       } 
       
       FileOutputStream;
       没有文件会给你创建,但是没有目录不会给你创建;      
       如果doGet方法什么也不写,会返回一个空白页面给你;   
       
       成员变量和局部变量最好不起同一个名字;
       
       //写日志: 
       logger.print(new  Date()+" : ");
       logger.print(request.getRemoteAddr());//获取客户端的 ip 地址; 
       logger.flush();
       
       getServletConfig() ;//如果子类没有覆盖的话, 得到父类 servlet 的初始化信息; 
       500-- 执行servlet代码时报异常; 
       
       父类的init(ServletConfig config)方法将config保存下来;而我们那覆盖时没有保存下来;
       如果覆盖有参的, 必须在子类中调用 super.init(config);才能通过getServletConfig()得到值;
       
       或者直接覆盖无参的方法,父类中有参的会自动调用无参的;
     
        public void init(ServletConfig config)throws ServletException
        {
        this.config = config;
        init();
        }

        public void init()throws ServletException
        {
    	.....;//覆盖了的无参的init()方法,会在Servlet创建时调用有参的init方法时
    		也会被调用。
        }
          
        直接调用getInitParameter()方法而不用再通过getServletConfig(); 方法内部实现了调用,节省编程;
        一个  <init-param> 标签只能配一个参数; 而  <init-param> 可以配多次; 
  3, service()方法:
       servlet只有一个, 并发时,多个线程同时去执行service方法; 
       request/response 每个线程一个; 
      
       给这几个语句加锁: 
       synchronized(this/logger){// this是当前的servlet; 或  logger的空间;  在这里是一样的; 
           logger.print(new  Date()+" : ");
           logger.print(request.getRemoteAddr());//获取客户端的 ip 地址; 
           logger.flush();
       }
       
      每个对象都是一块内存空间, (属性如果是公共的,要结合final;不能被修改);
      getName();//不用考虑并发;
      setAge();//必须考虑并发;
      getGender();//锁越细越好;对属性加锁;
      
      除非方法体中的所有内容都需要同步,才对方法加锁;否则只对代码块加锁就行了;
      response和request每次访问都会创建新的;局部变量; 不会构成并发;
      
      如何编写线程安全的资源(加锁):
      1) 首先判断需不需要加锁;
          操作同一资源,修改时; 或  有些资源只能工作在单线程下;
          一个连接在同一时间只服务于一个线程;
      2) 怎么样去加锁;
          对于局部(成员变量)的,直接对当前对象加锁即可;(同一时间只有一个servlet ); 
          对于全局的, 直接对静态变量(类名.class)加锁即可;
          
        碰见成员变量,用Vector ; 和实例的数量是一样的;
        方法的变量,用ArrayList; 每次调用方法都会创建新的;
         servlet 是服务器端的被多个线程同时访问的资源; 不要在service方法体中自己再开一个线程;
         
       ServletConfig : 在init之前已经封装好了, 只有一个;  
       SingleThreadModel:标记接口; 只解决了实例变量并发的问题;没有解决静态变量的问题;
       避免使用实例变量; 避免不了的要加锁;
  4,  destroy();
      工作在单线程下的;
     
      下面的了解;无太大意义; 
      web这种环境不适合做很长时间的访问;以下情况不用考虑; 长时间执行的内容放在后台执行;
         一个线程正在执行init()时,不可能有线程执行service();
         有线程执行service()时,有可能有一个线程进入destroy();  
         在destroy()方法中判断一下,所有进入servlet的线程都正常结束;再执行destroy()方法;
         用计数器, 是否关闭服务器; 来实现; 
        
         伪代码: 
         private  int threads;
         private boolean isShuttingDown;
         
         public   synchronized  boolean isShuttingDown(){
            return isShuttingDown;
         }
         public   synchronized  void  enterService(){
             threads++;
         }
         
         public   synchronized  void  leaveService(){
             threads--;
             notifyAll();
         }
         public void  doPost(){ 
            enterService();
            for(int i=0;i<=10;i++){
                if(isShuttingDown()){
                   break; //正常退出;
                }
                //service
            }
            leaveService();
         }
         
         public void destroy(){
             synchronized(this){
                  if(thread>0){
                        isShuttingDown=true;
                   }
                  while(thread>0){
                       wait();
                  }
             }
         }
        

 二 , Form 表单:
      reset :重置, 将页面恢复到打开时的状态;而不是清空; 
      Enumeration  paramNames=request.getParameterNames(); 
      
      while(paramNames.hasMoreElements()){
            String name=(String)paramNames.nextElement();
            String[] values = request.getParameterValues(name);
            out.println(name+ "= " + values);
      }
      //连接values
      private String  join(String str, String[]  val){
            
      }
      
      测试:
      
      配置文件: /servlet虚拟路径
      action="/应用路径/servlet虚拟路径"
      浏览器上, http://ip:端口号/应用路径/servlet虚拟路径
     
      表单:默认发送的有text, password, hidden, textarea;
      单选框和复选框必须选才能发过来; 否则是空串;
      
      getParameter(参数名);//返回参数的值, 名字必须一致,包括大小写;如果不存在返回null;
      注意复选框的处理;
      
      注意: 
      数据库不能放到公共网络上; 放到局域网中,必须通过代理服务器来访问; 
      定时的将数据从一个企业的数据库导出来, 放到另一个企业的数据库中;
      1) 备份,还原;  数据库不能直接访问;
      2) t表 , m表 ,  jdbc代码处理; 数据库ip地址不能公开;
      3)客户端,服务器端, 写一个定时器, 用socket传送, 封装 xml , 解析xml  用jdbc ; 
      
      getParameterMap: key -- String 
                                  value-- String[] 
       
      超链接和在地址栏传参数(查询字符串)一样;  都是get请求; 
      传大量的信息或保密的信息用post请求; 
   
   下次课: 
     
     解析请求和解析请求的url;
     如何用jdbc;
     如何配连接池;
   
   问题:
    1, 如何编写线程安全的servlet;
    2,如何解析请求;  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -