Java Web(5)-Servlet詳解(下)

山丘i發表於2020-07-28

一、HttpServletRequest 類

1. HttpServletRequest 類作用?

每次只要有請求進入 Tomcat 伺服器,Tomcat 伺服器就會把請求過來的 HTTP 協議資訊解析好封裝到 Request 物件中。 然後傳遞到 service 方法(doGet 和 doPost)中給我們使用,可以通過 HttpServletRequest 物件,獲取到所有請求的 資訊

2. HttpServletRequest 類的常用方法

  • getRequestURI() 獲取請求的資源路徑
  • getRequestURL() 獲取請求的統一資源定位符(絕對路徑)
  • getRemoteHost() 獲取客戶端的 ip 地址
  • getHeader() 獲取請求頭
  • getParameter() 獲取請求的引數
  • getParameterValues() 獲取請求的引數(多個值的時候使用)
  • getMethod() 獲取請求的方式 GET 或 POST
  • setAttribute(key, value); 設定域資料
  • getAttribute(key); 獲取域資料
  • getRequestDispatcher() 獲取請求轉發物件

具體如下:

首先把環境建好,配置好web.xml ,然後在類中

package com.md.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author MD
 * @create 2020-07-25 8:18
 */
public class RequestAPIServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println(req.getRequestURI());// /04_Servlet/requestAPIServlet

        System.out.println(req.getRequestURL());
        //http://localhost:8080/04_Servlet/requestAPIServlet

        System.out.println(req.getRemoteHost());//127.0.0.1

        System.out.println(req.getHeader("User-Agent"));//Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36

        System.out.println(req.getMethod());//GET
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

對應的web.xml

 <servlet>
        <servlet-name>RequestAPIServlet</servlet-name>
        <servlet-class>com.md.servlet.RequestAPIServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>RequestAPIServlet</servlet-name>
        <url-pattern>/requestAPIServlet</url-pattern>
    </servlet-mapping>

3. 獲取請求引數

首先在web下面建立html檔案,如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="http://localhost:8080/parameterServlet" method="post">
        使用者名稱:<input type="text" name="username"><br>
        密碼:<input type="password" name="password"><br>
        愛好:<input type="checkbox" name="hobby" value="cpp">C++
        <input type="checkbox" name="hobby" value="java">Java
        <input type="checkbox" name="hobby" value="python">Python
        <input type="submit">
    </form>
</body>
</html>

然後是對應的java程式碼,以及配置的web.xml(和上面的類似)

/**
 * @author MD
 * @create 2020-07-25 8:31
 */
public class ParameterServlet extends HttpServlet {


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("------------doGet--------------");
        // 獲取請求的引數
        String username = req.getParameter("username");
        String password = req.getParameter("password");
//        String hobby = req.getParameter("hobby");
        // 當有多個值的時候
        String [] hobby = req.getParameterValues("hobby");

        System.out.println("使用者名稱:"+username);
        System.out.println("密碼:"+password);
        System.out.println("愛好:"+ Arrays.asList(hobby));


    }
}

4. 中文亂碼

使用post請求的時候,如果使用者名稱輸入的是中文,則會出現中文亂碼的情況,所以需要這樣設定

public class ParameterServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 在post的時候注意設定字符集,要不中文亂碼
        // 只有在獲取請求引數呼叫之前使用才有效
        req.setCharacterEncoding("UTF-8");

        System.out.println("------------doPost--------------");

        // 獲取請求的引數
        String username = req.getParameter("username");
        String password = req.getParameter("password");
//        String hobby = req.getParameter("hobby");
        // 當有多個值的時候
        String [] hobby = req.getParameterValues("hobby");

        System.out.println("使用者名稱:"+username);
        System.out.println("密碼:"+password);
        System.out.println("愛好:"+ Arrays.asList(hobby));

    }
}

5. 請求轉發

什麼是請求的轉發?

請求轉發是指伺服器收到請求後,從一次資源跳轉到另一個資源的操作叫請求轉發

請求轉發的特點:

  • 瀏覽器位址列沒有改變
  • 一次請求
  • 共享Request域中的資料
  • 可以轉發到WEB-INF目錄下
  • 不可以訪問工程以外的資源

例子如下:通過訪問Servlet1然後轉發到Servlet2去

public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       // http://localhost:8080/04_Servlet/servlet1?username=abc

        // 1. 獲取請求的引數
        String username = req.getParameter("username");
        System.out.println("在Servlet1中獲取到的請求引數:"+username);
        // 在Servlet1中獲取到的請求引數:abc


        // 2. 把獲取到的資料傳遞,也可以自定義引數傳遞
//        req.setAttribute("username" , username);
        req.setAttribute("key","我來自Servlet1");


        // 3. 轉發
        // 地址必須以 /開頭 ,這個地址也是在web.xml中配置對應的你要去的
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
        requestDispatcher.forward(req,resp);
        
        // 或者可以直接這樣
        req.getRequestDispatcher("/servlet2").forward(req,resp);

    }
}

對應的web.xml就不展示了,都類似

/**
 * @author MD
 * @create 2020-07-25 8:57
 */
