day16-Servlet05

Servlet05

14.HttpServletRequest

  1. HttpServletRequest對象代表客戶端的請求
  2. 當 客戶端/瀏覽器 通過HTTP協議訪問伺服器時,HTTP請求頭中的所有資訊都封裝在這個對象中
  3. 通過這個對象的方法,可以獲取客戶端的資訊
  • HttpServletRequest類圖

image-20221112160803071

image-20221112161006386 image-20221112161332903

14.1HttpServletRequest常用方法

  1. getRequestURI():獲取請求的資源路徑

    //localhost:8080/servlet/loginServlet

  2. getRequestURL():獲取請求的統一資源定位符(絕對路徑)

    //localhost:8080/servlet/loginServlet

  3. getRemoteHost():獲取客戶端的主機

  4. getRemoteAddr():獲取客戶端的ip

  5. getHeader():獲取請求頭

  6. getParameter():獲取請求的參數

  7. getParameterValues():獲取請求的參數(多個值的時候使用)

  8. getMethod():獲取請求的方式get或post

  9. setAttribute(key,value):設置域數據

  10. getAttribute(key):獲取域數據

  11. getRequestDispatcher():獲取請求轉發對象(請求轉發的核心對象)

14.2HttpServletRequest應用實例

需求:在一個表單提交數據給Servlet,在該Servlet中通過HttpServletRequest對象獲取相關數據

package com.li.servlet.request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(name = "HttpServletRequestMethods", value = "/requestMethods")
public class HttpServletRequestMethods extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //這裡我們使用request對象,獲取表單提交的各種數據
        //System.out.println("HttpServletRequestMethods doPost()被調用...");

        //1.獲取和http請求頭相關的資訊
        System.out.println("請求的資源URI= " + request.getRequestURI());
        System.out.println("請求的統一資源定位符(絕對路徑)URL= " + request.getRequestURL());
        System.out.println("請求的客戶端ip地址= " + request.getRemoteAddr());
        /*
        getRemoteAddr()應用:發現某個ip在10s內訪問的次數超過100次,就封ip
        實現思路:1用一個集合concurrentHashMap[k=ip v=訪問次數] 2啟動執行緒定時掃描 3做出相應處理
        */
        //如果我們希望得到請求的頭的相關資訊,可以直接使用request.getHeader("請求頭欄位名")
        System.out.println("http請求頭HOST= " + request.getHeader("Host"));
        System.out.println("該請求發起的地址是= " + request.getHeader("Referer"));
        //請獲取訪問網站的瀏覽器是什麼?
        String userAgent = request.getHeader("User-Agent");
        //User-Agent= Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
        String[] s = userAgent.split(" ");//使用空格分割
        //取最後一個字元,再用 /分割,取第一個字元
        System.out.println("瀏覽器的種類= " + s[s.length - 1].split("\\/")[0]);
        System.out.println("http請求方式= " + request.getMethod());

        //2.獲取和請求參數相關的資訊,要去在返回數據前獲取參數
        //username=&pwd=&hobby=lb&hobby=cc
        //2.1獲取表單的數據[單個數據]
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");
        //2.2獲取表單一組數據[多個數據]
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println("username= " + username);
        System.out.println("pwd= " + pwd);
        //增強for循環的快捷鍵 iter->回車即可
        for (String hobby : hobbies) {
            System.out.println("hobby= " + hobby);
        }
        //推而廣之,如果是單選,下拉框等,獲取數據的方法大同小異
    }
}

html頁面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊</title>
</head>
<body>
<h1>註冊用戶</h1>
<!--注意:這裡的requestMethods不是你的類名,是你在web.xml裡面(或者註解裡面)配置的<url-pattern>-->
<form action="//localhost:8080/servlet_demo/requestMethods" method="post">
    u:<input type="text" name="username"/><br/><br/>
    p:<input type="password" name="pwd"/><br/><br/>
    選擇你最喜歡的三國人物:
    <input type="checkbox" name="hobby" value="lb">劉備
    <input type="checkbox" name="hobby" value="cc">曹操
    <input type="checkbox" name="hobby" value="sq">孫權<br/><br/>
    <input type="submit" value="註冊用戶">
</form>
</body>
</html>

瀏覽器中訪問html頁面,輸入數據,點擊註冊:

image-20221112173741298

後台輸出如下:

image-20221112174008561

