• Java Web开发笔记


    问题:
    读取资源文件问题
    servletContext.getRealPath()
    servletContext.getResouce().getPath()
    setvletContext.getResourceAsStream()
     

    1、Servlet入门(编写Hello World程序)

         根据接口文档的接收,创建一个一个servlet需要以下步骤
         1)在tomcat的webapps目录下创建hello目录,然后在hello目录下创建WEB-INF/classes目录
         2)在classes目录下创建一个HelloWorldServlet.java文件
         3)在该源文件中定义一个HelloWorldServlet类,该类可以实现Servlet接口,为了方便,
              咱们可以直接继承HttpServlet或者类,然后重写service方法,代码如下
              备注:其实我们应该重写doGet( )或者doPost( )方法,因为HttpServlet中的service实现了一些处理逻辑,比如,根据请求方法调用doGet()或doPost(),或者是缓存的处理  等,但是我们这里主要是体验下servlet的执行过程,所以先重写service方法,真正项目不能这样干的,切记。对于service( )、doGet( )、doPost( )三种的关系,后面会做解析
             
     
        4)编译HelloWorldServlet.java源文件
             javac -d . HelloWorldServlet.java
             注意:编译时候,需要将tomcat主目录下的
    lib中的servlet-api.jar加入到classpath,否则会编译失败
     
        5)在WEB-INF目录下创建web.xml的配置文件,并编写如下内容:
            
     
    6)重启tomcat服务器,然后再浏览器上输入:http://localhost:8080/hello/helloWorld,结果如下:
          
     
    搭建好的web目录结构如下
    F:.
    └─helloWorld
        └─WEB-INF
            └─classes           //存放Java class文件 
            └─lib                 //存放jar包
            └─web.xml         //web应用部署说明文件
        └─*.jsp、*.html
     
     
    2、Servlet生命周期
         Servlet生命周期是由部署的Servlet容器控制的。Servlet不能单独运行,它的运行完全由Servlet引擎来控制和调度
         Servlet接口主要定义了以下一些方法:
             init(ServletConfig config)
             service(ServletRequest req, ServletResponse res)
             destroy()
         1)当Servlet被首次访问时,容器会创建该Servlet的实例,这里强调“首次”,因为该servlet实例对象在整个服务器运行期间仅存在一个
         2)然后调用init()方法进行Servlet对象初始化  
         3)然后调用service处理客户的请求 
         4)直到WEB服务器关闭,servlet容器会调用调用destroy()方法销户该servlet实例。
         注意:
         1)针对客户的多次Servlet请求,通常情况下,服务器只会创建一个servlet实例对象,也就是说
              Servlet实例对象一旦被创建,它就会驻留在内存中,为后续的其他请求服务,直至web容器
              退出,servlet实例对象才会销毁。
         2)在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求
              都导致Servlet引擎调用一次Servlet的service方法。对于每个访问请求,Servlet引擎都会创建
              新的HttpServletRequest请求对象和一个新的HttpServletResponse相应对象,然后将两个对象
              作为参数传递给它的调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法
     
     
    3、Servlet的使用
         在Servlet的开发过程中,一般不直接实现Serlvet接口来编写Serlvet,而是通过继承现成的HttpServlet来开发Serlvet,然后覆盖doGet和doPost方法
         HttpServlet类主要提供了一下方法:
             init(ServletConfig config)
             service(ServletRequest req, ServletResponse res)
             service(HttpServletRequest req, HttpServletResponse res)
             destroy()
             doXXX( )方法,如doGet()
     
         HttpServlet的调用过程
         当Servlet被首次访问时,容器会创建该Servlet的实例,
         1)然后调用init()方法进行Servlet对象初始化  
         2)然后调用service处理客户的请求,在Service方法中会根据客户请求method来判断具体执行哪个doXXX()方法
              例如,如果GET,则调用doGet() ,如果是post,则调用doPost方法进行处理
         3)当一个servlet许久不被访问的时候,servlet容器会调用调用destroy()方法销户该servlet实例。 
     
     
     
    4、web.xml配置
    由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
    <servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name><servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
    <servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个主要的子元素:<servlet-name><url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:
     
     
    1)同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元的的<servlet-name>子元素的设置可以是同一个
    2)在Servlet映射到的URL中可以使用 * 通配符,但是只能有两种固定的格式:一种是 *.扩展名;另外一种是以正斜杆( / ) 开头并以“/*"结尾,即不带后缀名的URL,则必须以正斜杆( / ) 开头
     
     第一种方式
    <servlet-mapping>
         <servlet-name> servletName <servlet-name>
         <url-pattern>/* <url-pattern>
    </servlet-mapping>
     
    第二种方式
    <servlet-mapping>
         <servlet-name> servletName <servlet-name>
         <url-pattern>*.do <url-pattern>
    </servlet-mapping>
     
    <servlet-mapping>
         <servlet-name> servletName <servlet-name>
         <url-pattern>xxx/yyy/test.do <url-pattern>
    </servlet-mapping>
     
    注意:第二种方式中的第一个例子,*.do前面不能带任何内容,否则报错,例如,不能配置成如下
    <servlet-mapping>
         <servlet-name> servletName <servlet-name>
         <url-pattern>xx/yy/*.do <url-pattern>
    </servlet-mapping>
     
     
    3)Servlet URL映射原则
         适用通配符时,有些时候,多个Servlet映射的URL可能存在冲突,那么此时会使用最具体匹配原则进行匹配
         *.后缀 的URL优先级最低
     
         对于如下的一些映射关系:
         Servlet1 映射到 /abc/*
         Servlet2 映射到 /*
         Servlet3 映射到 /abc
         Servlet4 映射到 *.do
     
         问题:
         当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
          Servlet引擎将调用Servlet1
         当请求URL为“/abc时,“/abc/*”和“/abc都匹配,哪个servlet响应
     
         Servlet引擎将调用Servlet3
         当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
          Servlet引擎将调用Servlet1
         当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
     
         Servlet引擎将调用Servlet2
         当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
     
         Servlet引擎将调用Servlet2
     
     
    4)配置Servlet在web服务器启动就加载
          如果在web.xml中<servlet>元素中配置了一个<load-on-startup>元素,那么WEB服务器在启动时,就会装载并创建
          Servlet的实例对象以及调用Servlet实例对象的init( )方法。
          例如:
          
         注意:
         <load-on-startup>元素指定的指只能为自然数(大于等于0的整数),数值越小,优先级越高,越优先被加载
     
     
    5)默认的servlet
         ①如果某个Servlet的URL映射路径仅仅为一个正斜杆( / ) ,那么这个Servlet就成为当前Web应用程序的缺省Servlet.
         ②凡是在web.xml中找不到匹配的<servlet-mapping>元素的URL时,它们的访问请求都将交给缺省的Servlet处理,
            也就是说,缺少的Servlet的用于处理所有其他的Servlet都不能处理的访问请求
         ③在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet
            的Servlet,并将这个Servlet设置为缺省的Servlet。
         ④当访问Tomcat服务器的某个静态HTML文件和图片时,实际上是在访问这个缺省servlet,由这个Servlet将这些
            静态资源返回给浏览器
     
         注意:一般不要自己配置默认的Servlet,不然,客户端无法访问静态的web资源
          
     
     
    5、Servlet中常用对象
        ServletConfig
        ServletConfig封装了web.xml中<init-param>配置的初始化参数,该对象由Servlet容器在创建Servlet实例对象时创建,
        然后调用Servlet的init( )方法时,传递给Serlvet,进而可以在Servlet中访问当前Servlet的初始化参数。
        1)在web.xml配置初始化参数的案例
             
        2)ServletConfig对象提供方法
             getInitParameter(param_name)      #通过参数参数名称获取参数的具体值
             getInitParameterNames( )              #获取所有初始化参数的名称,以Enumeration类型返回
             getServletName( )                          #获取当前Servlet名称,即web.xml中配置的<servlet-name>元素值
             getServletContext()                        #获取当前web应用的context域对象
        
        注意:如果重写了init( )方法,则必须调用父类的init方法,super.init(config),否则this.getServletConfig()获取不到ServletConfig对象
     
        ServletContext
        WEB容器在启动的时候,会为每个WEB应用都创建一个对应的ServletContext对象,它代表当前的WEB应用。
           1)如何得到ServletContext实例对象
             ServletConfig对象维护了对ServletContext的引用,可以通过ServletConfig的getServletContext对象获取
        
           2ServletContext的作用
               ① 多个Servlet通过ServletContext对象实现该WEB应用的数据共享,这个就是所谓的context域对象
                   Servlet可以通过ServletContext对象的setAttribute(key ,value)方法将数据存放到ServletContext对象中
                   然后其他的Servlet对象可以通过ServletContext对象的getAttribute( key ) 来获取这些数据
                   例如:
                       servlet1:
                            this.getServletConfig().getServletContext().setAttribute("abc" ,"123456789") ;
                      servlet2:
                            this.getServletConfig().getServletContext().getAttribute("abc")
     
              ② 获取WEB应用的初始化参数,就是web.xml的<context> </context>元素维护的WEB应用初始化参数
                  
                  程序中的使用
                  
             ③ 实现Servlet的转发
                 RequestDispatcher rd = context.getRequestDispatcher("/1.jsp"); 
         rd.sendRedirect(req ,resp);
     
             ④ 访问资源文件
                 得到文件路径
                 读取资源文件的三种方式
                 .properties的文件
     
                 数据有关系则使用xml,没有关系则使用.properties文件
     
                 在sevlet中,“/"表示当前web应用目录
                 
                ServletContext.getResourceAsStream()
                ServletContext.getRealPath()
                //普通java类中读取文件
                ClassLoader.getResourceAsStream(); //1)文件不能太大 2)文件只会被加载一次,所以不能实时读取更新后的文件内容
                ClassLoader.getResource(file_name).getPath()   //得到文件路径,然后再使用FileInputStream进行处理
     
     
        ServletResponse对象
        用于向客户端输出响应数据。该对象实例再每次客户端请求时,web服务器都会创建一个新的response对象,然后通过service()方法传给当前servlet。
        在子类HttpServletResponse中提供了许多用户操作Http响应消息头的方法,如addHeader(name ,value) 和setHeader(name ,value) ,
        这两个方法的区别是addHeader是添加HTTP消息头,而setHeader则如果已经存在消息头,则会更新,否则添加该消息头
        OutputStream 和writer,都是用于输出响应报文体内容。
        outputStream用于输出字节流,可以处理任何内容,而writer处理字符流,只能处理字符数据
        response.getOutputStream()与response.getWriter()不能同时调用
     
       实现文件下载
      
     
     
        控制浏览器缓存
        
        
     
         ServletResponse实现重定向
           1)通过http消息头来实现
                response.setStatus(302);
                response.setHeader("location" ,"/firstServlet/index.jsp")
           2)通过response提供的函数来实现
                response.sendRedirect("/firstServlet/index.jsp")
           特点:
           1)浏览器地址栏的的地址内容会发生变化
           2)浏览器发生了两次请求
           例如:
           
     
     
           response一些细节
           1)getOutputStream 和 getWriter这两个方式相互排斥,不能在一个请求中同时这两个方法
                
           2)Servlet程序向ServletOutputStream或PrintWriter对象写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当做响应消息的正文,然后在与各响应状态行和各响应消息头组合后输出到客户端
           3)Servlet的service方法调用结束后,Serlvet引擎会检查getOutputStream 和 getWriter返回的输出流对象是否已经调用过close,如果没有,则Servlet引擎会调用close。
           4)服务器在向客户端输出时,即调用out.prinln(),并不会及时的返回到客户端,而是会放到缓冲区中,只有当缓冲区溢出或则调用out.flush()   或则response.flushBuffer()提交时,才向客户端输出,而调用response.sendRedirect()会清空缓冲区内容,所以在跳转之前写的客户端输出代码不会有效果
     
     
     
     
         ServletRequest对象
         获取客户端传输的参数
         1)request.getParameter("key")
         2)request.getParameterNames();
         3)request.getParameterValues();
         4)request.getParameterMap();
              可以结合BeanUtils使用
     
         request乱码问题
         对于post提交方式:
              在getParameter()之前先设置request的码表,即request.setCharacterEncoding("charset")
         对于get方式(这里无论是表单提交还是普通的超链接提交)
              默认情况下,request使用ISO8859-1进行解码,所以先获取参数值,再手工转码处理
              String value = request.getParameter("key")
              String newValue = new String(values.getBytes("ISO8859-1"),"new charset")
     
         request实现服务器端跳转
         request.getRequestDispatcher("url").forward(req ,resp);
     
     
          
         实现页面跳转方式总结
         首先,页面跳转有浏览器端跳转和服务器跳转两种方式,
         浏览器端跳转时,浏览器地址栏请求地址发生改变,浏览器总共发生了两次请求,此时这两次请求时独立的
         服务器端跳转时,这种方式对客户来说是透明的,客户完成察觉不到。浏览器地址栏请求地址没变化,跳转前请求页面和跳转后页面是同一个request对象
     
          //客户端跳转,通过SerlvetResponse对象完成,location可以为绝对URL或者相对URL,如果是相对URL,则系统在将它放入location报头之前,自动将相对URL转换成绝对URL
          resp.sendRedirect(location)
       等价于
       response.setStatus(302);
          response.setHeader("location"  , location)
     
       //服务器端跳转,通过RequestDispatcher对象完成,RequestDispatcher对象可以通过SerlvetRequest对象或者SerlvetContext对象的获取,但是两者有区别
       RequestDispatcher.forward(req, resp);
       
       //这个可以是绝对地址也可以使相对地址,如果这里使用相对地址,则同ServletContext.getRequestDispatcher,相对于application_root的地址
       req.getRequestDispatcher("/servlet005/005")   
     
       //这里使用相对地址,相对于application_root的地址 
       ServletContext.getRequestDispatcher("/servlet005/005"
     
     
      
       Servlet实现缓存
       浏览器缓存原理
       第一种, 浏览器把缓存文件的最后修改时间通过 header ”If-Modified-Since“来告诉Web服务器
           1. 浏览器客户端想请求一个文档,  首先检查本地缓存,发现存在这个文档的缓存,  获取缓存中文档的最后修改时间,通过: If-Modified-Since, 发送Request给Web服务器。

           2. Web服务器收到Request,将服务器的文档修改时间(Last-Modified): 跟request header 中的,If-Modified-Since相比较, 如果时间是一样的, 说明缓存还是最新的, Web服务器将发送304 Not Modified给浏览器客户端, 告诉客户端直接使用缓存里的版本

     

     

           第二种, 浏览器把缓存文件的ETag, 通过header "If-None-Match", 来告诉Web服务器。
     
     
           禁止浏览器缓存
             resp.setHeader("Pragma","No-cache");
         resp.setHeader("Cache-Control","no-cache");、
         resp.setDateHeader("Expires",0);
     
     
     
     Servlet处理表单数据
     
    servlet容易已经帮我进行url解码,并将相关参数进行解析处理,我们仅需要调用以下一些方法便可以获取requet中的相关参数
     
    //该方法获取某个参数名为name的参数值,如果该参数名对应多个参数,则返回第一出现的值

    req.getParameter(name)


    例如:
    xxxx?userName=test&passwd=123456
    调用getParameter("userName") 则返回test
     
    xxxx?userName=test&passwd=123456&userName=abc
    上面url出现参数userName两次,调用getParameter("userName") 也是返回test
     
     
     
     
    //返回该请求中所有的参数名称,它是一个Enumeration类型
    req.getParameterNames()
     
    例如:
    xxxx?userName=test&passwd=123456
    调用getParameterNames() 则返回Enumeration,该对象包含userName和passwd两个参数名
     
     
     
    //返回该请求中所有的参数名称,它是一个Map类型,该Map实例的key是参数名称,value就是参数值所组成的数组。
    getParameterMap()
     
     
     
    //获取指定参数名称的所有值,返回值为数组类型
    getParameterValues(name)
    xxxx?userName=test&passwd=123456&userName=abc
    上面url出现参数userName两次,调用getParameter("userName") 则返回由{"test" ,"abc"}组成的数组
     
     
     
    Servlet Web页面压缩技术—gzip
    在serlvet 中使用gzip压缩技术页面进行压缩返回给客户端浏览器,使用步骤如下:
     
    1)首先通过客户端发送的Http报文头Accept-Encoding的字段值是否包含gzip,例如:Accept-Encoding : gzip  //因为不是所有客户端都支持gzip编码
    2)设置返回内容编码格式:resp.setHeader("Content-Encoding""gzip");  //告诉客户端返回的gzip编码内容
    2)创建GZIPOutputStream输出流对象,OutputStream out = new GZIPOutputStream(resp.getOutputStream());
    3)将输出内容写入输出流对象,out.write(content.getBytes());
    4)关闭输出流对象out.close( ) //??这一步必须执行,否则无法将输出内容返回给客户端
     
     
     
    Servlet中Cookie的管理
    cookie是由服务器向客户端发送,并将内容保存在浏览器客户端
     
    服务器端向客户端发送cookie
    1、创建Cookie对象,创建Cookie对象需要传入cookie的name和value,这两个参数都是字符串类型
          Cookie cookie = new Cookie("name" ,"vaue");
          注意:这样创建出来的cookie是会话级别的,即,会话结束后,该cookie对象就会被浏览器清理掉,如果希望cookie保存到硬盘,则进行第二步
     
    2、设置cookie的最大有效期限。负数表示临时的,是会话级别的, 0表示是临时的(如果是新cookie)或者要求浏览器删除掉已经存在cookie,正数表示cookie的有效期限,以秒为单位
         cookie.setMaxAge(senconds)  //senconds以秒为单位
     
    3、将cookie发送到客户端。
          如果cookie对象在服务器端创建后没有发送到客户端,那么该cookie是不启作用的。
          HttpServletResponse.addCookie( cookie )  //把cookie添加http协议报头的Set-Cookies字段返回给客户端
     
     服务器端读取客户端的cookies
     Cookie[] cookies = HttpServletRequest.getCookies( ); 
     因为浏览器是以主机或者域名的方式保存cookie,因此,即使当前请求的URL没有向浏览器发送过cookie,但是HttpServletRequest.getCookies( )可能不为空的。
     因此,需要遍历cookies这个数组,然后根据cookie的name来判断是否我们需要的cookie
     
    修改浏览器cookie值
    因为浏览器向服务器端发送cookie信息时,仅仅是发送cookie的name和lvalue,其他的信息,如maxage都已经"丢失"
    所以需要修改cookie值时,需要重新创建一个同名的cookie,同时设置它maxage等属性
     
     
     
     
    Servlet会话跟踪(Session)
    1、什么是session?
    Session代表服务器与浏览器的一次会话过程,这个过程是连续的,也可以时断时续的,但是这个过程通过session来维护。在Servlet中,session指的是HttpSession类的对象。
     
    2、session的原理
    首先session是由服务器端产生的,在服务器端保存,然后在服务器返回响应页面时,在http响应报文头中将session的id以cookie的方式返回给浏览器吗,一般为JSESSIONID=xxxxx。后续浏览器请求页面时,再将该session id传给服务器,服务器首先根据这个session id查看有没对应的session对象,如果有,则直接取出来用。
     
    首次访问,服务器通过Set-Cookie报头将session id发送给客户端:
     
    第二次访问时,浏览器通过请求报头Cookie,将session id发送给服务器
     
    3、Servlet对session的管理
    Servlet中对应session接口类为HttpSession,该类提供一下方法对session进行管理
     
     
    4、session误区
    《1》Session创建的时间,即session是什么时候被创建的?
    一 个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时才被创建,注意如果JSP没有显示的使用 <% @page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句 HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的 session对象的来历。
    由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。
     
    引申:
    1)、访问*.html的静态资源因为不会被编译为Servlet,也就不涉及session的问题。
    2)、当JSP页面没有显式禁止session的时候,在打开浏览器第一次请求该jsp的时候,服务器会自动为其创建一个session,并赋予其一个sessionID,发送给客户端的浏览器。以后客户端接着请求本应用中其他资源的时候,会自动在请求头上添加:
    Cookie:JSESSIONID=客户端第一次拿到的session ID
    这样,服务器端在接到请求时候,就会收到session ID,并根据ID在内存中找到之前创建的session对象,提供给请求使用。这也是session使用的基本原理----搞不懂这个,就永远不明白session的原理。
    首次访问
     
    第二次访问
     
    通过图可以清晰发现,第二次请求的时候,已经添加session ID的信息。
     
     
    《2》服务器端Session删除的时间
      1)Session超时:超时指的是连续一定时间服务器没有收到该Session所对应客户端的请求,并且这个时间超过了服务器设置的Session超时的最大时间。
      2)程序调用HttpSession.invalidate()
      3)服务器关闭或服务停止
     
     
    《3》session存放在哪里
     服务器端的内存中。不过session可以通过特殊的方式做持久化管理
        
     
    《4》session的id是从哪里来,sessionID是如何使用的
    当 客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该 session对象,当浏览器下次(session继续有效时)请求别的资源的时候,浏览器会偷偷地将sessionID放置到请求头中,服务器接收到请 求后就得到该请求的sessionID,服务器找到该id的session返还给请求者(Servlet)使用。一个会话只能有一个session对象, 对session来说是只认id不认人
     
     
    《5》session会因为浏览器的关闭而删除吗?
     不会,session只会通过上面提到的方式去关闭。
     
     
    《6》关闭浏览器是否session也就无效了?
    其实不是,关闭浏览器,只能说该浏览器客户端与服务器端的本次会话结束,因为关闭浏览器时,浏览器会把保存session id的cookie JSESSIONID删除了,
    因此,该浏览器客户端下次再请求时,已经没有session id发给服务器端,因此服务器会创建一个新的session,旧的那个session,等待超时后,自动销毁
     
             
              
          





  • 相关阅读:
    jQuery -&gt; 获取指定上下文中的DOM元素
    安装Nginx须要系统的辅助软件(linux)
    ASP.NET MVC + MySQL で開発環境構築
    Parameters.Add和Parameters.AddWithValue
    MVC js动态生成from提交数据然后生成文件下载
    C# 压缩文件 的创建
    C#中的GetElementsByClassName方法
    windows下使用pip安装python模块lxml
    总结WCF开发中遇到的几个问题
    Xpath
  • 原文地址:https://www.cnblogs.com/itmanxgl/p/9617f98d947941174454f4a6b574c3f7.html
Copyright © 2020-2023  润新知