Request & Response

Request

Request基础

# Request对象 和 Response对象的原理
  1)request 和 response 对象是由服务器创建
  2)request对象是来获取请求消息的,response对象是来设置响应消息的

# Request对象继承体系结构
  ServletRequest       -- 接口
    | 
  HttpServletRequest   -- 接口
    |
  org.apache.catalina.connector.RequestFacade   -- 类(Tomcat提供)

Request的功能  

# 获取请求消息数据
  * 获取请求行的数据: GET /day14/demo1?name=zhangsan HTTP/1.1
    1)获取请求方式  GETString getMethod()
    2)获取虚拟路径  /day14String getContextPath()
    3)获取资源路径  /demo1String getServletPath()
    4)获取GET方式请求参数  name=zhangsanString getQueryString()
    5)获取请求URI  /day14/demo1
      * String getRequestURI():/day14/demo1
      * StringBuffer getRequestURL():http://localhost/day14/demo1

      * URL:统一资源定位符
      * URI:统一资源标识符
    6)获取协议及版本  HTTP/1.1String getProtocol()
    7)获取客户机的 IP 地址String getRemoteAddr()

package cn.itcast.web.requests;

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("/RequestDemo1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求方式:GET
        String method = req.getMethod();
        System.out.println(method);
        // 获取虚拟目录:/day14
        String contextPath = req.getContextPath();
        System.out.println(contextPath);
        // 获取Servlet路径:/demo1
        String servletPath = req.getServletPath();
        System.out.println(servletPath);
        // 获取get方式请求参数:name=zhangsan
        String queryString = req.getQueryString();
        System.out.println(queryString);
        // 获取请求URI:/day14/demo1
        String requestURI = req.getRequestURI();
        System.out.println(requestURI);
        // 获取请求URL:http://localhost:80/day14/RequestDemo1
        StringBuffer requestURL = req.getRequestURL();
        System.out.println(requestURL);
        // 获取协议及版本:HTTP/1.1
        String protocol = req.getProtocol();
        System.out.println(protocol);
        // 获取客户机的IP地址
        String remoteAddr = req.getRemoteAddr();
        System.out.println(remoteAddr);

    }
}
View Code 

  * 获取请求头数据
    1)通过请求头的名称获取请求头的值(不区分大小写)String getHeader(String name)
    2)获取所有的请求头名称Enumeration<String> getHeaderNames()

package cn.itcast.web.requests;

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.util.Enumeration;

/**
 * 演示 Request 对象获取请求行数据
 */
@WebServlet("/RequestDemo2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取所有请求体的名称
        Enumeration<String> headerNames = req.getHeaderNames();
        // 遍历
        while (headerNames.hasMoreElements()) {
            String s = headerNames.nextElement();
            // 根据名称获取请求头的值
            String header = req.getHeader(s);
            System.out.println(s + "---" + header);
        }

    }
}
View Code 

  * 获取请求体数据
    * 只有 POST 请求才有请求体,在请求体中封装了 POST 请求的参数
    * 步骤:
      1)获取流对象
        * 获取字符输入流,只能操作字符数据:BufferReader getReader()
        * 获取字节输入流,可以操作所有类型的数据:ServletInputStream getInputStream()
      2)再从流对象中获取数据

其他功能

# 获取请求参数的通用方式:不论 GET 还是 POST 请求方式都可以使用下列方法来获取请求参数
  * 根据参数名称获取参数值String getParameter(String name)
  * 根据参数名称获取参数值的数组(可接收checkbox的值)String[ ] getParameterValues(String name)
  * 获取所有请求的参数名称Enumeration<String> getParameterNames()
  * 获取所有参数的 Map 集合Map<String, String[ ]> getParameterMap()

package cn.itcast.web.requests;

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.util.Enumeration;
import java.util.Map;
import java.util.Set;

