zoukankan      html  css  js  c++  java
  • Servlet技术(下)

    Servlet技术(下)

    1下载文件

    下载文件的实现:把需要下载的文件通过java InputStream 读入转换成二进制文件,再将InputStream中的内容读入到一个byte数组中,最后将byte数组中的内容写入到OutputStream输出流中,OutputStream的实例化对象由Tomcat容器创建的ServletResponse对象的获得

    package mypack;

    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.*;

    public class DownloadServlet extends HttpServlet {
     public void doGet(HttpServletRequest request,HttpServletResponse response)
            throws ServletException, IOException {
       OutputStream out; //输出响应正文的输出流
       InputStream in;  //读取本地文件的输入流
       //获得filename请求参数
       String filename=request.getParameter("filename");
       
       if(filename==null){
         out=response.getOutputStream();
         out.write("Please input filename.".getBytes());
         out.close();
         return;
      }
       
       //创建读取本地文件的输入流
       /* getResourceAsStream(java.lang.String path)
       ** Returns the resource located at the named path as an InputStream object.
       **/
       in= getServletContext().getResourceAsStream("/store/"+filename);
        /* available()
        ** Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream
        */
       int length=in.available();
       //设置响应正文的MIME类型,MIME类型设置为force-download,浏览器会以下载的方式来处理响应正文
       response.setContentType("application/force-download");
       response.setHeader("Content-Length",String.valueOf(length));
       response.setHeader("Content-Disposition", "attachment;filename=""+filename +"" ");
       
       /** 把本地文件中的数据发送给客户 */
       out=response.getOutputStream();
       int bytesRead = 0;
       byte[] buffer = new byte[512];
       /* read()
       ** Reads some number of bytes from the input stream and stores them into the buffer array b
       */
       while ((bytesRead = in.read(buffer)) != -1){
         /* out.write(byte[] b,int off, int len)
         ** Writes len bytes from the specified byte array starting at offset off to this output stream.
         */
         out.write(buffer, 0, bytesRead);
      }
         
       in.close();
       out.close();
    }
    }

    /****************************************************
    * 作者:孙卫琴                                     *
    * 来源:<<Tomcat与Java Web开发技术详解>>           *
    * 技术支持网址:www.javathinker.net               *
    ***************************************************/

     

    2 读写Cookie

    客户端首次访问服务器时,服务器先在客户端存放包含客户的相关信息的Cookie,以后客户端每次请求访问服务器时,都会在HTTP请求数据中包含Cookie(准确的说Cookie会包含在HTTP请求的请求头中),服务器解析HTTP请求中的Cookie,就能由此获得关于客户的信息

    Tomcat作为Web服务器,提供了与Cookie交互的API,即 java.servlet.http.Cookie,因此Web应用中的Servlet可以直接通过Cookie类来访问HTTP请求中包含的Cookie中的数据。

    package mypack;

    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.*;

    public class CookieServlet extends HttpServlet {
     int count=0;

     public void doGet(HttpServletRequest request,HttpServletResponse response)
       throws ServletException, IOException {
       
       response.setContentType("text/plain");
       PrintWriter out=response.getWriter();
       //获得HTTP请求中的所有Cookie
       Cookie[] cookies=request.getCookies();
       if(cookies!=null){
         //访问每个Cookie
         for(int i = 0; i < cookies.length; i++){
           out.println("Cookie name:"+cookies[i].getName());
           out.println("Cookie value:"+cookies[i].getValue());
           out.println("Max Age:"+cookies[i].getMaxAge()+" ");
        }
      }else{
         out.println("No cookie.");
      }

       //向客户端写一个Cookie
       //Cookie类的构造方法有两个参数,cookieName和cookieValue,都是字符串类型
       response.addCookie(new Cookie(
               "cookieName" + count, "cookieValue" + count));
       count++;
    }
    }

    /* Cookie类一些其他常用的方法
    ** cookie.setMaxAge(60*60) //设置客户端在本地保存该Cookie的时间1h,想要删除cookie直接将参数改为0即可
    ** cookie.setValue(string value) //修改cookie的值,cookieName是final类型的,不能修改
    */

    /* HTTPServletResponse提供的与Cookie相关的方法
    ** response.addCookie(Cookie cookie) //将该cookie加入到响应中
    */
    /* HTTPServletRequest提供的与Cookie相关的方法
    ** Cookie[] response.getCookies() //返回HTTP请求中的所有Cookie,将其作为一个数组返回
    */


    /****************************************************
    * 作者:孙卫琴                                     *
    * 来源:<<Tomcat与Java Web开发技术详解>>           *
    * 技术支持网址:www.javathinker.net               *
    ***************************************************/

    Cookie的共享范围

    默认情况下,哪个web应用保存的cookie,cookie就只在这个web应用中可以访问。

    在同一个Tomcat容器中共享Cookie

    一个Servlet容器可以包含多个web应用,为了使同一个Servlet中的其他web应用也能访问该cookie

    Cookie cookie=new Cookie("username","tom");
    cookie.setPath("/");
    response.addCookie(cookie);

    setPath(string path)方法: Specifies a path for the cookie to which the client should send the cookie.

    "/" 表示Tomcat服务器的根路径,相当于 localhost:8080/ 或者 webapp/ ,因此将cookie的path设置为 “/” 之后,客户端访问该浏览器中的其他web应用的时候也会发送该cookie

     

    在不同的Tomcat容器中共享Cookie

    Cookie cookie=new Cookie("username","tom");
    cookie.setDomain(".cat.tom");
    response.addCookie(cookie);

    setDomain(string pattern)方法:Specifies the domain within which this cookie should be presented.

     

    3 访问Web应用的工作目录

    每个Web应用都有一个工作目录,Servlet容器会把与这个Web应用相关的临时文件存放在这个目录下,Tomcat为Web应用提供的默认的工作目录为

    <CATALINA_HOME>/work/[enginename]/[hostname]/[contextpath]

    例如:web应用helloapp被默认发布到Tomcat的名为Catalina的Engine的localhost虚拟主机中,那么helloapp应用的默认工作目录为:

    <CATALINA_HOME>/work/Catalina/localhost/helloapp

    设置work directory

    web应用的工作目录可以在server.xml文件中的context标签中设置,通过workDir属性来设置

    在Servlet中获得work directory

    当Servlet容器在初始化一个Web应用时,会向刚创建的ServletContext对象中设置一个名为 “javax.servlet.context.tempdir” 的属性,该属性值为一个java.io.File类型的对象,代表当前Web应用的工作目录,因此,Servlet获取工作目录的方式为:

    File workDir=(File)context.getAttribute(“javax.servlet.context.tempdir”);

     

    4 转发和包含

    Servlet对象由Servlet容器创建,并且Servlet对象的service()方法也有容器调用,而一个Servlet无法直接调用另一个Servlet对象的service()方法,因为这个Servlet对象无法获得另一个Servlet对象的引用

    请求转发包含使一个Servlet对象可以调用另一个Servlet对象的方法

     

    java.servlet.RequestDispatcher类:

    该类表示请求分发器,包含include()forward()两个方法,分别表示请求和转发

    void forward(ServletRequest request, ServletResponse response)
    void include(ServletRequest request, ServletResponse response)

    可以看到forward方法和include方法都是包含两个参数 ServletRequest和ServletResponse的, 因此被请求或者包含的Servlet与原Servlet共享 request和 response对象

    获取RequestDispatcher对象的方法:

    //方式一:调用ServletContext的getRequestDispatcher(String path)方法
    //其中path表示被请求或者包含的Servlet的绝对路径,绝对路径以 “/” 打头,“/” 表示 localhost:8080/ 或者 webapp/
    //方式二:调用ServletRequest的getRequestDispatcher(String path)方法
    //其中path表示被请求或者包含的Servlet的绝对路径或者相对路径,绝对路径同上,相对路径表示原Servlet所在的目录

     

    **dispatcher.forward(request,response)**方法的处理流程:

    a.清空存放响应正文数据的缓冲去 因此原组件Servlet中已经通过PrintWriter或者ServletOutputStream写入响应正文中的内容会被清空(响应头中的内容是否会清空不知道,请试一试)。如果在调用forward之前调用了flushBuffer()或者close()方法,程序会抛出IllegalStateException异常

    b.如果目标组件为Servlet或者JSP,调用其service()方法,把该方法中的响应结果发送给客户端;如果是静态的HTML文档,就读取文档中的数据并把它发送到客户端

     

    dispatcher.include(request,response)方法的处理流程:

    a.如果目标组件为Servlet或者JSP,调用其service()方法,把该方法中的响应结果添加到响应正文中;如果是静态的HTML文档,就读取文档中的数据并把它添加到响应正文中

    b.返回到源组件的服务方法中,继续执行后续的代码块

     

    5 重定向 sendRedirect(String location)

    重定向机制是由HTTP协议提供的一种机制,存在于HttpServletResponse接口中,而ServletResponse接口中不包含该方法

    重定向的运作流程:

    1.用户在浏览器输入特定的URL,请求访问服务器端的某个组件

    2.服务器端的组件返回一个状态码为302的响应结果,该响应结果的含义为:让浏览器端再请求访问另一个Web组件。响应结果中提供了另一个Web组件的URL,另一个Web组件可以在同一个Web服务器上,也可以在不同Web服务器上

    3.浏览器接受到这种响应结果之后,再立即自动请求访问另一个Web组件

    4.浏览器接受来自另一个Web组件的响应结果

     

    HttpServletResponse.sendRedirect(String location)方法:

    Servlet源组件生成的响应结果不会被发送到客户端,只有重定向的目标组件生成的响应结果才会被发送到客户端

    如果在调用sendRedirect之前调用了flushBuffer()或者close()方法,程序会抛出IllegalStateException异常

    源组件和目标组件不共享ServletRequest对象,因为浏览器重新发出请求

    sendRedirect方法中的 location参数,如果以 “/” 打头,表示当前服务器根路径的URL , 如果以“http://” 开头,表示完整的URL

    目标组件不需要是同一个Web服务器上的Web应用,可以是任意服务器上的

     

     

    6 访问Servlet容器内的其他Web应用

    同一个Servlet容器中可以有多个Web应用,Web应用之间是可以互相访问的

    ServletContext接口中提供了getContext(String uripath) 方法,该方法可以获取其他Web应用的ServletContext对象,参数 uripath 指定其他Web应用的URL入口

    可以通过<Context>元素的crossContext属性设置Web应用是否能访问其他Web应用资源

    crossContext=false: Context元素对应的Web应用无法得到其他Web应用的ServletContext对象

    crossContext=true: Context元素对应的Web应用可以得到其他Web应用的ServletContext对象

     

    7 解决并发问题

    一个Web应用可能在一个时间被多个浏览器请求服务,因此可能会产生并发的问题

    解决并发的方案:

    1.合理决定在Servlet中定义的变量的作用域类型

    package mypack;

    import javax.servlet.*;
    import java.io.*;

    public class HelloServlet1 extends GenericServlet {
    private String username=null; //username为实例变量

    /** 响应客户请求*/
    public void service(ServletRequest request,
    ServletResponse response)
    throws ServletException, IOException {

    //把username请求参数赋值给username实例变量
    username=request.getParameter("username");

    try{
    Thread.sleep(3000); //特意延长响应客户请求的时间
    }catch(Exception e){e.printStackTrace();}

    //设置HTTP响应的正文的MIME类型及字符编码
    response.setContentType("text/html;charset=GBK");

    /*输出HTML文档*/
    PrintWriter out = response.getWriter();
    out.println("<html><head><title>HelloServlet</TITLE></head>");
    out.println("<body>");
    out.println("你好: "+username);
    out.println("</body></html>");

    out.close(); //关闭PrintWriter
    }
    }

    在以上程序中,通过两个浏览器同时访问该Web应用

    浏览器1: http://localhost:8080/helloapp/hello1?username=老鼠

    浏览器2: http://localhost:8080/helloapp/hello1?username=小鸭

    可能两个浏览器得到的结果都是:

    你好:小鸭

    这是由于并发问题导致的。

     

    解决方案:将username的定义放到service方法中,这样不同浏览器请求web服务的时候会有不同的username变量

     

    8.使用Java同步机制对多线程同步

     

  • 相关阅读:
    Oracle经典教程学习笔记
    SQL server触发器、存储过程操作远程数据库插入数据,解决服务器已存在的问题
    sublime text3编译C/C++系统提示丢失zlib1.dll解决的方法
    上机题目(0基础)- 数据库事务(Java)
    SGU
    iOS
    iOS刷新某个cell时候crash
    nginx+tomcat反复请求
    加密学教程(Cryptography Tuturials)文件夹
    C/C++与Matlab混合编程初探
  • 原文地址:https://www.cnblogs.com/foodie-nils/p/14883930.html
Copyright © 2011-2022 走看看