4/17day35_servletContext_respons

2020-04-24  本文已影响0人  蹦蹦跶跶的起床啊

回顾

1. request作用
        开发人员可以通过request对象,获取http协议请求消息

2. request获取Http请求信息
    请求行
        1.请求方式:getMethod()
        2.虚拟路径:getContextPath()
    请求头
        getHeader(String name); -- 不区分大小写
        referer:防盗链
        user-agent:浏览器兼容性
    请求参数(体)
        String getParameter(String name);
        String[] getParameterValues(String name);
        Map getParameterMap(); 结合BeanUtils实现参数快速封装...

3. 请求转发
    服务器内部资源的一种跳转方式

4. 域对象(共享数据)
    何时创建?
        用户发送请求
    何时销毁?
        服务器做出响应
    作用范围?
        一次请求,多次转发

5. 案例:用户登录
    接收请求参数
    请求转发
    域对象

ServletContext&Response

今日目标

1. ServletContext:应用上下文对象

2. response【重点】

3. 综合案例
    

一 ServletContext

1.1 概述

主要作用

  1. 域对象(共享数据)
  2. 获取资源在服务器的真实地址
  3. 获取全局的配置参数
  4. 获取文件MIME类型

获取ServletContext对象

1. 通过request对象获得
        ServletContext sc = request.getServletContext();
        
2. 继承HttpServlet后,可以直接调用
        ServletContext sc = getServletContext();

1.2 域对象(共享数据)

1. 存储数据
        void setAttribute(String name,Object value)
2. 获取数据
        Object getAttribute(String name)
3. 删除数据
        void removeAttribute(String name)
@WebServlet("/OneServlet")
public class OneServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 向servletContext域存数据....
        ServletContext sc1 = request.getServletContext();
        ServletContext sc2 = getServletContext();
        sc1.setAttribute("user", "jack");
        System.out.println("OneServlet存了数据。。。");
    }

}
@WebServlet("/TwoServlet")
public class TwoServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 从servletContext域获取数据
        String user = (String) request.getServletContext().getAttribute("user");
        System.out.println("TwoServlet获取数据:"+user);
    }

}

生命周期

1. 何时创建?
        项目加载时,创建
        
2. 何时销毁?
        项目卸载时,销毁

3. 作用范围?
        与项目共存亡(多个servlet都可以操作它)

1.3 获取资源在服务器的真实地址

* API
        String getRealPath(String path);
@WebServlet("/RealpathServlet")
public class RealpathServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取car.jpg 文件真实路径
        String carPath = request.getServletContext().getRealPath("/img/car.jpg");
        System.out.println(carPath);
        // 获取web.xml 文件真实路径
        String webPath = request.getServletContext().getRealPath("/WEB-INF/web.xml");
        System.out.println(webPath);
    }

}

1.4 获取全局的配置参数

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <!--全局配置参数:所有的servlet都可以读取...-->
    <context-param>
        <param-name>encode</param-name>
        <param-value>UTF-8</param-value>
    </context-param>
</web-app>
@WebServlet("/ContextPathServlet")
public class ContextPathServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取全局参数
        String value = request.getServletContext().getInitParameter("encode");
        System.out.println("全局配置参数:"+value);
    }

}

1.5 获取文件MIME类型

<a href="/day10_servletContext/MimeServlet?filename=luola.avi">获取文件的mime类型</a><br>
@WebServlet("/MimeServlet")
public class MimeServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取指定文件的mime类型
        // 获取请求参数
        String filename = request.getParameter("filename");
        // 获取文件的mime类型
        String mimeType = request.getServletContext().getMimeType(filename);
        response.getWriter().write(filename + "---" + mimeType);
    }

}

1.6 案例:统计网站的访问次数

需求

一般个人博客的首页,都会显示你是第几位访问此网站...

@WebServlet(value = "/CountServlet", loadOnStartup = 4) // 服务器启动时,创建此servlet对象
public class CountServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        getServletContext().setAttribute("count", 0);
    }

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置response响应编码
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("<h1>itcast博客网站</h1>");

        // 用户每次访问,从域中取出,加1,再存进去
        ServletContext servletContext = request.getServletContext();
        // 从域中取出
        Integer count = (Integer) servletContext.getAttribute("count");
        // 加1
        count++;
        // 再存进去
        servletContext.setAttribute("count", count);

        response.getWriter().write("<div>你是,第" + count + "位访问此网站...</div>");
    }

}

二 Response【重点】

2.1 概述

