ServletRequest请求,ServletResponse响应,学生管理系统案例实现

知识点梳理

详细讲义

1. 请求对象

2.1 请求对象介绍

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

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

  • 咱们经常使用的对象就是ServletRequest和HttpServletRequest,它们的区别就是是否和HTTP协议有关web

     

     

2.2 经常使用方法介绍

  • 先了解便可,接下来咱们会一步一步介绍apache

 

 

2.3 请求对象的使用示例

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

  • 获取路径方法windows

     

     

    • getQueryString,获取请求的数据,好比url问号后边的数据数组

    • URI是以一种抽象的,高层次概念定义统一资源标识,而URL则是具体的资源标识的方式浏览器

    • URI比URL范围大,URL是URI的一种缓存

    • url?后边的请求参数,也能够叫作查询字符串 (请求动做是查询,把请求参数做为查询关键字)tomcat

    • 重点方法: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ʃə(r)].调度

    • 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);
        }
    }
    
  • 访问

     

相关文章
相关标签/搜索