public class Servlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 獲取請求的引數
        String username = req.getParameter("username");
        System.out.println("在Servlet2中獲取到的請求引數:"+username);//在Servlet2中獲取到的請求引數:abc

        // 2. 檢視從Servlet1中傳遞的引數
        Object key = req.getAttribute("key");
        System.out.println("Servlet1中傳來的引數:"+key);//Servlet1中傳來的引數:我來自Servlet1

        // 3. 處理自己的業務
        System.out.println("正在處理Servlet2的業務");//正在處理Servlet2的業務

    }
}

6. base標籤

所以在html檔案中,跳轉的時候若使用相對路徑,指定相對的那個路徑

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--
        base標籤設定頁面相對路徑工作時參照的地址
        href 屬性就是引數的地址值
    -->
    <!--<base href="http://localhost:8080/04_Servlet/a/b/c.html">-->
    <!--
        也可以這樣,但最後的斜槓不能省略
    -->
    <base href="http://localhost:8080/04_Servlet/a/b/">

</head>
<body>
    這是a目錄下的b目錄下的c.html頁面
    <a href="../../index.html">跳到首頁</a>
<!--通過定義了base,這個就相當於那個地址的上上層
    http://localhost:8080/04_Servlet/index.html
-->
</body>
</html>

開發中儘量使用絕對路徑,實在不行就使用base+相對路徑

7. web中 / 斜槓的不同意義

在web中 / 是一種絕對路徑

  1. / 斜槓被瀏覽器解析,得到的地址就是 http://ip:port

    <a href="/">斜槓</a>

  2. / 斜槓 如果被伺服器解析,得到的地址是:http://ip:port/工程路徑

    • <url-pattern>/servlet1</url-pattern>
    • servletContext.getRealPath(“/”);
    • request.getRequestDispatcher(“/”);
  3. 特殊情況: response.sendRediect(“/”); 把斜槓傳送給瀏覽器解析。得到 http://ip:port/

二、HttpServletResponse 類

1. HttpServletResponse 類的作用

HttpServletResponse 類和 HttpServletRequest 類一樣。

每次請求進來,Tomcat 伺服器都會建立一個 Response 物件傳 遞給 Servlet 程式去使用。HttpServletRequest 表示請求過來的資訊,HttpServletResponse 表示所有響應的資訊,

我們如果需要設定返回給客戶端的資訊,都可以通過 HttpServletResponse 物件來進行設定

2. 兩個輸出流

字元流 getWriter() 用於傳字串(常用)
位元組流 getOutputStream() 用於下載(傳遞二進位制資料)

3. 如何往客戶端回傳資料

首先還是先建立一個servlet,配置對應的web.xml

注意中文的亂碼情況

package com.md.servlet;
/**
 * @author MD
 * @create 2020-07-25 9:57
 */
public class ResponseIOServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//        System.out.println(resp.getCharacterEncoding());//ISO-8859-1
//
//        // 設定伺服器字符集為
//        resp.setCharacterEncoding("UTF-8");
//        // 此時若瀏覽器沒有使用UTF-8中文還是亂碼,這個時候需要
//        // 通過設定響應頭,使得瀏覽器也使用UTF-8字符集
//        resp.setHeader("Content-Type","text/html; charset=UTF-8");


        // 或者直接可以這樣寫,自動設定伺服器字符集和瀏覽器響應頭
        // 方法一定要流獲取之前先呼叫,通常放在最上面就行
        resp.setContentType("text/html; charset=UTF-8");


        // 需求:往客戶端回傳字串資料

        PrintWriter writer = resp.getWriter();
        writer.write("response");
        writer.write("越過山丘,");
    }
}

4. 請求重定向

請求重定向,是指客戶端給伺服器發請求,然後伺服器告訴客戶端說。我給你一些地址。你去新地址訪問。叫請求 重定向(因為之前的地址可能已經被廢棄)

請求重定向的特點:

  • 瀏覽器的地址會發生改變
  • 兩次請求
  • 不能共享Request域中的資料
  • 不能訪問WEB-INF下的資源
  • 可以訪問工程外的資源

例子如下:訪問Response1重定向到Response2

/**
 * @author MD
 * @create 2020-07-25 10:15
 */
public class Response1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("Response 1 ");

//        // 設定響應狀態碼,表示重定向
//        resp.setStatus(302);
//
//        // 設定響應頭,說明新的地址,和web.xml裡的要對應
//        resp.setHeader("Location","http://localhost:8080/04_Servlet/response2");


        // 推薦使用
        resp.sendRedirect("http://localhost:8080/04_Servlet/response2");
    }
}

//-----------------------------------

public class Response2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Response  2 ");

        resp.getWriter().write("Response2 result !");

    }
}

對應的web.xml

<servlet>
        <servlet-name>Response1</servlet-name>
        <servlet-class>com.md.servlet.Response1</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Response1</servlet-name>
        <url-pattern>/response1</url-pattern>
    </servlet-mapping>

    <!---->
    <servlet>
        <servlet-name>Response2</servlet-name>
        <servlet-class>com.md.servlet.Response2</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Response2</servlet-name>
        <url-pattern>/response2</url-pattern>
    </servlet-mapping>

相關文章