Response体系结构

    ServletResponse 接口
            |   
    HttpServletResponse 接口
            |   
    org.apache.catalina.connector.ResponseFacade 实现类(由tomcat提供的)

2.2 设置Http响应消息

响应行

* 格式
        协议/版本号 状态码
     
* 例如
        HTTP/1.1 200
        
* API
    1. 设置状态码
            void setStatus(int sc)          

响应头

* 格式
        响应头名称:响应头的值
        
* 例如
        Location:http://www.itcast.cn
        
* API
    1. 设置指定头名称和对应的值
            void setHeader(String name, String value)  

响应体【重点】

* API(输出流对象)
    1. 字符输出流
            PrintWriter getWriter()
    
    2. 字节输出流
            ServletOutputStream getOutputStream()
            
    注意:在同一个servlet中,二种类型的输出流不能同时存在,互斥

2.3 响应重定向

需求

用户访问AServlet后,服务器告诉浏览器重定向到BServlet

步骤分析

* 方式一
    // 1.设置状态码
        response.setStatus(302);
    // 2.设置响应头 Location
        response.setHeader("Location","重定向网络地址");
        
        
* 方式二
    // 1.response这哥们封装专门处理重定向的方法
        response.sendRedirect("重定向网络地址");

重定向特点

1. 地址栏会发生改变

2. 重定向是二次请求

3. 重定向是客户端(浏览器)行为,可以跳转到服务器外部资源...

4. 不能使用request域共享数据
@WebServlet("/AServlet")
public class AServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("AServlet执行了....");
       /* // 1.设置状态码
        response.setStatus(302);
        // 2.设置响应头 Location
        response.setHeader("Location","/day10_response/BServlet");*/

        // 1.response这哥们封装专门处理重定向的方法
        response.sendRedirect("http://www.itcast.cn");
    }

}
@WebServlet("/BServlet")
public class BServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("BServlet执行了....");
    }

}

转发与重定向的区别

1. 哪个对象
    转发(request对象的方法)        
        request.getRequestDispatcher("/bServlet").forward(request,response);
    重定向(response对象的方法)      
        response.sendRedirect("/day10_response/bServlet");
        
2. 几次请求
    转发
        地址栏: 没有改变
        浏览器: 发了一次请求
        服务器: 只有一对请求和响应对象
        发生的位置: 服务器
    重定向
        地址栏: 发生了改变
        浏览器: 发了两次请求
        服务器: 有两对请求和响应对象
        发生的位置: 浏览器
            
3. 小结
    写法 
        转发("/servlet资源路径") 服务器内部行为
        重定向 ("/虚拟路径(项目名)/servlet资源路径") 浏览器外部行为
    使用场景(重点掌握) 
        如果需要传递数据(request域),使用转发
        如果不需要传递数据(request域),使用重定向

2.4 响应定时刷新

需求

在当前页面停留3秒钟之后,跳转到传智播客首页

步骤分析

1. 通过response设置响应头 Refresh
        response.setHeader("Refresh","间隔时间(秒);跳转页面");
@WebServlet("/RefreshServlet")
public class RefreshServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 通过response设置响应头 Refresh
        response.setHeader("Refresh", "3;http://www.itcast.cn");
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write("操作成功,3秒后跳转到传智首页...");
    }

}

2.5 响应中文【重中之重】

需求

向页面输出中文数据没有乱码

步骤分析

1. 通过response获取字符输出流
        PrintWriter pw = response.getWriter();
        
2. 通过字符输出输出文本
        pw.write("中文....");

解决中文乱码

1. 指定服务器响应编码方式
        response.setCharacterEncoding("GBK");
        
2. 统一浏览器和服务器编码
        response.setContentType("text/html;charset=utf-8"); 
@WebServlet("/EncodeServlet")
public class EncodeServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //  指定服务器响应编码方式
        // response.setCharacterEncoding("UTF-8");
        // 统一浏览器和服务器编码
        response.setContentType("text/html;charset=utf-8");

        // 1. 通过response获取字符输出流
        PrintWriter pw = response.getWriter();
        // 2. 通过字符输出输出文本
        pw.write("中文....");
    }

}

三 综合案例【作业】

3.1 点击切换验证码

需求

在页面展示登录验证码,点击此验证码可以更换新的验证码

作用:防止表单的恶意提交

本质上:就是一张随机图片

如何通过java代码制作一个验证码

在今天的资料中,准备了验证码制作Servlet工具类

/*
    跟我一起了解一下验证码的制作代码....
 */