@WebServlet("/RequestDemo6")
public class RequestDemo5 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取请求参数
        String username = request.getParameter("username");
        System.out.println(username);

        String[] hobbies = request.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }

        Enumeration<String> parameterNames = request.getParameterNames();
        // 遍历枚举
        while (parameterNames.hasMoreElements()) {
            String s = parameterNames.nextElement();
            System.out.println(s + "..." + request.getParameter(s));
        }

        Map<String, String[]> map = request.getParameterMap();
        Set<String> keys = map.keySet();
        for (String key : keys) {
            // 根据键获取值
            System.out.println(key + "..." + map.get(key));
        }
    }

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

  * 中文乱码问题:
    * GET 方式:Tomcat 8 已经将 GET 方式乱码问题解决了
    * POST 方式:会乱码
      * 解决:在获取参数前,设置 Request的编码:request.setCharacterEncoding("utf-8")

# 请求转发:一种在服务器内部的资源跳转方式
  * 步骤
    1)通过 Request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
    2)使用 RequestDispatcher对象进行转发:forword(ServletRequest request, ServletResponse response)
  * 特点
    1)浏览器地址栏路径不发生变化
    2)只能转发到当前服务器内部资源中
    3)转发也被视为一次请求

# 共享数据
  * 域对象:一个有作用范围的对象,可以在范围内共享数据
  * Request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
  * 方法:
    1)存储数据:void setAttribute(String name, Object obj)
    2)通过键获取值:Object getAttribute(String name)
    3)通过键移除键值对:void removeAttribute(String name)

package cn.itcast.web.requests;

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;

@WebServlet("/RequestDemo3")
public class RequestDemo3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo3 被访问了");
        // 存储数据到 request域中
        request.setAttribute("msg","hello");
        request.getRequestDispatcher("/RequestDemo4").forward(request, response);

    }

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

# 获取 ServletContext
  * ServletContext getServletContext() 

案例:用户登录

# 用户登录案例需求
  1)编写 login.html 登录页面:username & password 两个输入框
  2)使用 Druid数据库连接池技术,操作Mysql,day14数据库中的 user表
  3)使用 JDBCTemplate技术封装 JDBC
  4)登陆成功,跳转到 SuccessServlet展示:登录成功!${用户名}$,欢迎您
  5)登录失败,跳转到 FailServlet展示:登陆失败,用户名或密码错误

# 分析

# 开发步骤
  1)创建项目,导入 html页面,配置文件,jar包

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///day14
username=root
password=123
initialSize=5
maxActive=10
maxWait=3000
Druid.xml

  2)创建数据库环境

CREATE DATABASE day14;
USE day14;
CREATE TABLE USER( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(
32) UNIQUE NOT NULL, PASSWORD VARCHAR(32) NOT NULL );

   3)创建包 cn.itcast.domain,创建类 User

package cn.itcast.domain;

/**
 * 用户的实体类
 */
public class User {
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("User{");
        sb.append("id=").append(id);
        sb.append(", username='").append(username).append('\'');
        sb.append(", password='").append(password).append('\'');
        sb.append('}');
        return sb.toString();
    }
}
User

  4)创建包 cn.itcast.util,编写工具类 JDBCUtils

package cn.itcast.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.sql.Statement;

/**
 * JDBCUtils,使用 Druid连接池
 */
public class JDBCUtils {
    // 1、定义成员变量 DataSource
    private static DataSource ds;

    static {
        try {
            Properties pro = new Properties();
            pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接的方法
     */
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    /**
     * 释放资源的方法
     */
    public static void close(Statement stmt, Connection conn) {
        close(null, stmt, conn);
    }

    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取连接池的方法
     */
    public static DataSource getDataSource() {
        return ds;
    }
}
JDBCUtils

  5)创建包 cn.itcast.dao,创建类 UserDao,提供 login() 方法

package cn.itcast.dao;

import cn.itcast.domain.User;
import cn.itcast.util.JDBCUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 * 提供 login的方法
 */
public class UserDao {
    // 声明JDBCTemplate对象来共用
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    /**
     * 登录方法
     */
    public User login(User loginUser) {
        try {
            // 编写 sql
            String sql = "select * from user where username = ? and password = ?";
            // 调用 query方法
            User user = template.queryForObject(sql,
                    new BeanPropertyRowMapper<User>(User.class),
                    loginUser.getUsername(), loginUser.getPassword());

            return user;
        } catch (DataAccessException e) {
            e.printStackTrace();
            return null;
        }
    }
}
UserDao

