在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

案例:获取当前工程的资源

得到web目录下的某个图片资源在浏览器上显示出来

方法

在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

案例:读取Web目录下的资源文件

步骤

  1. 得到上下文对象
  2. 通过上下文对象的方法读取web/WEB-INF/图片文件,转成一个输入流
  3. 得到响应的字节输出流response.getOutputStream()
  4. 将输入流中数据复制到输出流中
  5. 关闭流

执行效果

在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

代码

package com.itheima.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

@WebServlet(name = "Demo2Servlet", urlPatterns = "/demo2")
public class Demo2Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 得到上下文对象
        ServletContext application = getServletContext();
        //2. 通过上下文对象的方法读取web/WEB-INF/图片文件,转成一个输入流
        InputStream in = application.getResourceAsStream("/WEB-INF/cart504.jpg");
        //3. 得到响应的字节输出流response.getOutputStream()
        OutputStream out = response.getOutputStream();
        //4. 将输入流中数据复制到输出流中
        int len = 0;
        byte[] buf = new byte[1024];
        while((len=in.read(buf))!=-1) {
            out.write(buf,0,len);
        }
        //5. 关闭流
        in.close();
        out.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

改进代码

package com.itheima.servlet;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

@WebServlet(name = "Demo2Servlet", urlPatterns = "/demo2")
public class Demo2Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 得到上下文对象
        ServletContext application = getServletContext();
        //2. 通过上下文对象的方法读取web/WEB-INF/图片文件,转成一个输入流
        InputStream in = application.getResourceAsStream("/WEB-INF/girl.jpg");
        //3. 得到响应的字节输出流response.getOutputStream()
        OutputStream out = response.getOutputStream();
        //4. 将输入流中数据复制到输出流中
        /*int len = 0;
        byte[] buf = new byte[1024];
        while((len=in.read(buf))!=-1) {
            out.write(buf,0,len);
        }*/
        //直接将输入流复制到输出流
        IOUtils.copy(in,out);
        //5. 关闭流
        in.close();
        out.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

小结

ServletContext的方法 功能
InputStream getResourceAsStream(String path) 得到web目录下资源,转成输入流

案例:获取资源在服务器的真实地址

使用上下文对象得到web资源真实的地址

方法

在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

步骤

  1. 得到上下文对象
  2. 通过getRealPath()得到资源部署到服务器上的真实地址,注:不是开发的地址
  3. 打印到浏览器上

代码

package com.itheima.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 得到服务器的真实地址
 */
@WebServlet(name = "Demo3Servlet", urlPatterns = "/demo3")
public class Demo3Servlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        //得到上下文对象
        ServletContext application = getServletContext();
        //得到资源的真实地址
        String realPath = application.getRealPath("/WEB-INF/girl.jpg");
        out.print("资源的真实地址是:" + realPath);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

执行结果

在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

小结

ServletContext的方法 功能
String getRealPath(String path) 得到资源在服务器的真实地址

综合案例:得到第几个登录的用户

使用上下文作用域对象实现当前是第几个登录的用户

上下文域

作用域的功能:用于不同的Servlet之间,或不同的用户之间进行数据共享。
在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

上下文域的作用范围

回顾请求域:一个请求结束,数据就丢失

​ 只要web服务器没有关闭,这个域中的值就一直存在,所有的用户都可以访问。如果有成员变量,会有线程安全的问题。

案例:得到当前是第几个登录的用户

分析

在浏览器上实现下载文件(利用ServletContext的方法实现的功能)
流程
在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

步骤

  1. 在init方法中得到上下文对象
  2. 创建count=0,并且将值放入上下文域中.
  3. 登录方法中得到用户名和密码
  4. 判断用户名和密码是否正确
  5. 如果正确,得到上下文对象
  6. 从上下文域中取出count
  7. 加1再更新上下文域
  8. 重定向到另一个Servlet
  9. 否则跳转到登录页面

代码

HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>用户登录</title>
</head>
<body>
<h2>用户登录</h2>
<form action="login" method="post">
    <table>
        <tr>
            <td>用户名</td>
            <td><input type="text" name="username"/></td>
        </tr>
        <tr>
            <td>密码</td>
            <td><input type="password" name="password"/></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" value="登录"/></td>
        </tr>
    </table>
