1. 程式人生 > >Servlet第四篇【request物件常用方法、應用】

Servlet第四篇【request物件常用方法、應用】

什麼是HttpServletRequest

HttpServletRequest**物件代表客戶端的請求,當客戶端通過HTTP協議訪問伺服器時,**HTTP請求頭中的所有資訊都封裝在這個物件中,開發人員通過這個物件的方法,可以獲得客戶這些資訊。

簡單來說,要得到瀏覽器資訊,就找HttpServletRequest物件

HttpServletRequest常用方法

獲得客戶機【瀏覽器】資訊

  • getRequestURL方法返回客戶端發出請求時的完整URL。
  • getRequestURI方法返回請求行中的資源名部分。
  • getQueryString 方法返回請求行中的引數部分。
  • getPathInfo方法返回請求URL中的額外路徑資訊。額外路徑資訊是請求URL中的位於Servlet的路徑之後和查詢引數之前的內容,它以“/”開頭。
  • getRemoteAddr方法返回發出請求的客戶機的IP地址
  • getRemoteHost方法返回發出請求的客戶機的完整主機名
  • getRemotePort方法返回客戶機所使用的網路埠號
  • getLocalAddr方法返回WEB伺服器的IP地址。
  • getLocalName方法返回WEB伺服器的主機名

獲得客戶機請求頭

  • getHeader方法
  • getHeaders方法
  • getHeaderNames方法

獲得客戶機請求引數(客戶端提交的資料)

  • getParameter方法
  • getParameterValues(String name)方法
  • getParameterNames方法
  • getParameterMap方法

HttpServletRequest應用

防盜鏈

什麼是防盜鏈呢?比如:我現在有海賊王最新的資源,想要看海賊王的要在我的網頁上看。現在別的網站的人看到我有海賊王的資源,想要把我的資源貼上在他自己的網站上。這樣我獨家的資源就被一個CTRL+C和CTRL+V搶走了?而反盜鏈就是不能被他們CRTL+C和CRTL+V

  • 下面我模擬一下場景。現在我首頁先有一個超連結,指向著海賊王最新資源

  • 當我點進去,就能看到海賊王最新資源了

  • 其他的人可以通過複製貼上我的地址,放到它們的網頁上

  • 這樣我就划不來啦【我的廣告你來沒看呢!】。想要看我的資源,就必須經過我的首頁點進去看

  • 想要實現這樣的效果,就要獲取Referer這個訊息頭判斷Referer是不是從我的首頁來的。如果不是從我的首頁來的,跳轉回我的首頁


        //獲取到網頁是從哪裡來的
        String referer = request.getHeader("Referer");

        //如果不是從我的首頁來或者從位址列直接訪問的,
        if ( referer == null || !referer.contains("localhost:8080/zhongfucheng/index.jsp") ) {

            //回到首頁去
            response.sendRedirect("/zhongfucheng/index.jsp");
            return;
        }

        //能執行下面的語句,說明是從我的首頁點選進來的,那沒問題,照常顯示
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("路飛做了XXXXxxxxxxxxxxxxxxxx");
  • 首先按正常預想的,別人從首頁點選我的資源,訪問我海賊王最新的資源

\

  • 能夠成功訪問到資源

  • 如果我在瀏覽器直接輸入地址【此時Referer是為null的】,我們來看看

  • 跳回到首頁上,不能訪問到海賊王資源

  • 再試試,如果別人貼上了我的資源url,在它的網頁上掛了一個網址呢。

  • 在別人網頁上點選的時候

  • 又跳回到了我的首頁了。

表單提交資料【通過post方式提交資料】


<form action="/zhongfucheng/Servlet111" method="post">
    <table>
        <tr>
            <td>使用者名稱</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密碼</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td>性別</td>
            <td>
                <input type="radio" name="gender" value="男"><input type="radio" name="gender" value="女"></td>
        </tr>
        <tr>
            <td>愛好</td>
            <td>
                <input type="checkbox" name="hobbies" value="游泳">游泳
                <input type="checkbox" name="hobbies" value="跑步">跑步
                <input type="checkbox" name="hobbies" value="飛翔">飛翔
            </td>
        </tr>
        <input type="hidden" name="aaa" value="my name is zhongfucheng">
        <tr>
            <td>你的來自於哪裡</td>
            <td>
                <select name="address">
                    <option value="廣州">廣州</option>
                    <option value="深圳">深圳</option>
                    <option value="北京">北京</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>詳細說明:</td>
            <td>
                <textarea cols="30" rows="2" name="textarea"></textarea>
            </td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
            <td><input type="reset" value="重置"></td>
        </tr>
    </table>
  • 在Servlet111中獲取到提交的資料,程式碼如下

        //設定request字元編碼的格式
        request.setCharacterEncoding("UTF-8");

        //通過html的name屬性,獲取到值
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String gender = request.getParameter("gender");

        //複選框和下拉框有多個值,獲取到多個值
        String[] hobbies = request.getParameterValues("hobbies");
        String[] address = request.getParameterValues("address");

        //獲取到文字域的值
        String description = request.getParameter("textarea");

        //得到隱藏域的值
        String hiddenValue = request.getParameter("aaa");

        ....各種System.out.println().......

  • 向表單輸入資料

  • Servlet111得到表單帶過來的資料,最後的一個數據是隱藏域帶過來的。