@WebServlet("/CheckcodeServlet")
public class CheckcodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //  创建画布
        int width = 120;
        int height = 40;
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //  获得画笔
        Graphics g = bufferedImage.getGraphics();
        //  填充背景颜色
        g.setColor(Color.white);
        g.fillRect(0, 0, width, height);
        //  绘制边框
        g.setColor(Color.red);
        g.drawRect(0, 0, width - 1, height - 1);
        //  生成随机字符
        //  准备数据
        String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        //  准备随机对象
        Random r = new Random();
        //  声明一个变量 保存验证码
        String code = "";
        //  书写4个随机字符
        for (int i = 0; i < 4; i++) {
            //  设置字体
            g.setFont(new Font("宋体", Font.BOLD, 28));
            //  设置随机颜色
            g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));

            String str = data.charAt(r.nextInt(data.length())) + "";
            g.drawString(str, 10 + i * 28, 30);

            //  将新的字符 保存到验证码中
            code = code + str;
        }
        //  绘制干扰线
        for (int i = 0; i < 6; i++) {
            //  设置随机颜色
            g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));

            g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
        }

        //  将验证码 打印到控制台
        System.out.println(code);

        //  将验证码放到session中
        request.getSession().setAttribute("code_session", code);

        //  将画布显示在浏览器中
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
    }

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

}
<img src="/day10_response/CheckcodeServlet" alt="servlet随机验证码" id="img1"> <br>
<script>
    // 给图片绑定一个点击事件
    document.getElementById('img1').onclick=function () {
        // 重置src路径,重写发送请求
        this.src='/day10_response/CheckcodeServlet?'+new Date().getTime(); // 后面加一个毫秒值的时间戳,欺骗浏览器
    }
</script>

3.2 文件下载

需求

用户点击页面的链接,浏览器开始下载文件。

3.2.1 使用链接下载文件

① 将资料中的下载素材复制到web项目中

② 编写下载页面

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>donload.html</title>

</head>
<body>
<h3>文件下载</h3>
<h5>超链接下载</h5>
<a href="/day10_response/download/demo.docx">word文档</a><br>
<a href="/day10_response/download/car.jpg">图片下载</a><br>
<a href="/day10_response/download/test.zip">压缩包下载</a><br>
<h5>servlet下载</h5>
</body>
</html>

③ 缺点

  1. 浏览器可识别的媒体类型,是直接打开而不是下载...
  2. 不能判断用户是否登录(vip),进行限制

3.2.2 使用Servlet下载文件【推荐....】

1. 被下载文件的字节输入流
        FileInputStream
        
2. response字节输出流
        ServletOutputStream
        
3. 告知客户端下载文件的MIME类型(最新的浏览器此步骤可以省略....)
        Content-Type:MIME类型
        
4. 告知浏览器以附件的方式保存
        Content-Disposition:attachment;filename=文件名
            attachment 附件
            filename=文件名

需求分析

① download.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>donload.html</title>

</head>
<body>
<h3>文件下载</h3>
<h5>超链接下载</h5>
<a href="/day10_response/download/demo.docx">word文档</a><br>
<a href="/day10_response/download/car.jpg">图片下载</a><br>
<a href="/day10_response/download/test.zip">压缩包下载</a><br>
<h5>servlet下载</h5>
<a href="/day10_response/DownLoadServlet?filename=demo.docx">word文档</a><br>
<a href="/day10_response/DownLoadServlet?filename=girl.jpg">靓女</a><br>
<a href="/day10_response/DownLoadServlet?filename=禽兽.jpg">禽兽</a><br>
</body>
</html>

② DownLoadServlet

@WebServlet("/DownLoadServlet")
public class DownLoadServlet extends HttpServlet {

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

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.获取请求文件名
        String filename = request.getParameter("filename");
        // 2.获取文件真实路径,封装到字节输入流
        ServletContext servletContext = request.getServletContext();
        String realPath = servletContext.getRealPath("/download/" + filename);
        FileInputStream in = new FileInputStream(realPath);
        // 3.告诉浏览器mime类型
        String mimeType = servletContext.getMimeType(filename);
        response.setContentType(mimeType);

        // 4.告诉浏览器以附件方式保存
        // 解决中文乱码和浏览器兼容性
        String userAgent = request.getHeader("user-agent");
        // 调用工具类处理
        filename = DownLoadUtils.getName(userAgent, filename);

        response.setHeader("content-disposition", "attachment;filename=" + filename);

        // 5.获取字节输出流
        ServletOutputStream out = response.getOutputStream();

        // 6.io流的拷贝
        byte[] b = new byte[4096];// 4kb
        int len = -1;
        while((len = in.read(b))!=-1){
            out.write(b, 0, len);
        }