</form>
</body>
</html>
登录的Servlet
package com.itheima.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/*
1. 实现登录
2. 登录成功,从上下文域中取出count,并加1,并且更新上下文域
 */
@WebServlet(name = "LoginServlet", urlPatterns = "/login")
public class LoginServlet extends HttpServlet {

    //向上下文域中添加一个count=0
    @Override
    public void init() throws ServletException {
        //得到上下文域
        ServletContext application = getServletContext();
        application.setAttribute("count", 0);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //实现登录
        //得到用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        //判断是否登录成功
        if ("newboy".equals(username) && "123".equals(password)) {
            //登录成功,从上下文域中取出count,并且加1以后再更新
            //得到上下文域
            ServletContext application = getServletContext();
            int count = (int) application.getAttribute("count");
            //加1以后再更新
            application.setAttribute("count", ++count);
            //重定向到count这个servlet中
            response.sendRedirect("count");
        }
        else {
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.print("<h2>登录失败</h2>");
            out.print("<a href='index.html'>请重试</a>");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
显示人数的Servlet
package com.itheima.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/*
显示第几个登录的用户
 */
@WebServlet(name = "CountServlet", urlPatterns = "/count")
public class CountServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("<h2>欢迎您,登录成功,您是第" + getServletContext().getAttribute("count") + "个用户</h2>");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

小结

ServletContext的方法 作用
Object getAttribute(“键”) 从上下文域中取出值
void setAttribute(“键”,Object 数据) 向上下文域中添加键和值
void removeAttribute(“键”) 删除键和值

一个Web项目有一个上下文对象,Web服务器启动的时候创建,Web服务器关闭的时候销毁。

案例:使用附件的方式下载文件

实现不同类型的文件下载

页面效果

在浏览器上实现下载文件(利用ServletContext的方法实现的功能)

下载页面

<!DOCTYPE html>
<html>
  <head>
    <title>资源下载列表</title>
    <meta charset="utf-8">
  </head>
  
  <body>
   <h2>文件下载页面列表</h2>
   <h3>超链接的下载</h3>
   <a href="download/file.txt">文本文件</a><br/>
   <a href="download/file.jpg">图片文件</a><br/>
   <a href="download/file.zip">压缩文件</a><br/>
   <hr/>
   <h3>手动编码的下载方式</h3>
   <!-- 注:down这里是下载的Servlet的访问地址 -->
   <a href="down?filename=file.txt">文本文件</a><br/>
   <a href="down?filename=file.jpg">图片文件</a><br/>
   <a href="down?filename=file.zip">压缩文件</a><br/>
   <a href="down?filename=美女.jpg">美女</a><br/>
  </body>
</html>

使用超链接下载的不足:

  1. 文本文件,图片文件是直接在浏览器上打开的,而不是下载。
  2. 暴露了资源的真实地址,可能会被其它网站盗链资源。
  3. 不利于业务逻辑的代码控制,如:下载前需要扣积分,必须是会员才可以下载等。

下载设置的响应头

设置响应头 参数说明
Content-Disposition: attachment; filename=文件名 Content-Disposition:
attachment:
filename:

步骤

  1. 从链接上得到文件名
  2. 设置content-disposition头
  3. 得到文件的输入流
  4. 得到response的输出流
  5. 写出到浏览器端

下载的Servlet

package com.itheima.servlet;

import org.apache.commons.io.IOUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

/**
 下载的Servlet
 */
@WebServlet(name = "Demo4DownloadServlet", urlPatterns = "/down")
public class Demo4DownloadServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //得到要下载的文件名
        String filename = request.getParameter("filename");
        System.out.println(filename);  //get没有乱码
        //设置响应头,下载文件。汉字需要URL编码
        response.setHeader("content-disposition","attachment;filename=" + URLEncoder.encode(filename,"utf-8"));
        //得到上下文对象
        ServletContext application = getServletContext();
        //得到资源的输入流
        InputStream in = application.getResourceAsStream("/download/" + filename);
        //得到浏览器的输出流
        OutputStream out = response.getOutputStream();
        //使用io工具类复制输入输出流
        IOUtils.copy(in,out);
        in.close();
        out.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}