超連結方式提交資料

常見的get方式提交資料有使用超連結,sendRedirect()

格式如下:


    sendRedirect("servlet的地址?引數名="+引數值 &"引數名="+引數值);
  • 我們來使用一下,通過超連結將資料帶給瀏覽器

    <a href="/zhongfucheng/Servlet111?username=xxx">使用超連結將資料帶給瀏覽器</a>
  • 在Servlet111接收資料

        //接收以username為引數名帶過來的值
        String username = request.getParameter("username");
        System.out.println(username);
  • 注意看瀏覽器左下角

  • 伺服器成功接收到瀏覽器傳送過來的資料

  • 並且,傳輸資料明文的出現在瀏覽器的位址列上

  • sendRedirect()和超連結類似,在這裡就不贅述了

解決中文亂碼問題

細心的朋友會發現,我在獲取表單資料的時候,有這句程式碼request.setCharacterEncoding("UTF-8");,如果沒有這句程式碼,會發生什麼事呢?我們看看。

  • 再重新填寫資料

  • 在伺服器檢視提交過來的資料,所有的中文資料都亂碼了

  • 來這裡我們來分析一下亂碼的原因,在前面的部落格中我已經介紹了,Tomcat伺服器預設編碼是ISO 8859-1,而瀏覽器使用的是UTF-8編碼。瀏覽器的中文資料提交給伺服器,Tomcat以ISO 8859-1編碼對中文編碼,當我在Servlet讀取資料的時候,拿到的當然是亂碼。而我設定request的編碼為UTF-8,亂碼就解決了。

  • 接下來使用get方式傳遞中文資料,把表單的方式改成get即可

  • 當我們訪問的時候,又出現亂碼了!

  • 於是我按照上面的方式,把request物件設定編碼為UTF-8試試

        request.setCharacterEncoding("UTF-8");
        String name = request.getParameter("name");
  • 結果還是亂碼。這是為什麼呢?我明明已經把編碼設定成UTF-8了,按照post方式,亂碼問題已經解決了!。我們來看看get和post方式的區別在哪?為什麼post方式設定了request編碼就可以解決亂碼問題,而get方式不能呢。

  • 首先我們來看一下post方法是怎麼進行引數傳遞的。當我們點選提交按鈕的時候,資料封裝進了Form Data中http中多了一個上傳請求頭,既然request物件封裝了http請求,所以request物件可以解析到傳送過來的資料,於是只要把編碼設定成UTF-8就可以解決亂碼問題了

  • 而get方式不同,它的資料是從訊息行帶過去的,沒有封裝到request物件裡面,所以使用request設定編碼是無效的。

  • 要解決get方式亂碼問題也不難,我們既然知道Tomcat預設的編碼是ISO 8859-1,那麼get方式由訊息體帶過去給瀏覽器的時候肯定是用ISO 8859-1編碼了

        //此時得到的資料已經是被ISO 8859-1編碼後的字串了,這個是亂碼
        String name = request.getParameter("username");

        //亂碼通過反向查ISO 8859-1得到原始的資料
        byte[] bytes = name.getBytes("ISO8859-1");

        //通過原始的資料,設定正確的碼錶,構建字串
        String value = new String(bytes, "UTF-8");

上面的程式碼有些難理解,我畫張圖說明一下:

  • 經過我們手工轉換,再來訪問一下

  • 好的,成功解決掉亂碼問題了。
  • 除了手工轉換,get方式還可以改Tomcat伺服器的配置來解決亂碼,但是不推薦使用,這樣不靈活。
  • 我們都知道Tomcat預設的編碼是ISO 8859-1,如果在Tomcat伺服器的配置下改成是UTF-8的編碼,那麼就解決伺服器在解析資料的時候造成亂碼問題了

  • 在8080埠的Connector上加入URIEncoding="utf-8",設定Tomcat的訪問該埠時的編碼為utf-8,從而解決亂碼,這種改法是固定使用UTF-8編碼的


    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" URIEncoding="utf-8"/>
  • 設定了編碼後,沒有做任何手工轉換,成功拿到資料

  • 當然也有另一種改伺服器編碼的方式。設定Tomcat的訪問該埠時的編碼為頁面的編碼,這種改法是隨著頁面的編碼而變
    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" useBodyEncodingForURI="true" />
  • 設定編碼為UTF-8

        request.setCharacterEncoding("UTF-8");
        String name = request.getParameter("name");

  • 再次訪問

  • 手寫超連結如果附帶中文引數問題,要URL重寫,在JSP部落格中會講到

  • 總結:

    • post方式直接改request物件的編碼
    • get方式需要手工轉換編碼
    • get方式也可以修改Tomcat伺服器的編碼,不推薦,因為會太依賴伺服器了!
    • 提交資料能用post就用post

實現轉發

之前講過使用response的sendRedirect()可以實現重定向,做到的功能是頁面跳轉,使用request的getRequestDispatcher.forward(request,response)實現轉發,做到的功能也是頁面跳轉,他們有什麼區別呢?現在我先來說下轉發

  • 程式碼如下所示

        //獲取到requestDispatcher物件,跳轉到index.jsp
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/index.jsp");

        //呼叫requestDispatcher物件的forward()實現轉發,傳入request和response方法
        requestDispatcher.forward(request, response);
  • 訪問Servlet111

  • 上面已經說了,可以通過sendRedirect()重定向可以在資源尾部新增引數提交資料給伺服器。那麼轉發能不能提交資料給伺服器呢?

  • 答案明顯是可以的,並且使用這種方法非常頻繁

  • 在講ServletContext的時候,曾經說過Servlet之間可以通過ServletContext實現通訊,ServletContext也能稱之為域物件。而request也可以稱之為域物件,只不過ServletContext的域是整個web應用,而request的域僅僅代表一次http請求
  • 下面我們來使用request實現Servlet之間的通訊,Servlet111程式碼

        //以username為關鍵字存zhongfucheng值
        request.setAttribute("username", "zhongfucheng");

        //獲取到requestDispatcher物件
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/Servlet222");

        //呼叫requestDispatcher物件的forward()實現轉發,傳入request和response方法
        requestDispatcher.forward(request, response);

  • Servlet222程式碼

        //獲取到存進request物件的值
        String userName = (String) request.getAttribute("username");

        //在瀏覽器輸出該值
        response.getWriter().write("i am :"+userName);
  • 訪問Servlet111看下效果

  • 如上圖所示,Servlet222成功拿到了request物件在Servlet111存進的資料

  • 現在問題又來了,我們可以使用ServletContext和request實現Servlet之間的通訊,那麼我們用哪一種呢?一般的原則:可以使用request就儘可能使用request。因為ServletContext代表著整個web應用,使用ServletContext會消耗大量的資源,而request物件會隨著請求的結束而結束,資源會被回收使用request域進行Servlet之間的通訊在開發中是非常頻繁的

轉發的時序圖

請求轉發的細節

  • 如果在呼叫forward方法之前,在Servlet程式中寫入的部分內容已經被真正地傳送到了客戶端,forward方法將丟擲IllegalStateException異常。 也就是說:不要在轉發之前寫資料給瀏覽器

  • 我們來試試是不是真的會出現異常。


        OutputStream outputStream = response.getOutputStream();
        outputStream.write("--------------------------------------------".getBytes());

        //關閉流,確保讓資料到瀏覽器中
        outputStream.close();

        //跳轉
        request.getRequestDispatcher("/Foot").forward(request, response);

  • 訪問的時候,看到瀏覽器可以輸出資料,Tomcat後臺丟擲了異常

  • 如果在呼叫forward方法之前向Servlet引擎的緩衝區中寫入了內容,只要寫入到緩衝區中的內容還沒有被真正輸出到客戶端,forward方法就可以被正常執行,原來寫入到輸出緩衝區中的內容將被清空,但是,已寫入到HttpServletResponse物件中的響應頭欄位資訊保持有效

轉發和重定向的區別

實際發生位置不同,位址列不同

  • 轉發是發生在伺服器的
    • 轉發是由伺服器進行跳轉的,細心的朋友會發現,在轉發的時候,瀏覽器的位址列是沒有發生變化的,在我訪問Servlet111的時候,即使跳轉到了Servlet222的頁面,瀏覽器的地址還是Servlet111的。也就是說瀏覽器是不知道該跳轉的動作,轉發是對瀏覽器透明的。通過上面的轉發時序圖我們也可以發現,實現轉發只是一次的http請求一次轉發中request和response物件都是同一個。這也解釋了,為什麼可以使用request作為域物件進行Servlet之間的通訊。
  • 重定向是發生在瀏覽器的
    • 重定向是由瀏覽器進行跳轉的,進行重定向跳轉的時候,瀏覽器的地址會發生變化的。曾經介紹過:實現重定向的原理是由response的狀態碼和Location頭組合而實現的。這是由瀏覽器進行的頁面跳轉實現重定向會發出兩個http請求request域物件是無效的,因為它不是同一個request物件

用法不同

很多人都搞不清楚轉發和重定向的時候,資源地址究竟怎麼寫。有的時候要把應用名寫上,有的時候不用把應用名寫上。很容易把人搞暈。記住一個原則:給伺服器用的直接從資源名開始寫,給瀏覽器用的要把應用名寫上

  • request.getRequestDispatcher(“/資源名 URI”).forward(request,response)
    • 轉發時”/”代表的是本應用程式的根目錄【zhongfucheng】
  • response.send(“/web應用/資源名 URI”);
    • 重定向時”/”代表的是webapps目錄

能夠去往的URL的範圍不一樣

  • 轉發是伺服器跳轉只能去往當前web應用的資源
  • 重定向是伺服器跳轉,可以去往任何的資源

傳遞資料的型別不同

  • 轉發的request物件可以傳遞各種型別的資料,包括物件
  • 重定向只能傳遞字串

跳轉的時間不同

  • 轉發時:執行到跳轉語句時就會立刻跳轉
  • 重定向:整個頁面執行完之後才執行跳轉

轉發和重定向使用哪一個?

根據上面說明了轉發和重定向的區別也可以很容易概括出來。轉發是帶著轉發前的請求的引數的。重定向是新的請求

典型的應用場景:

  1. 轉發: 訪問 Servlet 處理業務邏輯,然後 forward 到 jsp 顯示處理結果,瀏覽器裡 URL 不變
  2. 重定向: 提交表單,處理成功後 redirect 到另一個 jsp,防止表單重複提交,瀏覽器裡 URL 變了

RequestDispatcher再說明

RequestDispatcher物件呼叫forward()可以實現轉發上面已經說過了。RequestDispatcher還有另外一個方法include(),該方法可以實現包含,有什麼用呢?

我們在寫網頁的時候,一般網頁的頭部和尾部是不需要改變的。如果我們多個地方使用Servlet輸出網頭和網尾的話,需要把程式碼重新寫一遍。而使用RequestDispatcher的include()方法就可以實現包含網頭和網尾的效果了

  • 我們來操作吧!現在我有網頭和網尾的Servlet

  • 使用Servlet111將網頭和網尾包含

        request.getRequestDispatcher("/Head").include(request, response);

        response.getWriter().write("--------------------------------------------");


        request.getRequestDispatcher("/Foot").include(request, response);
  • 訪問一下Servlet111,成功把網頭和網尾包含了

相關推薦

Servletrequest物件常用方法應用

什麼是HttpServletRequest HttpServletRequest**物件代表客戶端的請求,當客戶端通過HTTP協議訪問伺服器時,**HTTP請求頭中的所有資訊都封裝在這個物件中,開發人員通過這個物件的方法,可以獲得客戶這些資訊。 簡單

Struts2請求資料自動封裝Action得到域物件

前言 前三篇的Struts博文基本把Struts的配置資訊講解完了…..本博文主要講解Struts對資料的處理 一般地,我們使用Servlet的時候都是分為幾個步驟的: 得到web層的資料、封裝資料 呼叫service層的邏輯業務程式碼 將資料儲存在域物

JSPEL表示式介紹獲取各類資料11個內建物件執行運算回顯資料自定義函式fn方法

什麼是EL表示式? 表示式語言(Expression Language,EL),EL表示式是用”${}”括起來的指令碼,用來更方便的讀取物件! EL表示式主要用來讀取資料,進行內容的顯示!

JDBC--資料庫連線池DbUtils框架分頁

1.資料庫連線池 什麼是資料庫連線池 簡單來說:資料庫連線池就是提供連線的。 為什麼我們要使用資料庫連線池 資料庫的連線的建立和關閉是非常消耗資源的 頻繁地開啟、關閉連線造成系統性能低下 編寫連線池 編寫連線池需實現java.sql

ServletCookie和Session的區別應用

