1. 程式人生 > 實用技巧 >請求&響應

請求&響應

請求物件介紹

請求:獲取資源。在BS架構中,就是客戶端瀏覽器向伺服器發出詢問

請求物件:就是在專案當中用於傳送請求的物件

ServletRequest 和 HttpServletRequest

請求物件的常用方法-獲取各種路徑

返回值 方法名 說明

String getContextPath() 獲取虛擬目錄名稱

String getServletPath() 獲取Servlet對映路徑

String getRemoteAddr() 獲取訪問者ip地址

String getQueryString()     獲取請求的訊息資料

String getRequestURI()    獲取統一資源識別符號

StringBuffer   getRequestURL()    獲取統一資源定位符

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 {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //getContextPath()      獲取虛擬目錄名稱
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //getServletPath()      獲取Servlet對映路徑
        String servletPath = request.getServletPath();
        System.out.println(servletPath);
        //getRemoteAddr()       獲取訪問者ip地址
        String remoteAddr = request.getRemoteAddr();
        System.out.println(remoteAddr);
        //getQueryString()    獲取請求的訊息資料     (瞭解)
        String queryString = request.getQueryString();
        System.out.println(queryString);
        //getRequestURI()     獲取統一資源識別符號   /request/ServletDemo01  共和國
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        //getRequestURL()     獲取統一資源定位符   http://localhost:8080/request/ServletDemo01   中華人民共和國
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURL);
    }

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

請求物件常用方法-獲取請求頭資訊

返回值 方法名 說明

String getHeader(String name) 根據請求頭名稱獲取一個值

Enumeration<String> getHeaders(String name) 根據請求頭名稱獲取多個值

Enumeration<String> getHeaderNames() 根據所有請求頭名稱

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 {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //getHeader(String name)     根據請求頭名稱獲取一個值
        String connection = request.getHeader("connection");
        System.out.println(connection);
        System.out.println("----------");
        //getHeaders(String name)   根據請求頭名稱獲取多個值
        Enumeration<String> values = request.getHeaders("Accept-Encoding");
        while(values.hasMoreElements()){
            String value = values.nextElement();
            System.out.println(value);
        }
        System.out.println("----------");
        //getHeaderNames()          根據所有請求頭名稱
        Enumeration<String> names = request.getHeaderNames();
        while(names.hasMoreElements()){
            String name = names.nextElement();
            String value = request.getHeader(name);
            System.out.println(name+","+value);

        }
    }

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

2.3.3 請求物件常用方法3-獲取請求引數(非常重要)

返回值 方法名 說明

String getParameter(String name) 根據名稱獲取資料

String[] getParameterValues(String name) 根據名稱獲取所有資料

Enumeration<String>    getParameterNames() 獲取所有名稱

Map<String,String[]> getParameterMap() 獲取所有引數鍵值對

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 {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.根據名稱獲取資料   getParameter()
        String username = request.getParameter("username");
        System.out.println(username);
        String password = request.getParameter("password");
        System.out.println(password);
        System.out.println("----------------------");
        //2.根據名稱獲取所有資料 getParameterValues()
        String[] hobbies = request.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }
        System.out.println("----------------------");
        //3.獲取所有名稱  getParameterNames()
        Enumeration<String> names = request.getParameterNames();
        while(names.hasMoreElements()){
            String name = names.nextElement();
            System.out.println(name);
        }
        System.out.println("----------------------");
        //4.獲取所有引數的鍵值對 getParameterMap()
        Map<String, String[]> map = request.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();
        }

    }

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

2)封裝請求引數到實體類中

第一種:最簡單直接的封裝方式

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

/*
* 封裝物件-手動封裝
* */
@WebServlet("/ServletDemo04")
public class ServletDemo04 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.獲取所有的資料
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String[] hobbies = request.getParameterValues("hobby");
        //2.封裝學生物件
        Student stu=new Student(username,password,hobbies);
        //輸出物件
        System.out.println(stu);



    }

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

  

  

第二種:使用反射方式封裝  

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.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