14.3HttpServletRequest注意事項和細節

  1. 獲取doPost參數中文亂碼解決方法,設置編碼類型request.setCharacterEncoding("UTF-8");

    注意要寫在獲取參數之前:

    image-20221112174621994

  2. 注意:如果通過PrintWriter writer,有返回數據給瀏覽器,建議將獲取參數的程式碼寫在writer.print()之前,否則可能獲取不到參數值(post)

  3. 處理http響應數中文亂碼問題

    image-20221112175013837

  4. 再次理解HTTP協議響應Content-Type的含義,比如text/html,text/plain,application/x-tar

    Content-Type表示返回的數據類型,瀏覽器會根據這個類型來解析數據,詳見HTTP協議MIME類型

14.4請求轉發

14.4.1為什麼需要請求轉發

  1. 目前我們學習的都是一次請求,對應一個Servlet

    image-20221112181819875

  2. 在實際的開發中,往往業務比較複雜,需要在一次請求中,使用到多個Servlet完成一個任務(Servlet鏈,流水作業)

    image-20221112182014390

14.4.2請求轉發說明

  1. 實現請求轉發:請求轉髮指一個web資源收到客戶端請求後,通知伺服器去調用另外一個web資源進行處理

  2. HttpServletRequest對象(也叫request對象)提供了一個getRequestDispatcher方法,該方法返回一個RequestDispatcher對象,調用這個對象的forward方法可以實現請求轉發

  3. request對象同時也是一個域對象,開發人員通過request對象在實現轉發時,把數據通過request對象帶給其他web資源處理

    • setAttribute方法
    • getAttribute方法
    • removeAttribute方法
    • getAttributeNames方法

14.4.3請求轉發應用實例

例子

需求:瀏覽器在某html頁面輸入數據,checkServlet根據該數據對進行操作,如果輸入的數據為「tom」,就將其設置為「管理員」,如果不是,就設置為「普通用戶」,由managerServlet向伺服器返回數據

image-20221112192943227

CheckServlet:

package com.li.servlet.request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;

@WebServlet(urlPatterns = {"/checkServlet"})
public class CheckServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("CheckServlet doPost()被調用...");

        //根據用戶名來確定該用戶是什麼身份
        String username = request.getParameter("username");
        //注意:如果是同一個request對象(請求轉發),那麼可以在不同的Servlet中使用getParameter取出該參數
        if ("tom".equals(username)) {
            //分配許可權
            //request對象是一個域對象,通過request對象,在實現轉發時,
            // 把數據通過request對象帶給其他web資源處理
            request.setAttribute("role", "管理員");//k-v
        } else {
            request.setAttribute("role", "普通用戶");//k-v
        }

        //獲取分發器
        /**
         * 1. /managerServlet寫的是想轉發的Servlet的url-pattern
         * 2. / 會被解析成 /servlet_demo
         *      因此請求轉發是不可能轉發到外網去的
         * 3.forward(request,response)表示把當前的request和response對象傳遞給下一個Servlet使用,
         *      保證了下一個Servlet和當前的Servlet使用的是同一個request和response對象
         */
        RequestDispatcher requestDispatcher =
                request.getRequestDispatcher("/managerServlet");
        requestDispatcher.forward(request, response);

    }
}

ManagerServlet:

package com.li.servlet.request;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(urlPatterns = {"/managerServlet"})
public class ManagerServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("ManagerServlet doPost()被調用...");

        //因為是同一個request對象,因此可以用request.getParameter("username")獲取username
        String username = request.getParameter("username");
        String role = (String) request.getAttribute("role");//k-v
        //輸出資訊
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("用戶名:" + username + "<br/>");
        writer.print("role:" + role);
        writer.flush();
        writer.close();
    }
}

login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登錄</title>
</head>
<body>
<form action="//localhost:8080/servlet_demo/checkServlet" method="post">
    u:<input type="text" name="username"><br/>
    <input type="submit" value="登錄">
</form>
</body>
</html>

redeployTomcat,在瀏覽器中訪問//localhost:8080/servlet_demo/login.html,輸入數據,點擊登錄,可以看到地址欄變為//localhost:8080/servlet_demo/checkServlet,但沒有變為managerServlet(地址會保留在第一個Servlet的URL)

image-20221112202633137 image-20221112202743178

image-20221112202907968 image-20221112202925282