Session和Cookie的區別 從儲存方式上比較 Cookie只能儲存字串,如果要儲存非ASCII字串還要對其編碼。 Session可以儲存任何型別的資料,可以把Session看成是一個容器

68 中介軟體的常用方法

1.什麼是中介軟體? 2. Django 自定義中介軟體的五個方法 處理請求:process_request(self,request)        0.執行的時間點:     返回響應之後   1. 執行順序     按照中介軟體註冊的順序執

request物件常用方法總結(及示例)----JSP內建物件

JSP內建物件:request物件   客戶端的請求資訊被封裝在request物件中,通過它才能瞭解到客戶的需求,然後做出響應。它是HttpServletRequest類的例項。request物件具有請求域,即完成客戶端的請求之前,該物件一直有效。常用方法如下

104. Spring Boot 啟動流程分析從零開始學Spring Boot

問題的提出:Spring Boot不像spring需要定義xml檔案檔案,那麼spring boot是如何在沒有配置檔案的情況下為我們啟動一個完整的WEB工程的呢。我們先@SpringBootApplication開始分析下這個啟動流程,原始碼取自:1.4.1.RELEAS

JAVA之反射方法應用

JAVA之反射的應用 import java.util.HashMap; import java.util.Map; public class Child extends Parent { public int add(int a,int b){ return a+b; }

Python開發:Python基礎之函數

nco pos *args 更強 三元 sequence hunk ins att 三元運算 三元運算(三目運算),是對簡單的條件語句的縮寫。 # 書寫格式 result = 值1 if 條件 else 值2 # 如果條件成立,那麽將 “值1” 賦值給result

shell腳本——常用小腳本

tina conf type details -a des iptable pass 進程 shell腳本第四篇——常用小腳本1、將系統進程按內存占用大小排列顯示出來# ps -e -o “%C : %p : %z : %a”|sort -k5-nr 2、將系統進程

python全棧開發Python流程控制

int 語法 password sat code 修改 就是 bre and 十二 流程控制之if…else 既然我們編程的目的是為了控制計算機能夠像人腦一樣工作,那麽人腦能做什麽,就需要程序中有相應的機制去模擬。人腦無非是數學運算和邏輯運算,對於數學運算在上一節我們已經說

web前端CSS屬性操作

idt lba adding 人的 ... charset 平鋪 cit stat 一、文本屬性 1.text-align:cnter 文本居中2.line heigth 垂直居中 :行高,和高度對應3.設置圖片與文本的距離:vertical-align4.text-de

Django ORM數據庫基礎

創建 local bug 創建表 dev 查看 src 數據 add 一、ORM介紹 映射關系:   表名 --------------------》類名   字段--------------------》屬性   表記錄-----------------》類實例化對象

Flask 使用Flask的擴展實現簡單頁面登錄功能

blog resp login sgd user flask password proc request from flask import Flask,render_template,request,redirect,session app = Flask(__name

Django Restful Framework版本解析器序列化和請求數據驗證

tor ade clu cts scheme com 繼承 src 當前 一、版本 程序也來越大時,可能通過版本不同做不同的處理 沒用rest_framework之前,我們可以通過以下這樣的方式去獲取。 class UserView(APIView): def

python學習python函數

none 表達 return語句 開頭 bject 內容 python函數 實現 模塊 一、函數的介紹 函數是組織好的,可重復使用的,用來實現單一,或相關聯功能的代碼段。 函數能提高應用的模塊性,和代碼的重復利用率。你已經知道Python提供了許多內建函數,比如print(

python學習python函數 (二)

運行時 本質 接收參數 hello 函數 作用域 返回 高階函數 clas 一、裝飾器 裝飾器:本質就是函數,功能是為其它函數添加附加功能 裝飾器的原則: 不修改被修飾函數的源代碼 不修改被修飾函數的調用方式 裝飾器的知識儲備:   裝飾器 = 高階函數 + 函數嵌套

ASP.NET MVC快速入門之完整示例(MVC5+EF6)

redirect name php sql語句 rop 方法 輸入框 一次 編輯 目錄 【第一篇】ASP.NET MVC快速入門之數據庫操作(MVC5+EF6) 【第二篇】ASP.NET MVC快速入門之數據註解(MVC5+EF6) 【第三篇】ASP.NET MVC快速入門

: Ansible 常用模塊使用

__name__ 處理 ron mage minute art outfile and 刪除一個用戶 一、 command | shell 模塊 該模塊為:執行命令模塊 (由於命令模塊較為強大,可根據自身對操作系統的熟練程度而增加。所以這裏不再介紹類似可以實