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);
        }
    }
    
  • 訪問

     

相關文章
相關標籤/搜索