  6)创建包 cn.itcast.web.servlet包,创建类 LoginServlet()

package cn.itcast.servlet;

import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import org.apache.commons.beanutils.BeanUtils;


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.lang.reflect.InvocationTargetException;
import java.util.Map;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置编码
        req.setCharacterEncoding("utf-8");

        /*// 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 封装user对象
        User loginUser = new User();
        loginUser.setUsername(username);
        loginUser.setPassword(password);*/

        // 获取所有请求参数
        Map<String, String[]> map = req.getParameterMap();
        // 创建 User对象
        User loginUser = new User();
        try {
            BeanUtils.populate(loginUser,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        // 调用 UserDao的login方法
        UserDao dao = new UserDao();
        User user = dao.login(loginUser);

        if (user == null) {
            // 登录失败
            req.getRequestDispatcher("/failServlet").forward(req,resp);
        } else {
            // 登录成功
            // 存储数据
            req.setAttribute("user",user);
            // 转发
            req.getRequestDispatcher("/successServlet").forward(req,resp);
        }

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
LoginServlet

  7)在 servlet包下,编写 FailServlet类和SuccessServlet类

package cn.itcast.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;

@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 给页面写一句话

        // 设置页面的编码
        response.setContentType("text/html;charset=utf-8");

        // 输出
        response.getWriter().write("登录失败,用户名或密码错误");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
FailServlet
package cn.itcast.servlet;

import cn.itcast.domain.User;

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;

@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 设置页面的编码
        response.setContentType("text/html;charset=utf-8");
        // 获取request域中共享的user对象
        User user = (User) request.getAttribute("user");
        // 输出
        response.getWriter().write("登录成功," + user.getUsername() + "欢迎您");
    }

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

  8)login.html 中 form表单的action路径写法:
    * 虚拟目录 + 资源名称
  9)BeanUtils工具类,简化数据封装,(org.apache.commons.beanutils.BeanUtils)
    * 用于封装 JavaBean的
    ①:JavaBean:标准的Java类
      * 要求
        1、类必须被 public 修饰
        2、必须提供空参的构造器
        3、成员变量必须使用 private 修饰
        4、提供公共的 setter 和 getter 方法
      * 功能:封装数据
    ②:属性的概念
      * setter 和 getter 方法名截取后的产物
      * 例如:getUsername() --> Username --> username
    ③:方法:
      1、setProperty(Object obj, String name, Object value):设置属性值
      2、getProperty(Object obj, String name):获取属性值
      3、populate(Object obj, Map map):将 Map 集合的键值对信息封装到对应的 JavaBean对象中

package cn.itcast.test;

import cn.itcast.domain.User;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;

public class BeanUtilsTest {

    @Test
    public void test() {
        User user = new User();
        try {
            BeanUtils.setProperty(user, "username", "zhangsan");
            System.out.println(user);

            String password = BeanUtils.getProperty(user, "password");
            System.out.println(password);

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }
}
BeanUtils 

Response

设置响应消息

# 设置响应行
  * 格式:HTTP/1.1 200 ok
  * 设置状态码:setStatus(int sc)

# 设置响应头setHeader(String name, String value)

# 设置响应体:
  1)获取输出流
    * 字符输出流:PrintWriter getWriter()
    * 字节输出流:ServletOutputStream getOutputStream()
  2)使用输出流,将数据输出到客户端浏览器

案例