14.4.4請求轉發注意細節

  1. 瀏覽器地址不會變化(地址會保留在第一個Servlet的URL)

  2. 在同一次HTTP請求中,進行多次轉發,仍然是一次HTTP請求

  3. 在同一次HTTP請求中,進行多次轉發,多個Servlet可以共享request域/對象的數據,即request域/對象的數據(參數,屬性)的作用域,是在一次HTTP請求有效

    因為是同一個request對象(數據上來講)

  4. 可以轉發到WEB-INF目錄下

  5. 不能訪問當前WEB工程外的資源

  6. 因為瀏覽器地址欄會停留在第一個Servlet,如果你刷新頁面,會再次發出請求(並且會帶數據)。

    所以在支付頁面情況下,不要使用請求轉發,否則會造成重複支付 [解決方案可以使用重定向]

image-20221112205005615

14.5習題

14.5.1習題一

通過HttpServletRequest對象獲取到訪問服務的的瀏覽器名稱

通過字元串分割,14.2已完成

14.5.2習題二

請想辦法獲取到 JSESSIONID的值

image-20221112180402215

//獲取 JSESSIONID的值
String cookie = request.getHeader("Cookie");
String[] s1 = cookie.split(";");
String[] strings = s1[0].split("=");
System.out.println("JSESSIONID的值= "+strings[1]);

image-20221112181501739

14.5.3習題三

下面是一個表單,完成如下功能

(1)編寫一個RegisterServlet,能夠接收到提交的各種數據,並獲取瀏覽器所在電腦的作業系統和位數

(2)並把接收到的數據返回給瀏覽器顯示

(3)注意處理中文亂碼問題

(4)暫不處理文件提交

image-20221112205321403

RegisterServlet:

package com.li.servlet.request.homework;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(urlPatterns = {"/registerServlet"})
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.獲取表單提交的數據

        //先設置編碼類型
        request.setCharacterEncoding("utf-8");
        //單個數據使用 getParameter
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");
        String pwd2 = request.getParameter("pwd2");
        //多個數據使用getParameterValues
        String[] sports = request.getParameterValues("sport");
        String gender = request.getParameter("gender");
        String city = request.getParameter("city");
        String introduce = request.getParameter("introduce");

        //2.獲取用戶瀏覽器所在電腦的作業系統和位數
        //Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0
        String User_Agent = request.getHeader("User-Agent");
        String[] s = User_Agent.split(" ");//使用空格分割
        //s[1]="(Windows" 取出索引為1及之後的字元串
        String OS = s[1].substring(1);
        //s[5]=x64;
        String OSNum = s[5].substring(1, 3);

        //3.返回輸出
        //設置編碼類型
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print("你的用戶名稱:" + username + "<br/>");
        writer.print("你的用戶密碼:" + pwd + "<br/>");
        writer.print("你的確認密碼:" + pwd2 + "<br/>");
        writer.print("喜歡的運動:");
        for (String sport : sports) {
            writer.print(sport + " ");
        }
        writer.print("<br/>你的性別:" + gender + "<br/>");
        writer.print("喜歡的城市:" + city + "<br/>");
        writer.print("自我介紹:" + introduce + "<br/>");
        writer.print("電腦作業系統:" + OS + "<br/>");
        writer.print("位數:" + OSNum + "<br/>");
        writer.flush();
        writer.close();
    }
}

register_form.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶註冊</title>
</head>
<body>
<form action="//localhost:8080/servlet_demo/registerServlet" method="post">
    用戶註冊資訊<br/>
    用戶名稱:<input type="text" name="username"/><br/>
    用戶密碼:<input type="password" name="pwd"/><br/>
    確認密碼:<input type="password" name="pwd2"/><br/>
    請選中你喜歡的運動項目<br/>
    <input type="checkbox" name="sport" value="lq">籃球<br/>
    <input type="checkbox" name="sport" value="zq">足球<br/>
    <input type="checkbox" name="sport" value="sq">手球<br/>
    請選中你的性別<br/>
    <input type="radio" name="gender" value="men">男<br/>
    <input type="radio" name="gender" value="women">女<br/>
    請選中你喜歡的城市
    <select name="city">
        <option>--請選中--</option>
        <option value="gz">廣州</option>
        <option value="bj">北京</option>
        <option value="sh">上海</option>
    </select><br/>
    自我介紹<textarea name="introduce"></textarea><br/>
    <input type="submit" value="提交">
    <input type="reset" value="重置">
</form>
</body>
</html>

image-20221112224256688 image-20221112224304878

Tags: