03Request&Response-授课

Request&Response-授课

1. 请求对象

2.1 请求对象介绍

  • 请求:获取资源。在 BS 架构中,就是客户端浏览器向服务器端发出询问,请求获取资源

  • 请求对象:就是在项目当中用于发送请求的对象

  • 我们常用的对象就是ServletRequest和HttpServletRequest,它们的区别就是是否和HTTP协议有关
    在这里插入图片描述

2.2 常用方法介绍

  • 先了解即可,接下来我们会一步一步介绍
    在这里插入图片描述

2.3 请求对象的使用示例

2.3.1 请求对象常用方法1-获取各种路径

  • 获取路径方法
    在这里插入图片描述

    • getQueryString,获取请求的数据,比如url问号后边的数据
    • URI是以一种抽象的,高层次概念定义统一资源标识,而URL则是具体的资源标识的方式
    • URI比URL范围大,URL是URI的一种
    • url?后边的请求参数,也可以叫做查询字符串 (请求动作是查询,把请求参数作为查询关键字)
    • 重点方法:getContextPath,getQueryString,getRequestURI
  • 案例:新建项目request_demo,新建类com.itheima.servlet.ServletDemo01

  • 这里的项目需要是java ee 8 ,我们要用注解注册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;

/*
    获取路径的相关方法
 */
@WebServlet("/servletDemo01")
public class ServletDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取虚拟目录名称 getContextPath()
        String contextPath = req.getContextPath();  ***
        ///getServletContext().getContextPath();
        System.out.println(contextPath);

        //2.获取Servlet映射路径 getServletPath()
        String servletPath = req.getServletPath();
        System.out.println(servletPath);

        //3.获取访问者ip getRemoteAddr()
        String ip = req.getRemoteAddr();
        System.out.println(ip);

        //4.获取请求消息的数据 getQueryString()  url?后边的字符串(查询字符串)
        // xxxurl?keyword=abc (?后边的参数,很多时候都是作为查询条件,keyword=abc叫做查询字符串)
        String queryString = req.getQueryString();
        System.out.println(queryString);

        //5.获取统一资源标识符 getRequestURI()    /request/servletDemo01   共和国
        String requestURI = req.getRequestURI();
        System.out.println(requestURI);

        //6.获取统一资源定位符 getRequestURL()    http://localhost:8080/request/servletDemo01  中华人民共和国
        StringBuffer requestURL = req.getRequestURL();
        System.out.println(requestURL);

    }

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

  • 访问
    在这里插入图片描述

2.3.2 请求对象常用方法2-获取请求头信息

  • 获取请求头
    在这里插入图片描述

    • 有的请求头是有多个值,所以可以通过getHeaders方法获取
    • 比如:accept-encoding,他的值就有多个:gzip,deflate,br
  • 案例:新建ServletDemo02

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

/*
    获取请求头信息的相关方法
 */
@WebServlet("/servletDemo02")
public class ServletDemo02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.根据请求头名称获取一个值
        String connection = req.getHeader("connection");
        System.out.println(connection);
        System.out.println("--------------");

        //2.根据请求头名称获取多个值
        Enumeration<String> values = req.getHeaders("accept-encoding");
        while(values.hasMoreElements()) {
            String value = values.nextElement();
            System.out.println(value);
        }
        System.out.println("--------------");

        //3.获取所有的请求头名称
        Enumeration<String> names = req.getHeaderNames();
        while(names.hasMoreElements()) {
            String name = names.nextElement();
            String value = req.getHeader(name);
            System.out.println(name + "," + value);
        }

    }

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

  • 访问
    在这里插入图片描述

2.3.3 请求对象常用方法3-获取请求参数(非常重要)

1)获取请求参数信息的方法 ***
  • 获取请求头参数
    在这里插入图片描述

    • 如果请求参数只有一个值,通过getParameter获取,比如:text
    • 如果请求参数有多个值,通过getParameterValues获取,比如:checkbox
    • 重点掌握:getParameter,getParameterMap
  • 案例:新建web/register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
    <form action="/request/servletDemo03" method="get" autocomplete="off">
        姓名:<input type="text" name="username"> <br>
        密码:<input type="password" name="password"> <br>
        爱好:<input type="checkbox" name="hobby" value="study">学习
              <input type="checkbox" name="hobby" value="game">游戏 <br>
        <button type="submit">注册</button>
    </form>
</body>
</html>
  • 新建ServletDemo03
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.util.Enumeration;
import java.util.Map;

/*
    获取请求参数信息的相关方法
 */
@WebServlet("/servletDemo03")
public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.根据名称获取数据   getParameter()
        String username = req.getParameter("username");
        System.out.println(username);
        String password = req.getParameter("password");
        System.out.println(password);
        System.out.println("--------------------");

        //2.根据名称获取所有数据 getParameterValues()
        String[] hobbies = req.getParameterValues("hobby");
        for(String hobby : hobbies) {
            System.out.println(hobby);
        }
        System.out.println("--------------------");

        //3.获取所有名称  getParameterNames()
        Enumeration<String> names = req.getParameterNames();
        while(names.hasMoreElements()) {
            String name = names.nextElement();
            System.out.println(name);
        }
        System.out.println("--------------------");

        //4.获取所有参数的键值对 getParameterMap()
        Map<String, String[]> map = req.getParameterMap();
        for(String key : map.keySet()) {
            String[] values = map.get(key);
            System.out.print(key + ":");
            for(String value : values) {
                System.out.print(value + " ");
            }
            System.out.println();
        }
    }

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

  • 访问
    在这里插入图片描述
2)获取参数手动封装对象
  • 我们通过上面的方法可以获取到请求参数,但是如果参数过多,在进行传递时,方法的形参定义将会变得非常难看

  • 此时我们应该用一个对象来描述这些参数,它就是实体类。这种类的定义,从基础阶段我们就开始使用了

  • 在基础阶段,我们做过一个学生管理系统,用到了一个Student的类,它就是用于描述一个学生的实体类

  • 我们现在要做的就是把表单中提交过来的数据填充到实体类中

  • 案例:新建com.itheima.bean.Student

    package com.itheima.bean;
    
    import java.util.Arrays;
    
    public class Student {
        private String username;
        private String password;
        private String[] hobby;
    
        public Student() {
        }
    
        public Student(String username, String password, String[] hobby) {
            this.username = username;
            this.password = password;
            this.hobby = hobby;
        }
    
        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;
        }
    
        public String[] getHobby() {
            return hobby;
        }
    
        public void setHobby(String[] hobby) {
            this.hobby = hobby;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ", hobby=" + Arrays.toString(hobby) +
                    '}';
        }
    }
    
    
  • 新建ServletDemo04

    package com.itheima.servlet;
    
    import com.itheima.bean.Student;
    
    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("/servletDemo04")
    public class ServletDemo04 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.获取所有的数据
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            String[] hobbies = req.getParameterValues("hobby");
    
            //2.封装学生对象
            Student stu = new Student(username,password,hobbies);
    
            //3.输出对象
            System.out.println(stu);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
    
  • 修改register.html

    <form action="/request/servletDemo04">
    
  • 访问
    在这里插入图片描述

3) 获取参数反射封装对象
  • 问题:如果获取的参数有10个,那么就需要写十次String xx= req.getParameter("xx");,这样太麻烦

  • 那我们就可以采用反射封装对象方式

  • 此种封装的使用要求是,表单<input>标签的name属性取值,必须和实体类中定义的属性名称一致

  • 案例:新建ServletDemo05

    package com.itheima.servlet;
    
    import com.itheima.bean.Student;
    
    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.beans.PropertyDescriptor;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.util.Map;
    
    /*
        封装对象-反射方式(使用反射+内省实现数据模型的封装)
     *  内省:是sun公司推出的一套简化反射操作的规范。把javabean中的属性都封装成一个属性描述器。
     * 	        属性描述器中会有字段信息,get和set方法(取值或存值)
     */
    @WebServlet("/servletDemo05")
    public class ServletDemo05 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.获取所有的数据
            Map<String, String[]> map = req.getParameterMap();
    
            //2.封装学生对象
            Student stu = new Student();
            //2.1遍历集合
            for(String name : map.keySet()) {//username
                String[] value = map.get(name);
                try {
                    //2.2获取Student对象的属性描述器
                    //构造函数的第一个参数决定是哪个属性的描述器。第二个参数是当前属性所属对象的字节码
                    PropertyDescriptor pd = new PropertyDescriptor(name,stu.getClass());
                    //2.3获取对应的setXxx方法
                    Method writeMethod = pd.getWriteMethod(); // setUsername()
                    //2.4执行方法
                    if(value.length > 1) {
                        writeMethod.invoke(stu,(Object)value);//如果是多个属性值(爱好),需要转换为object		   // stu.setUsername(value)
                    }else {
                        writeMethod.invoke(stu,value);//通过当前属性描述器的写入方法,将value写入stu对象的这个属性身上
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            //3.输出对象
            System.out.println(stu);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
    
  • 修改register.html

     <form action="/request/servletDemo05" >
    
  • 访问
    在这里插入图片描述

4) 获取请求参数工具类封装 ***
  • 上述的操作还是都太麻烦,能不能直接调用现成的工具呢?

  • 可以,使用apache的beanutils包

  • copy jar包

    “day03_请求响应\资料\beanutils的jar包”下所有的包,copy到“项目/web/WEB-INF/libs”下

    然后添加到项目引用库
    在这里插入图片描述

  • 案例:新建ServletDemo06

    package com.itheima.servlet;
    
    import com.itheima.bean.Student;
    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.util.Map;
    
    /*
        封装对象-工具类方式
     */
    @WebServlet("/servletDemo06")
    public class ServletDemo06 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.获取所有的数据
            Map<String, String[]> map = req.getParameterMap();
    
            //2.封装学生对象
            Student stu = new Student();
            try {
                BeanUtils.populate(stu,map);//将map中的数据,封装到stu对象中(就这么一句话就搞定了)
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            //3.输出对象
            System.out.println(stu);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
    
  • 修改register.html

    <form action="/request/servletDemo06">
    
  • 访问 : 通过register.html点击注册之后,跳转过去发现报错
    在这里插入图片描述

    • 报错信息说是,找不到BeanUtils

    • 我们刚刚不是添加到项目引用库中了么?注意我们现在的项目是需要部署到tomcat的,项目中有了,但是部署到tomcat的war包中还没有,所以需要特殊处理一下:

    • File - Project Structure
      在这里插入图片描述

  • 访问
    在这里插入图片描述

2.3.4 用流的形式读取请求信息 ***

  • 除了上述方式可以获取请求信息,还可以通过流来获取
    在这里插入图片描述

    • BufferedReader了解即可
    • ServletInputStream常用于获取图片,文件 ***
  • 案例:新建ServletDemo07

    package com.itheima.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletInputStream;
    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("/servletDemo07")
    public class ServletDemo07 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //字符流(必须是post方式)
            /*BufferedReader br = req.getReader(); 
            String line;
            while((line = br.readLine()) != null) {
                System.out.println(line);
            }*/
            //br.close();//这个流是从req对象中获取的,不是自己创建的,所以不需要我们关闭
    
            //字节流 (应用场景,请求参数中有二进制文件(图片)时)
            ServletInputStream is = req.getInputStream();
            byte[] arr = new byte[1024];
            int len;
            while((len = is.read(arr)) != -1) {
                System.out.println(new String(arr,0,len));
            }
            //is.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 修改 register.html

    <!--如果是字符流,post请求方式-->
    <form action="/request/servletDemo07" method="post">
    
  • 访问
    在这里插入图片描述

    • 流方式获取到的中文,会进行编码,所以看到的姓名是编码后的

2.3.5请求正文中文编码问题

  • GET 方式
    • 没有乱码问题。在 Tomcat 8.5 版本后已经解决
  • POST 方式
    • 有乱码问题。可以通过 setCharacterEncoding() 方法来解决
1)POST方式请求 ***
  • 案例:ServletDemo08

    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;
    
    /*
        中文乱码
     */
    @WebServlet("/servletDemo08")
    public class ServletDemo08 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username = req.getParameter("username");
            System.out.println(username);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 修改register.html

     <form action="/request/servletDemo08" method="post" >
    
  • 访问
    在这里插入图片描述

  • 解决乱码,修改

    //设置编码格式
    req.setCharacterEncoding("UTF-8");
    
2)GET方式请求 (了解)

GET方式请求的正文是在地址栏中,在Tomcat8.5版本及以后,Tomcat服务器已经帮我们解决了,所以不会有乱码问题了。

而如果我们使用的不是Tomcat服务器,或者Tomcat的版本是8.5以前,那么GET方式仍然会有乱码问题,解决方式如下:(以下代码了解即可,因为我们现在使用的是Tomcat9.xx版本)

/**
 * 在Servlet的doGet方法中添加如下代码
 */
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /*
         * GET方式:正文在地址栏
         * username=%D5%C5%C8%FD
         * %D5%C5%C8%FD是已经被编过一次码了
         *
         * 解决办法:
         * 	 使用正确的码表对已经编过码的数据进行解码。
         * 		就是把取出的内容转成一个字节数组,但是要使用正确的码表。(ISO-8859-1)
         * 	 再使用正确的码表进行编码
         * 		把字节数组再转成一个字符串,需要使用正确的码表,是看浏览器当时用的是什么码表
         */
        String username = request.getParameter("username");
        byte[] by = username.getBytes("ISO-8859-1");
        username = new String(by,"GBK");

        //输出到浏览器:注意响应的乱码问题已经解决了
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.write(username);
}

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