# 完成重定向
  * 重定向:资源跳转的方式
  * 重定向的特点redirect
    1)地址栏发生变化
    2)重定向可以访问其他站点(服务器)的资源
    3)重定向是两次请求,不能使用 Request对象来共享数据
  * 转发的特点:forward
    1)转发地址栏路径不变
    2)转发只能访问当前服务器下的资源
    3)转发只有一次请求,可以使用 Request对象来共享数据

package cn.itcast.web.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;

@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo1...");
        // 访问 /responseDemo1,会自动跳转到 /responseDemo2资源

        /*// 设置状态码为302
        resp.setStatus(302);
        // 设置响应头location
        resp.setHeader("location", "/day15/responseDemo2");*/

        // 简单的重定向方法
        resp.sendRedirect("/day15/responseDemo2");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}
View Code

  * 路径写法
    1)路径分类:
      * 相对路径:通过相对路径不可以缺点唯一资源
        * 如:./index.html
        *确定当前资源和目标资源之间的相对位置关系
          * ./ :当前目录
          * ../ :后退一级目录

      * 绝对路径:用过路径可以确定唯一的资源
        * 如:http://localhost/day15/responseDemo2

    2) 资源访问路径判断定义的路径是给谁用的,判断请求将来从哪里发出
      * 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
        * 建议虚拟目录动态获取:requset.getContextPath()
        * <a>,<form>,重定向
      * 给服务器使用:不需要加虚拟目录
        * 转发

# 服务器输出字符数据到浏览器
  * 步骤:
    1)获取字符输出流
    2)输出数据
  * 乱码问题
    1)PrintWriter response.getWriter(),从 Tomcat 获取的流的默认编码是 ISO-8859-1
    2)设置该流的编码
      * response.setCharacterEncoding("utf-8")

    3)告诉浏览器响应体使用的编码
      * response.setContentType("text/html;charset=utf-8") 

package cn.itcast.web.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("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 在获取流对象之前,设置编码方式,原来是 ISO-8859-1
        resp.setCharacterEncoding("utf-8");
        // 告诉浏览器,服务器发送的消息的编码方式
        // resp.setHeader("content-type","text/html;charset=utf-8");
        resp.setContentType("text/html;charset=utf-8");

        // 获取字符输出流
        PrintWriter writer = resp.getWriter();
        // 输出数据
        writer.write("<h1>hello response</h1>");
        writer.write("<h1>你好啊啊啊 response</h1>");

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}
View Code 

# 验证码
  * 本质:图片
  * 目的:防止恶意表单注册

package cn.itcast.web.servlet;

import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 创建对象,在内存中代表图片(验证码图片对象)
        int width = 100;
        int height = 50;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 美化图片
        // 填充背景色
        Graphics g = image.getGraphics(); // 设置画笔对象
        g.setColor(Color.cyan); // 设置画笔颜色
        g.fillRect(0, 0, width, height);
        // 画边框
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, width - 1, height - 1);

        // 生成验证码
        String str = "ABCEEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyz0123456789";
        // 生成随机角标
        Random ran = new Random();

        for (int i = 1; i <= 4; i++) {
            int index = ran.nextInt(str.length());
            //获取字符
            char ch = str.charAt(index);

            // 写验证码
            g.drawString(ch + "", width / 5 * i, height / 2);

        }
        // 画干扰线
        g.setColor(Color.green);
        // 随机生成坐标点
        for (int i = 0; i < 10; i++) {
            int x1 = ran.nextInt(width);
            int x2 = ran.nextInt(width);
            int y1 = ran.nextInt(height);
            int y2 = ran.nextInt(height);
            g.drawLine(x1, y1, x2, y2);
        }

        // 将图片输出到页面展示
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }
}
CheckCodeServlet
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img id="checkCode" src="/day15/checkCodeServlet">
<a id="change" href="javascript:void(0)">看不清,换一张?</a>