        // 7.释放资源
        out.close(); // out流对象,可以交给tomcat关闭
        in.close();
    }

}

③ 中文乱码

* 如果该下载文件名是中文的话,会出现乱码...
    谷歌和绝大多数的浏览器是通过 url编码
        URLEncode() 编码
        URLDecode() 解码
    火狐浏览器   base64编码
    
* 我们就需要考虑浏览器兼容性问题....
    今天帅哥提供了判断浏览器不同编码的工具类直接使用即可....

④ hutool工具包.....

官网:https://www.hutool.cn/

老师已经帮助大家下载了....

老师下午总结

疑惑点

  1. 找资源文件的方式

    • 如果我们查找web目录下的资源,我们使用ServletContext去查找。

      package com.itheima.response;
      
      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.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      
      @WebServlet("/demo1")
      public class Demo1Servlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              //1. 找到目标文件(如果是web目录下的资源,我们都使用ServletContext去查找)
              // getRealPath("/") 获取资源的绝对路径
              //getResourceAsStream("/路径")  返回资源的输入流
              InputStream inputStream = request.getServletContext().getResourceAsStream("/img/5.jpg");
      
      
              //2. 获取response的输出流
              ServletOutputStream outputStream = response.getOutputStream();
      
              //3. 边读取目标文件的数据,边输出
              byte[] buf = new byte[1024];
              int length = 0 ;
      
              while((length = inputStream.read(buf))!=-1){
                  outputStream.write(buf,0,length);
              }
      
              inputStream.close();
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      
  - **如果我们查找是src下面的内容,我们使用类路径去查找。**

    ```java
    package com.itheima.response;
    
    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.PrintWriter;
    import java.util.Properties;
    
    @WebServlet("/demo2")
    public class Demo2Servlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           response.setContentType("text/html;charset=utf-8");
            //如果需要读取src下面的内容,我们使用类路径
            //注意:如果需要使用类路径,一定要使用Class对象的getResourceAsStream的方法。
            //类路径: 查找类路径
            InputStream inputStream = Demo2Servlet.class.getResourceAsStream("/db.properties");//这个/则代表了classes目录
            //加载到ProPerties中
            Properties properties = new Properties();
            properties.load(inputStream);
    
            //输出到浏览器
            PrintWriter out = response.getWriter();
            out.write("用户名:"+ properties.getProperty("username")+"<br/>");
            out.write("密码:"+ properties.getProperty("password"));
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }
    
    ```
  1. 请求转发与请求重定向的区别

    回顾请求转发原理图

    package com.itheima.forward;
    
    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;
    
    //往request域中存储数据
    @WebServlet("/demo3")
    public class Demo3Servlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //往request域中存储数据
            request.setAttribute("name","gouwa");
            //请求转发到Demo4
            request.getRequestDispatcher("/demo4").forward(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }
    
    
    
    package com.itheima.forward;
    
    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;
    
    //从request域中获取数据
    @WebServlet("/demo4")
    public class Demo4Servlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //解决向浏览器输出中文乱码问题
            response.setContentType("text/html;charset=utf-8");
            //从request域中取出数据
            String name = (String) request.getAttribute("name");
            //向浏览器输出
            response.getWriter().write("从request域中获取到的数据:"+ name);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }
    
    

请求重定向原理图

请求转发与请求重定向的区别:

  1. 请求转发的时候浏览器地址栏不变化的,请求重定向浏览器地址栏是变化的。

  2. 请求转发浏览器发出一次请求,请求重定向浏览器发出了两次请求。

"/"在进行资源跳转的时候,

- 如果是给服务器去使用那么“/”代表了    http://localhost:8080/项目根路径
- 如果/是给浏览器去使用的时候,那么“/”代表了  http://localhost:8080/

今日重点

  1. ServletContext对象

    • ServletContext作为域对象

      • setAttribute()
      • getAttribute()
      • removeAttribute()
    • ServletContext获取当前模块的web目录下的资源(非常重要)

      • getRealPath
      • getResourceAsStream()
  1. Response对象

    • 向浏览器输出
    • getOutputSteam() 获取输出字节流
    • getWrite() 获取输出字符流
    • 向浏览器输出中文数据并且解决乱码问题
      • response.setcontentType("text/html';charset=utf-8")
    • 请求重定向
      • response.sendRedirect()
    • 文件下载请求头
      • response.setHeader(“content-disposition”,"attachement;filename=文件名")


        servletContext&response.png
上一篇下一篇

猜你喜欢

热点阅读