2.3.6 请求域 ***

在这里插入图片描述

  • 请求到ServletA,实现的功能,需要用到ServletB,那这时候就可以在ServletA将请求转发到ServletB
  • 那ServletB中可能会用到ServletA中的数据,那这时候就涉及到数据共享了
  • 在这里如果使用应用域来共享数据,就有点浪费了,因为我们只是在这次请求中需要共享数据,不是整个应用
  • 所以就用到了请求域

2.3.7 请求转发 ***

  • 请求转发:客户端的一次请求到达后,发现需要借助其他 Servlet 来实现功能

  • 特点:

    • 浏览器地址栏不变

    • 域对象中的数据不丢失

    • 负责转发的 Servlet 转发前后的响应正文会丢失 (ServletA的响应正文会丢失,由ServletB响应客户端)

    • 由转发的目的地来响应客户端
      在这里插入图片描述

      • 应用场景:如果一次请求中这个servlet无法单独完成任务,这时会将这个请求转发给另一个servlet
      • 如果这两个servlet需要共享数据,我们一般使用请求域
      • 请求转发,不会丢失请求域数据,所以共享数据,都使用请求域
  • 请求转发API
    在这里插入图片描述

    • dispatcher:[dɪˈspætʃə®].调度
    • forward:向前,(按新地址)转寄; 发送
    • getRequestDispatcher(‘转发的url’)
  • 案例:新建ServletDemo09

    package com.itheima.servlet;
    
    import javax.servlet.RequestDispatcher;
    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("/servletDemo09")
    public class ServletDemo09 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置共享数据
            req.setAttribute("encoding","gbk");
    
            //获取请求调度对象
            RequestDispatcher rd = req.getRequestDispatcher("/servletDemo10");
            //实现转发功能
            rd.forward(req,resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 新建ServletDemo10

    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;
    
    /*
        请求转发
     */
    @WebServlet("/servletDemo10")
    public class ServletDemo10 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取共享数据
            Object encoding = req.getAttribute("encoding");
            System.out.println(encoding);
    
            System.out.println("servletDemo10执行了...");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 访问
    在这里插入图片描述

2. 响应对象

2.1 响应对象介绍

2.1.1 关于响应

  • 响应:回馈结果。在 BS 架构中,就是服务器给客户端浏览器反馈结果

  • 响应对象:就是在项目中用于发送响应的对象
    在这里插入图片描述

  • 响应对象也是是Servlet规范中定义的,它包括了协议无关的和协议相关的

    • 协议无关的对象标准是:ServletResponse接口

    • 协议相关的对象标准是:HttpServletResponse接口

  • 我们课程中涉及的响应对象都是和HTTP协议相关的。即使用的是HttpServletResponse接口的实现类

2.1.2 常见状态码 ***

在这里插入图片描述

  • 405:请求方式不支持,例如:一般是后台只支持post请求,而发起的请求确实get请求,这时候就会提示405

  • 状态码首位含义:

    状态码说明
    1xx消息
    2xx成功
    3xx重定向
    4xx客户端错误
    5xx服务器错误

2.2 常用方法介绍

  • 在HttpServletResponse接口中提供了很多方法,接下来我们通过API文档,来了解一下这些方法
  • 先了解即可,接下来我们会一步一步介绍
    在这里插入图片描述

2.3 响应对象的使用示例

2.3.1 字节流响应消息&解决乱码

  • 字节流响应API
    在这里插入图片描述

    • 字节流,常用于处理图片,文件
  • 新建项目:response_demo,设置虚拟路径/response

  • 新建类:com.itheima.servlet.ServletDemo01

    package com.itheima.servlet;
    
    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;
    /*
        字节流响应消息及乱码的解决
     */
    @WebServlet("/servletDemo01")
    public class ServletDemo01 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            /*
                项目中常用的编码格式是u8,而浏览器默认使用的编码是gbk。导致乱码!
             */
            //1. 获取字节流输出对象
            ServletOutputStream sos = resp.getOutputStream();
    	    //2. 定义一个消息
            String str = "你好";
            //通过字节流对象输出
            sos.write(str.getBytes());//getBytes不带参数,默认获取操作系统的编码集(我们安装的都是中文windows,所以系统编码集是gbk)
            //sos.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 访问

    • 谷歌浏览器,没有乱码(这是因为谷歌浏览器的默认编码是gbk)
      在这里插入图片描述

    • 但是谷歌浏览器想查看编码,需要安装插件,所以我们再来看ie(发现默认是gb2312(gbk))
      在这里插入图片描述

  • 但其实,我们的代码都应该是utf-8编码格式,只不过是getBytes默认处理了,才没有出现乱码
    在这里插入图片描述

    • 代码格式是utf-8,但是到浏览器gbk上为啥不是乱码,这是因为getBytes方法默认处理了,getBytes默认与操作系统的编码格式一致,而操作系统编码是gbk,所以getBytes处理成gbk了
  • 那如何出现乱码呢?修改代码:

    sos.write(str.getBytes("UTF-8"));
    
  • 访问
    在这里插入图片描述

  • 解决乱码

    /*
     项目中常用的编码格式是u8,而浏览器默认使用的编码是gbk。导致乱码!
     解决方式一:修改浏览器的编码格式(不推荐,不能让用户做修改的动作)
     解决方式二:通过输出流写出一个标签:<meta http-equiv='content-type' content='text/html;charset=UTF-8'>
     解决方式三:response.setHeader("Content-Type","text/html;charset=UTF-8");  指定响应头信息
     解决方式四:response.setContentType("text/html;charset=UTF-8");
    */
    //sos.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>".getBytes());
    
    //resp.setHeader("Content-Type","text/html;charset=UTF-8");
    resp.setContentType("text/html;charset=UTF-8");//常用第四种,告知浏览器采用utf-8编码方式
    
  • 访问
    在这里插入图片描述

2.3.2 字符流响应消息&解决乱码 ***

  • 字符流API
    在这里插入图片描述

    • 字符流,常用于处理文字
  • 案例:新建ServletDemo02

    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("/servletDemo02")
    public class ServletDemo02 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1. 准备一个消息
            String str = "你好";
            //2. 获取字符流对象
            PrintWriter pw = resp.getWriter();
            //3. 通过字符流输出
            pw.write(str);
            //pw.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 访问
    在这里插入图片描述

  • 解决

    //解决中文乱码
    resp.setContentType("text/html;charset=UTF-8");
    
  • 访问
    在这里插入图片描述

  • 解决乱码总结

    • 如果是响应解决乱码问题,一般思路就是让浏览器与代码中的编码风格保持一致(utf-8)

       resp.setContentType("text/html;charset=UTF-8");
      
    • 如果请求中解决乱码,将gbk编码的中文信息转换为utf-8

      //设置编码格式 (将浏览器默认编码gbk的中文信息,转换为utf-8的信息)
       req.setCharacterEncoding("UTF-8");
      

2.3.3 响应图片

  1. 创建字节输入流对象,关联读取的图片路径

  2. 通过响应对象获取字节输出流对象

  3. 循环读取和写出图片

  4. 案例:新建ServletDemo03

    package com.itheima.servlet;
    
    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.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /*
        响应图片到浏览器
     */
    @WebServlet("/servletDemo03")
    public class ServletDemo03 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1. 创建字节输入流对象,关联图片路径
            String realPath = getServletContext().getRealPath("/img/hm.png");
            System.out.println(realPath);
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
    	    //注意:不能直接指定图片路径,需要同getRealPath获取,因为项目还要发布,我们需要获取到发布之后的图片路径
            //BufferedInputStream bis = new BufferedInputStream(new FileInputStream(/img/hm.png));
            //2. 获取字节输出流对象
            ServletOutputStream sos = resp.getOutputStream();
    
            //3. 循环读写
            byte[] arr = new byte[1024];
            int len;
            while((len = bis.read(arr)) != -1) {
                sos.write(arr,0,len);
            }
    
            bis.close();
            sos.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  5. 将今天资料“\day03_请求响应\资料\img”这个文件夹,copy到web目录下

  6. 访问
    在这里插入图片描述

2.3.4 设置缓存时间

  • 缓存:对于不经常变化的数据,我们可以设置合理缓存时间,以避免浏览器频繁请求服务器。以此来提高效率

  • 缓存API
    在这里插入图片描述

  • 案例:新建ServletDemo04

    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;
    
    /*
        缓存
     */
    @WebServlet("/servletDemo04")
    public class ServletDemo04 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String news = "这是一条很火爆的新闻~~";
    
            //设置缓存时间:1小时的缓存时间
            //参数1:Expires : 失效的意思
            //参数2:当前时间+1小时毫秒值(意思就是在1小时之后过期)
            resp.setDateHeader("Expires",(System.currentTimeMillis()+1*60*60*1000L));
    
            //设置编码格式
            resp.setContentType("text/html;charset=UTF-8");
            //写出数据
            resp.getWriter().write(news);
            System.out.println("aaa");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 第一次访问:发现执行了Servlet,并且打印了aaa
    在这里插入图片描述

  • 此时,这个Servlet已经被缓存下来了
    在这里插入图片描述

  • 第二次访问
    在这里插入图片描述

    • 并且控制台没有打印aaa

2.3.5 设置定时刷新

  • 定时刷新:过了指定时间后,页面自动进行跳转

  • 定时刷新API
    在这里插入图片描述

  • 案例:新建ServletDemo05

    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;
    
    /*
        定时刷新
     */
    @WebServlet("/servletDemo05")
    public class ServletDemo05 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String news = "您的用户名或密码错误,3秒后自动跳转到登录页面...";
    
            //设置编码格式
            resp.setContentType("text/html;charset=UTF-8");
            //写出数据
            resp.getWriter().write(news);
    
            //设置响应消息头定时刷新
    	    //Refresh:刷新
            //第二个参数第一部分:3,3设之后
            //第二个参数第二部分:跳转到哪个路径
            //resp.setHeader("Refresh","3;URL=/response/login.html");
            resp.setHeader("Refresh","3;URL="+req.getContextPath()+"/login.html");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
    
  • 将之前的login.html复制到这个项目:web/login.html

  • 访问:3s之后自动跳转到login.html
    在这里插入图片描述

2.3.6 请求重定向 ***

在这里插入图片描述

  • 案例:新建ServletDemo06

    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;
    
    /*
        请求重定向
     */
    @WebServlet("/servletDemo06")
    public class ServletDemo06 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置请求域数据
            req.setAttribute("username","zhangsan");
    
            //设置重定向
            resp.sendRedirect(req.getContextPath() + "/servletDemo07");
    	   //resp.sendRedirect("/response/servletDemo07");
    		// resp.sendRedirect("https://www.baidu.com");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 新建ServletDemo07,获取共享数据

    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;
    
    /*
        请求重定向
     */
    @WebServlet("/servletDemo07")
    public class ServletDemo07 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("servletDemo07执行了...");
            Object username = req.getAttribute("username");//获取不到
            System.out.println(username);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 访问:无法获取共享数据打印null
    在这里插入图片描述

  • 两次请求验证
    在这里插入图片描述

  • 重定向与转发的区别

  • 重定向:

    • 两次请求
    • 地址栏发生变化
    • 不可以使用request域共享数据 (既然是两次请求,那肯定不能使用请求域中共享的数据)
    • 可以重定向到其他服务器的url
  • 转发:

    • 一次请求
    • 地址栏不发生变化
    • 可以使用request域共享数据
    • 只能转发到自己服务器内部的url

2.3.7 响应对象-文件下载

  • 案例:新建ServletDemo08

    package com.itheima.servlet;
    
    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.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /*
        文件下载
     */
    @WebServlet("/servletDemo08")
    public class ServletDemo08 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.创建字节输入流,关联读取的文件
            //获取文件的绝对路径
            String realPath = getServletContext().getRealPath("/img/hm.png");
            //创建字节输出流对象
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));
    
            //2.设置响应头支持的类型  应用支持的类型为字节流
            /*
                Content-Type 消息头名称   支持的类型
                application/octet-stream   消息头参数  应用类型为字节流
             */
            resp.setHeader("Content-Type","application/octet-stream");
    
            //3.设置响应头以下载方式打开  以附件形式处理内容
            /*
                Content-Disposition  消息头名称  处理的形式
                attachment;filename=  消息头参数  附件形式进行处理;指定下载文件名称
             */
            resp.setHeader("Content-Disposition","attachment;filename=hm.png");
    
            //4.获取字节输出流对象
            ServletOutputStream sos = resp.getOutputStream();
    
            //5.循环读写文件
            byte[] arr = new byte[1024];
            int len;
            while((len = bis.read(arr)) != -1) {
                sos.write(arr,0,len);
            }
    
            //6.释放资源
            bis.close();
            //sos.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
  • 访问
    在这里插入图片描述