<script>
    /*
    分析:
        点击超链接或者图片需要换一张图片
            1、给超链接和图片绑定单机事件
            2、重新设置图片的src属性值
    */
    window.onload = function (ev) {
        var img = document.getElementById("checkCode");
        img.onclick = function (ev1) {
            var date = new Date().getTime();
            img.src = "/day15/checkCodeServlet?" + date;
        };

        var link = document.getElementById("change");
        link.onclick = function (ev1) {
            var date = new Date().getTime();
            img.src = "/day15/checkCodeServlet?" + date;
        };

    }
</script>
</body>
</html>
验证码切换 

ServletContext对象

# 概念代表整个 web 应用,可以和程序的容器(服务器)来通信

# 获取不同的方法获取的是同一个对象):
  * 用过 Request对象来获取:request.getServletContext()
  * 通过 HttpServlet获取:this.getServletContext()

# 功能
  * 获取 MIME类型
    * MIME类型:在互联网通信过程中定义的一种文件数据类型
    * 格式:大类型/小类型  如:text/html  image/jpeg
    * 获取一个文件的MIME类型:String getMimeType(String file)

package cn.itcast.web.servletContext;

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;

@WebServlet("/ServletContextDemo2")
public class ServletContextDemo2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取ServletContext
        ServletContext context = this.getServletContext();
        // 定义文件名称
        String filename = "a.jpg";
        // 获取MIME类型
        String mimeType = context.getMimeType(filename);
        System.out.println(mimeType);
    }

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

  * 域对象:共享数据
    * setAttribute(String name, Object value)
    * getAttribute(String name)
    * removeAttribute(String name)
    * ServletContext对象的范围:所有用户和所有请求的数据,因此使用需谨慎

  * 获取文件的真实路径(服务器路径)
    * 方法:String getRealPath(String path)

案例

# 文件下载需求
  1)页面显示超链接
  2)点击超链接后弹出下载提示框
  3)完成图片文件下载

# 分析
  1)超链接标签指向的资源如果能够被浏览器解析,则在浏览器中展示,不满足需求
  2)任何资源都必须弹出下载提示框
  3)使用响应头设置资源的打开方式:content-disposition:attachment;filename=xxx

# 步骤
  1)定义页面,编辑超链接 href 属性,指向 Servlet,传递资源名称 filename

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>download</title>
</head>
<body>
<a href="/day15/DownloadServlet?filename=1.jpg">图片1</a>

</body>
</html>
download.html

  2)定义Servlet
    ① 获取文件名称
    ② 使用字节输入流加载文件进内存
    ③ 指定 response 的响应头:content-disposition:attachment;filename=xxx
    ④ 将数据写出到 response输出流中

package cn.itcast.web.download;

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.FileInputStream;
import java.io.IOException;

@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数
        req.setCharacterEncoding("utf-8");
        String filename = req.getParameter("filename");

        // 找到文件的服务器路径
        ServletContext context = this.getServletContext();
        String realPath = context.getRealPath("/img/" + filename);
        System.out.println(realPath);

        // 设置response的响应头
        String mimeType = context.getMimeType(filename);
        resp.setContentType(mimeType);
        resp.setHeader("content-disposition", "attachment;filename=" + filename);

        // 将输入流的数据写出到输出流中
        FileInputStream fis = new FileInputStream(realPath);
        ServletOutputStream sos = resp.getOutputStream();
        byte[] buff = new byte[1024 * 8];
        int len = 0;
        while ((len = fis.read(buff)) != -1) {
            sos.write(buff, 0, len);
        }
        
        fis.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}
View Code 

# 问题
  * 中文文件名乱码
  * 解决:
    ① 获取客户端使用的浏览器版本信息
    ② 根据不同的版本信息,设置 filename 的编码方式

package cn.itcast.utils;

import sun.misc.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


public class DownLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}
View Code 

    

posted @ 2020-08-29 16:28  小么VinVin  阅读(179)  评论(0编辑  收藏  举报