/*
* 封裝物件-反射方式
* */
@WebServlet("/ServletDemo05")
public class ServletDemo05 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.獲取所有的資料
        Map<String, String[]> map = request.getParameterMap();
        //2.封裝學生物件
        Student stu=new Student();
        //2.1.遍歷集合
        for (String name : map.keySet()) {
            String[] value = map.get(name);
            //2.2獲取Student物件的屬性描述器,根據名稱拿到 stu裡面的get/set方法
            try {
                PropertyDescriptor pd=new PropertyDescriptor(name,stu.getClass());
                //2.3獲取對應的setXXX方法
                Method writeMethod = pd.getWriteMethod();
                //2.4執行方法
                if (value.length >1) {
                    writeMethod.invoke(stu,(Object) value);
                }else{
                    writeMethod.invoke(stu,value);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        //輸出物件
        System.out.println(stu);



    }

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

當我們寫完此種封裝方式之後,同學們可以發現,我們絕大多數封裝都可以使用這段程式碼來實現。並且,無論是誰來寫這段通用的封裝程式碼,其程式碼內容都是大同小異的。那麼,我們就可以得出一個很有趣的結論:一般遇到這種情況時,肯定有人幫我們寫好了,我們只需要用就行了。我們後面還會遇到類似這樣的情況。

此時,幫我們寫好這段封裝程式碼的是apache軟體基金會,我們前面學習的tomcat也是它提供的。它裡面有一個開源工具包集合commons,裡面有很多開源工具類,今天我們就來講解第一個:commons-beanutils

第三種:使用工具類封裝方式

匯入這兩個包

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.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/*
* 封裝物件-工具類方式
* */
@WebServlet("/ServletDemo06")
public class ServletDemo06 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.獲取所有的資料
        Map<String, String[]> map = request.getParameterMap();
        //2.封裝學生物件
        Student stu=new Student();
        try {
            BeanUtils.populate(stu,map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //輸出物件
        System.out.println(stu);



    }

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

  通過流物件獲取請求資訊

返回值        方法名        說明

BufferReader    getReader()     獲取字元輸入流

ServletInputStream  getInputStream()   獲取位元組輸入流 

package com.itheima.servlet;

import com.itheima.bean.Student;
import org.apache.commons.beanutils.BeanUtils;

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.BufferedReader;
import java.io.IOException;
import java.util.Map;

/*
* 流物件獲取資料
* */
@WebServlet("/ServletDemo07")
public class ServletDemo07 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //字元流(必須是post方式)
       /* BufferedReader br = request.getReader();
        String line;
        while((line=br.readLine())!=null){
            System.out.println(line);
        }*/
        //br.close();

        //位元組流
        ServletInputStream is = request.getInputStream();
        byte[] arr=new byte[1024];
        int len;
        while((len= is.read(arr))!=-1){
            System.out.println(new String(arr,0,len));
        }



    }

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

2.3.5請求正文中中文編碼問題

關於請求中文亂碼問題,我們需要分開討論,第一是POST請求方式,第二是GET方式。

1)POST方式請求

在POST方式請求中,我們的亂碼問題可以用如下程式碼解決:

request.setCharacterEncoding("UTF-8");

GET方式請求的正文是在位址列中,在Tomcat8.5版本及以後,Tomcat伺服器已經幫我們解決了,所以不會有亂碼問題了。

而如果我們使用的不是Tomcat伺服器,或者Tomcat的版本是8.5以前,那麼GET方式仍然會有亂碼問題,解決方式如下:(以下程式碼瞭解即可,因為我們現在使用的是Tomcat9.0.27版本)

/**
 * 在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);
}

  請求物件

請求域(request域):可以在一次請求範圍內進行共享資料

請求物件操作共享資料方法

返回值        方法名                說明

void      setAttribute(String name,Object value)   向請求域物件中儲存資料

Object     getAttribute(String name)         通過名稱獲取請求域物件中的資料

void      removeAttribute(String name)      通過名稱一處請求域物件中的資料

2.3.6 請求轉發(與重定向的區別)

在實際開發中,重定向和請求轉發都是我們要用到的響應方式,那麼他們有什麼區別呢?我們通過下面的示例來看一下:

請求轉發:客戶端的一次請求到達後,發現需要藉助其他Servlet來實現功能

特點:

  • 瀏覽器位址列不變
  • 域物件中的資料不丟失
  • 負責轉發的Servlet轉發前後的相應正文會丟失
  • 有轉發的目的地來響應客戶端

返回值        方法名                說明  

RequestDispatcher  getRequestDispatcher(String name)  獲取請求排程物件

返回值        方法名                說明

void         forward(ServletRequest req,ServletResponse resp)  實現轉發

ServletDemo09

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("/ServletDemo09")
public class ServletDemo09 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);



    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        //設定共享資料
        request.setAttribute("encoding","gbk");
        //獲取請求排程物件
        request.getRequestDispatcher("/ServletDemo10").forward(request,response);
    }
}

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 {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取共享資料
        Object encoding = request.getAttribute("encoding");
        System.out.println(encoding);

        System.out.println("ServletDemo10執行了");

    }
}

2.3.7 請求包含

在實際開發中,我們可能需要把兩個Servlet的內容合併到一起來響應瀏覽器,而同學們都知道HTTP協議的特點是一請求,一響應的方式。所以絕對不可能出現有兩個Servlet同時響應方式。那麼我們就需要用到請求包含,把兩個Servlet的響應內容合併輸出。我們看具體使用示例:

請求包含:可以合併其他Servlet中的功能一起響應給客戶端