3 案例-学生管理系统

3.1 案例效果演示

在这里插入图片描述

3.2 资源准备

  1. 创建一个 web 项目 : reqresp_test,虚拟目录/stu

  2. 在 web 目录下创建一个 index.html,包含两个超链接标签(添加学生、查看学生)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>学生管理系统首页</title>
    </head>
    <body>
        <a href="/stu/addStudent.html">添加学生</a>
        <a href="/stu/listStudentServlet">查看学生</a>
    </body>
    </html>
    
  3. 在 web 目录下创建一个 addStudent.html,用于实现添加功能的表单页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>添加学生</title>
    </head>
    <body>
        <form action="/stu/addStudentServlet" method="get" autocomplete="off">
            学生姓名:<input type="text" name="username"> <br>
            学生年龄:<input type="number" name="age"> <br>
            学生成绩:<input type="number" name="score"> <br>
            <button type="submit">保存</button>
        </form>
    </body>
    </html>
    
  4. 在 src 下创建一个 com.itheima.bean.Student 类,用于封装学生信息

    package com.itheima.bean;
    
    public class Student {
        private String username;
        private int age;
        private int score;
    
        public Student() {
        }
    
        public Student(String username, int age, int score) {
            this.username = username;
            this.age = age;
            this.score = score;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int getScore() {
            return score;
        }
    
        public void setScore(int score) {
            this.score = score;
        }
    }
    
    

3.3 添加学生功能

  • 实现步骤

    1. 创建 AddStudentServlet 类。继承 HttpServlet
    2. 重写 doGet 和 doPost 方法
    3. 获取表单中的数据
    4. 将获取到的数据封装成 Student 对象
    5. 将 Student 对象中的数据保存到 d:\stu.txt 文件中
    6. 通过定时刷新功能完成对浏览器的响应
  • 新建:AddStudentServlet

    package com.itheima.servlet;
    
    import com.itheima.bean.Student;
    
    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.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
        实现添加功能
     */
    @WebServlet("/addStudentServlet")
    public class AddStudentServlet extends HttpServlet{
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         
            
            //1.获取表单中的数据
            String username = req.getParameter("username");
            String age = req.getParameter("age");
            String score = req.getParameter("score");
    
            //2.创建学生对象并赋值
            Student stu = new Student();
            stu.setUsername(username);
            stu.setAge(Integer.parseInt(age));
            stu.setScore(Integer.parseInt(score));
    
            //3.将学生对象的数据保存到d:\\stu.txt文件中
            BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\stu.txt",true));
            bw.write(stu.getUsername() + "," + stu.getAge() + "," + stu.getScore());
            bw.newLine();
            bw.close();
    
            //4.通过定时刷新功能响应给浏览器
            resp.setContentType("text/html;charset=UTF-8");
            resp.getWriter().write("添加成功。2秒后自动跳转到首页...");
            resp.setHeader("Refresh","2;URL=/stu/index.html");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
    
  • 访问
    在这里插入图片描述

3.4 查看学生功能

  • 实现步骤

    1. 创建 ListStudentServlet 类。继承 HttpServlet
    2. 重写 doGet 和 doPost 方法
    3. 通过字符输入流读取 d:\stu.txt 文件中的数据
    4. 将读到的数据封装到 Student 对象中
    5. 将多个 Student 对象保存到集合中
    6. 遍历集合,将数据响应到浏览器
  • 新建ListStudentServlet

    package com.itheima.servlet;
    
    import com.itheima.bean.Student;
    
    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.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.ArrayList;
    
    /*
        实现查看功能
     */
    @WebServlet("/listStudentServlet")
    public class ListStudentServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.创建字符输入流对象,关联读取的文件
            BufferedReader br = new BufferedReader(new FileReader("d:\\stu.txt"));
    
            //2.创建集合对象,用于保存Student对象
            ArrayList<Student> list = new ArrayList<>();
    
            //3.循环读取文件中的数据,将数据封装到Student对象中。再把多个学生对象添加到集合中
            String line;
            while((line = br.readLine()) != null) {
                //张三,23,95
                Student stu = new Student();
                String[] arr = line.split(",");
                stu.setUsername(arr[0]);
                stu.setAge(Integer.parseInt(arr[1]));
                stu.setScore(Integer.parseInt(arr[2]));
                list.add(stu);
            }
    
            //4.遍历集合,将数据响应给浏览器
            resp.setContentType("text/html;charset=UTF-8");
            //获取输出流对象
            PrintWriter pw = resp.getWriter();
            for(Student s : list) {
                pw.write(s.getUsername() + "," + s.getAge() + "," + s.getScore());
                pw.write("<br/>");
            }
            // 注意:其实这个代码写复杂了。文本中的数据,与最终输出到浏览器的数据一模一样
            // 所以完全可以读出来的line,通过pw直接写即可,不需要封装List<student>
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    
    
  • 访问
    在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

InLoadwetrust

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值