JavaWeb詳解

Pluto372發表於2020-12-08

一、HTTP協議簡介

1、什麼是http協議

概述:

HTTP是Hyper Text Transfer Protocol的縮寫,即超文字傳輸協議。它是一種請求/響應式的協議,客戶端在與伺服器端建立連線後就可以向伺服器端傳送請求,這種請求被稱作HTTP請求,HTTP請求方法有8種:GET,POST,PUT,OPTIONS,HEAD,DELETE,TRACE,CONNECT,其中GET,POST是最為常用的兩種;伺服器端接收到請求後會做出相應的響應,這種響應被稱為HTTP響應。
在這裡插入圖片描述
預設埠號:80。

HTTP協議是一種純文字的無狀態協議!

2、http協議的工作原理

HTTP協議工作於客戶端-服務端架構之上。瀏覽器作為 HTTP客戶端通過URL向HTTP服務端即WEB伺服器傳送所有請求。

Web伺服器有:Apache伺服器,Tomcat伺服器,IIS伺服器( Internet lnformation Services)等。

Web伺服器根據接收到的請求後,向客戶端傳送響應資訊。

3、使用程式獲取網頁內容示例

public class HttpRequest {
    public static void main(String[] args) throws IOException {
        //與伺服器建立連線,並指定連線的埠號
        Socket socket = new Socket("14.215.177.39",80);
        PrintWriter out = new PrintWriter(socket.getOutputStream());
        //傳送請求內容
        out.println("GET / HTTP/1.1");  //請求行。採用GET方式請求
        out.println("Host:edu-learn4fun.com");
        out.println("Content-Type:text/html");
        out.println();  //空行
        out.flush();
        //接受伺服器響應內容
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String str = "";
        while((str = reader.readLine())!=null){
            System.out.println(new String(str.getBytes("GBK"),"utf-8"));
        }
        reader.close();
        out.close();
        socket.close();
    }
}

4、HTTP協議常見狀態

200 一切正常(所有狀態正常)

301 資源(網頁等)被永久轉移到其它URL

404 資源找不到。(首先去檢查一下所寫的路徑是否正確)

500 伺服器內部錯誤(程式出現異常,首先去檢視異常資訊以定位錯誤位置)

Web伺服器

Web伺服器主要用來接收客戶端傳送的請求和響應客戶端請求。

1、Tomcat(Apache)( 我們主要擼這隻貓 ):當前應用最廣的JavaWeb伺服器;

2、JBoss(Redhat紅帽):支援JavaEE,應用比較廣EJB容器 –> SSH輕量級的框架代替

3、GlassFish(Orcale):Oracle開發JavaWeb伺服器,應用不是很廣;

4、Resin(Caucho):支援JavaEE,應用越來越廣;

5、Weblogic(Orcale):要錢的!支援JavaEE,適合大型專案;

6、Websphere(IBM):要錢的!支援JavaEE,適合大型專案

二、servlet介紹

1、我的第一個servlet

涉及的技術知識點

1、Servlet

2、Request請求物件

3、Response響應物件

Servlet開發規則

實際編碼通過繼承HttpServlet來完成Servlet的開發

public class TestServlet extends HttpServlet{
}

Servlet類的相關方法:

doGet Servlet中用於處理 get請求的方法

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

doPost Servlet中用於處理post請求的方法

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

service
①在Servlet的頂層實現中,在service方法中呼叫的具體的doGet或者是doPost
②在實際開發Servlet的過程中,可以選擇重寫doGet以及doPost 或者 直接重寫service方法來處理請求。

java程式:

public class HelloWorld extends HttpServlet {

    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //向客戶端響應一個HelloWorld
        PrintWriter out = resp.getWriter();
        out.println("HelloWorld");  //向客戶端寫內容
        System.out.println("service.......");
    }
}

.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

<!--    配置servlet節點 順序不能變-->
    <servlet>
        <!-- servlet的名稱,可以隨便取,但是要注意servlet的名稱不能重複-->
        <servlet-name>helloWorld</servlet-name>
        <!-- servlet對於的類的全名稱。包名+類名-->
        <servlet-class>com.servlet.test01.HelloWorld</servlet-class>
    </servlet>

    <servlet-mapping>
        <!-- servlet name節點內容需要和servlet節點中的name屬性一致-->
        <servlet-name>helloWorld</servlet-name>
<!--        配置訪問路徑。這裡"/"表示專案的根目錄-->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

web.xml檔案。用於描述整個web應用的資訊的。

2、什麼是servlet

Servlet是執行在伺服器上的java類。它可以接收客戶端的請求,並向客戶端做出響應。

servlet的體系結構:

在這裡插入圖片描述

說明:
1、開發中我們從 HttpServlet繼承。

2、Servlet的組成部分:

 	- Servlet的主體部分: (servlet介面-->GenericServlet-->HttpServlet-->OurServlet)
 	- Servlet需要初始化,那麼就需要有初始化引數。這時就有了一個配置物件:
 	- ServletConfigServlet要執行,需要一個執行的環境。這是就需要一個上下文物件:
 	- ServletContextServlet要獲取客戶端的請求,就需要有一個請求物件:ServletRequest
 	- Servlet需要向客戶端響應訊息,就需要有一個響應物件: ServletRespons

3、servlet的生命週期

public class HelloWorld extends HttpServlet {

    public HelloWorld() {
        System.out.println("構造方法.......");
    }
    @Override
    public void destroy() {
        System.out.println("destroy.......");

        super.destroy();
    }

    @Override
    //初始化
    public void init() throws ServletException {
        System.out.println("init.......");
        super.init();
    }

    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //向客戶端響應一個HelloWorld
        PrintWriter out = resp.getWriter();
        out.println("HelloWorld");  //向客戶端寫內容
        System.out.println("service.......");
    }
}

.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

<!--    配置servlet節點 順序不能變-->
    <servlet>
        <!-- servlet的名稱,可以隨便取,但是要注意servlet的名稱不能重複-->
        <servlet-name>helloWorld</servlet-name>
        <!-- servlet對於的類的全名稱。包名+類名-->
        <servlet-class>com.servlet.test01.HelloWorld</servlet-class>
    </servlet>

    <servlet-mapping>
        <!-- servlet name節點內容需要和servlet節點中的name屬性一致-->
        <servlet-name>helloWorld</servlet-name>
<!--        配置訪問路徑。這裡"/"表示專案的根目錄-->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

</web-app>

第一次執行結果:
在這裡插入圖片描述

重新整理頁面:

在這裡插入圖片描述

分析:

現象:構造方法和init方法只執行了一次(第一次執行的時候執行的),後面一次訪問沒有在執行構造方法和init方法。

說明:每次訪問其實都是訪問的是同一個servlet例項。

執行順序:構造方法->init方法->servlet->doGet

說明:通過servlet的生命週期的說明,可以看出servlet是一個單例類。
在這裡插入圖片描述

4、get、post

get和post是HTTP請求的兩種基本方法(請求方法一共有8種),他們本質上就是TCP連結,並無差別。但是由於HTTP的規定和瀏覽器/伺服器的限制,導致他們在應用過程中體現出一些不同。

GET和POST有一個重大的區別

  • 簡單說:GET產生一個TCP資料包;POST產生兩個TCP資料包。

  • 複雜說:對於GET方式的請求,瀏覽器會把header和data一起傳送出去,伺服器響應200(狀態碼);對於POST請求,瀏覽器先傳送header,伺服器響應100(已經收到請求的第一部分,正在等待其餘部分),瀏覽器再次傳送data,伺服器返回200。

基本區別
在這裡插入圖片描述

get、post的選擇

post:

若符合下列任一情況,則用POST方法(如果要修改服務上的資料,那麼選擇POST):

  • 請求的結果有持續性的副作用,例如,資料庫內新增新的資料行。
  • 需要提交的資料量比較大時。
  • 要傳送的資料不是採用7位的ASCl編碼,例如二進位制資料等。

get:

若符合下列任一情況,則用GET方法(查詢伺服器上的資料選擇GET):

  • 請求是為了查詢資源,HTML表單資料僅用來幫助搜尋。

  • 請求結果無持續性的副作用。

  • 收集的資料及HTML表單內的輸入欄位名稱的總長不超過2048個字元。

5、servlet中文亂碼問題

在頁面提交的時候,和 servlet進行獲取的時候的編碼格式不統一造成的。tomcat 預設的編碼格式:ISO-8859-1,而這種編碼方式是不支援中文的。所以會出現中文亂碼。

解決方案:在接收和響應的時候設定固定的編碼格式為utf-8。

解決post請求亂碼問題

		//設定請求物件編碼格式
        request.setCharacterEncoding("utf-8");
        //設定響應物件編碼格式
        response.setCharacterEncoding("utf-8");
        //設定響應內容的型別,
		//為保證servlet向客戶端響應的訊息不會有亂碼
        response.setContentType("text/html");

在這裡插入圖片描述

附登錄檔單原始碼:

regist.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊</title>
</head>
<body>
<h1>使用者註冊</h1>
<form action="/WebStudy01/reg" method="post">
    <table>
        <tr>
            <th>使用者名稱:</th>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <th>密碼:</th>
            <td><input type="password" name="userpwd"></td>
        </tr>
        <tr>
            <th>性別:</th>
            <td>
                <select name="gender">
                    <option value=""></option>
                    <option value=""></option>
                </select>
            </td>
        </tr>

        <tr>
            <th>提交:</th>
            <td>
                <input type="submit">
            </td>
        </tr>
    </table>
</form>
</body>
</html>

java:

public class Regist extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //設定請求編碼格式
        request.setCharacterEncoding("utf-8");
        //設定響應編碼格式
        response.setCharacterEncoding("utf-8");
        //設定響應內容的型別,
        response.setContentType("text/html");

        /*
        獲取表單資料
        呼叫request請求物件的getParameter方法,引數和表單控制元件中name屬性保持一致
         */public class Regist extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //設定請求編碼格式
        request.setCharacterEncoding("utf-8");
        //設定響應編碼格式
        response.setCharacterEncoding("utf-8");
        //設定響應內容的型別,
        response.setContentType("text/html");

        //響應資料到客戶端
        PrintWriter out = response.getWriter();

        /*
        獲取表單資料
        呼叫request請求物件的getParameter方法,引數和表單控制元件中name屬性保持一致
         */
        String username = request.getParameter("username");
        String userpwd = request.getParameter("userpwd");
        String gender = request.getParameter("gender");
        String[] singers = request.getParameterValues("singer");
		
        //使用列舉
        Enumeration<String> names = request.getParameterNames();
        while (names.hasMoreElements()){
            out.println(names.nextElement()+"<br>");
        }
		
        //使用map鍵值對
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
        Iterator<Map.Entry<String, String[]>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, String[]> next = iterator.next();
            out.println(next.getKey()+"=="+ Arrays.toString(next.getValue())+"<br>");
        }

        out.println("使用者名稱:"+username+"<br>");
        out.println("密碼:"+userpwd+"<br>");
        out.println("性別:"+gender+"<br>");

        for (String str: singers) {
            out.println(str+"\t");
        }
    }
}
        String username = request.getParameter("username");
        String userpwd = request.getParameter("userpwd");
        String gender = request.getParameter("gender");

        //響應資料到客戶端
        PrintWriter out = response.getWriter();
        out.println("使用者名稱:"+username+"<br>");
        out.println("密碼:"+userpwd+"<br>");
        out.println("性別:"+gender+"<br>");
    }
}

先在URL位址列後邊加註冊網頁–>regist.html,新增註冊資訊後會跳轉響應介面。

配置Servlet:

<!--    配置使用者註冊,表單提交Servlet-->
    <servlet>
        <servlet-name>reg</servlet-name>
        <servlet-class>com.servlet.study01.Regist</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>reg</servlet-name>
        <url-pattern>/reg</url-pattern>
    </servlet-mapping>

解決get請求亂碼問題

String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"),"utf-8");

6、請求轉發和重定向:

需求:登入頁面將登入資訊提交到servlet中,如果登入成功則需要跳轉到歡迎頁面。

6.1 採用重定向方式:

1、登入介面程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登入</title>
</head>
<body>
    <div>
        <form action="/WebStudy01/login" method="post">
            <div>
                使用者名稱:<input type="text" name="username">
            </div>
            <div>
                密碼:<input type="password" name="password">
            </div>
            <div>
                <input type="submit" value="登入">
            </div>
        </form>
    </div>
</body>
</html>

2、java程式碼:

public class Login extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //設定請求編碼格式
        request.setCharacterEncoding("utf-8");
        //設定響應編碼格式
        response.setCharacterEncoding("utf-8");
        //設定響應內容的型別,
        response.setContentType("text/html");

        //獲取使用者和密碼
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //登入成功轉到歡迎介面
        //重定向
        response.sendRedirect("/WebStudy01/Welcome.html");
    }
}

配置servlet:

<!--    配置使用者登入Servlet-->
<servlet>
    <servlet-name>login</servlet-name>
    <servlet-class>com.servlet.study01.Login</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>login</servlet-name>
    <url-pattern>/login</url-pattern>
</servlet-mapping>

重定向過程示意圖:
在這裡插入圖片描述

說明:

  • 使用語句:response.sendRedirect("/WebStudy01/Welcome.html");
  • 重定向使用的是response響應物件,說明重定向是有伺服器向客戶端傳送一個響應資訊。
  • 重定向的本質是:由伺服器告訴客戶端,你在去請求另一個資源。
  • 重定向,客戶端向伺服器傳送了兩次請求。兩次請求斌沒有什麼聯絡,也是說可以請求任意網際網路資源(全路徑)
  • 絕對路徑中的"/"是伺服器中的根路徑

6.2 採用請求轉發方式:

修改程式碼:

//請求轉發
request.getRequestDispatcher("/Welcome.html").forward(request, response);

只需要將重定位程式碼刪除,寫這句即可。

圖示:
在這裡插入圖片描述

說明:

  • 請求轉發全過程只發起了一次請求;中間轉發了多少次,對客戶端來說最後反饋的訊息都是從所請求的物件來的。
  • 請求轉發,可以將請求的內容以及處理的結果一起轉發給下一個節點。
  • 路徑問題:請求轉發 getRequestDispatcher( “/welcome.jsp”)中的“/”表示專案的根路徑。

6.3 採用請求轉發和重定向的區別:

在這裡插入圖片描述

7、會話技術

會話技術:

會話技術幫助伺服器儲存客戶端狀態,來區分客戶端

一次會話:從開啟瀏覽器訪問站點的某些地址連結,到關閉瀏覽器,稱為一次會話

7.1 Cookie:客戶端會話技術

程式碼:

public class TestCookie extends HttpServlet {

    //讀cookie
    /*
    *cookie從客戶端來的,資料是從客戶端到服務端-->使用request物件來獲取cookie
    */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html");

        PrintWriter out = response.getWriter();

        //讀cookie
        Cookie[] cookies = request.getCookies();
        for(Cookie c:cookies){
            //獲取cookie的name
            if(c.getName().equals("uname")){
                //URLDecoder.decode() url 解碼
                out.println(URLDecoder.decode(c.getValue(),"utf-8"));
            }
        }
   }
    //寫cookie
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html");

        String username = request.getParameter("username");
        //URLEncoder.encode() url編碼
        Cookie cookie = new Cookie("uname", URLEncoder.encode(username,"utf-8"));
        //設定cookie過期時間,單位是秒
        cookie.setMaxAge(24*60*60);	//一天
        response.addCookie(cookie);
        PrintWriter out = response.getWriter();
		//a標籤預設提交方式是get提交
        out.println("<a href='/WebStudy01/cookie'>檢視cookie</a>");
        }
}

.xml 檔案配置:

  <!-- 測試cookie-->
    <servlet>
        <servlet-name>cookie</servlet-name>
        <servlet-class>com.servlet.study01.TestCookie</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>cookie</servlet-name>
        <url-pattern>/cookie</url-pattern>
    </servlet-mapping>
注意事項:
  • 關於cookie,無論是名字還是值,都不能包含特殊字元和空格。

  • 一般在儲存值的時候,都需要進行URL編碼。

  • 刪除cookie:只需要設定過期時間為負數。

  • cookie的使用示意圖:
    在這裡插入圖片描述

7.2 Session:服務端會話技術

1、為什麼要使用sessin:

首先是在如果要去多個頁面中共享資料,那麼在不使用session的情況下,就只能通過請求轉發的方式將資料帶到下一個介面。然而重定向的方式就不行了。其次,記錄使用者資訊,如果沒有session就只能記得cookie中,但是cookie又是記錄在瀏覽器客戶端的,並且以文字形式存放的。不僅存放內容有侷限性,而且安全性也有很大問題。

2、什麼是session

session(會話)是在一段時間,一個客戶端與伺服器的一 連串相關的互動過程。(說明:“一段時間內”—>session具有時效性)

3、程式碼:

public class TestSession extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/html");

            //獲取使用者名稱和密碼
            String username = request.getParameter("username");
            String password = request.getParameter("password");

            //記錄使用者資訊到session
        /**
         *getSession方法說明:
         * 有兩個引數過載。getSession(boolean引數)和getSession();
         * 有參:
         *      true:去request中獲得Session,如果Session不存在則建立一個新的Session並返回
         *            如果Session存在,則直接返回已存在的Session
         *      false:獲取Session,如果Session不存在,那麼返回null
         * 無參:<==>getSession(true)
         */
        HttpSession session = request.getSession();
        //將資料儲存到session中(儲存基本資訊)
        session.setAttribute("username", username);
        session.setAttribute("password", password);

        //注意:getAttribute(String string)
        System.out.println((String)session.getAttribute("username"));
        System.out.println((String)session.getAttribute("password"));

        //儲存使用者登入狀態,一般會儲存一個使用者物件
//        User u = new User(username,password);
//        session.setAttribute("user", u);

        //進入到welcome介面
        request.getRequestDispatcher("/Welcome.html").forward(request, response);
    }
}

.xml檔案配置:

 <!-- 測試session-->
    <servlet>
        <servlet-name>session</servlet-name>
        <servlet-class>com.servlet.study01.TestSession</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>session</servlet-name>
        <url-pattern>/session</url-pattern>
    </servlet-mapping>

4、設定session過期時間:

什麼是session過期時間:

​ 從最後一次訪問session開始計時,如果在過期時間之內沒有對session進行再次訪問,那麼系統會將session物件回收。

設定方式1:在程式中設定
//設定session的過期時間(單位:秒),一般不常用
session.setMaxInactiveInterval(60*60);
設定方式2:在專案的web.xml中進行設定(一般設定在最上邊)
  //設定session過期時間(單位:分鐘)
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>
設定方式3:在Tomat的web.xml中進行設定(設定方式與2相同)

在這裡插入圖片描述

說明:
1、在tomcat中進行設定,一般我們稱為session 的預設過期時間(一般都是30分鐘)。他會對所有釋出到這個伺服器上的專案起作用。

2、在專案的web.xml中設定,只會對本專案起作用。(優先順序高於在tomcat中設定)

3、在程式中設定,一般是在臨時需要增加session過期時間的時候進行設定。(例如:在教務系統中錄入成績的時候。當然現在一般不會採用這種方式,有更好的方式解決)

4、session的原理:
在這裡插入圖片描述
在這裡插入圖片描述

7.3 application / serveletContext

1、為什麼是serveletContext:

WEB容器在啟動時,它會為每個WEB應用程式都建立一個對應的ServletContext物件,它代表當前web應用。

servletConfig物件中維護了ServletContext物件的引用,開發人員在編寫servlet時,可以通過ServletConfig.getServletContext()方法獲得servletContext物件。也可以直接在servlet中呼叫getServeltContext()方法來直接獲取ServletContext物件。

由於一個WEB應用中的所有servlet共享同一個ServletContext物件,因此 servlet物件之間可以通過ServletContext物件來實現通訊。ServletContext物件通常也被稱之為 context或者application域物件。

2、application的特點:

1、存放在伺服器端

2、所有使用者公用

3、以key-value形式存放

4、可以存放任何物件

3、程式碼:
public class TestApplication extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html");

        //獲取servletContext物件
        ServletContext application = getServletContext();
        //寫application物件(和servlet的方式一樣)
        String username = request.getParameter("username");
        application.setAttribute("username",username);
        //讀 返回結果是object型別,需要強制轉型
        System.out.println((String)(application.getAttribute("username")));
    }
}

.xml檔案配置:

   <!-- 測試application-->
    <servlet>
        <servlet-name>application</servlet-name>
        <servlet-class>com.servlet.study01.TestApplication</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>application</servlet-name>
        <url-pattern>/app</url-pattern>
    </servlet-mapping>

7.4cookie、session在這裡插入圖片描述

、application的區別

8、過濾器

基本思想和結構

1、Filtering 的基本思想:
將jsp,servlet,html看作資源,容器用來處理這些資源,併為資源提供服務。因此,可以在處理這些資源之前或之後,通過過濾器增加一些通用功能;比如:登入許可權驗證、字元編碼轉換、資源訪問許可權控制、敏感詞彙過濾。而且這些過濾器可以形成一個鏈

在這裡插入圖片描述

2、過濾器結構:
在這裡插入圖片描述

編寫過濾器

public class EncodeFiter implements Filter {
    private String encode = "";
    private String content = "";
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
         encode = filterConfig.getInitParameter("encode");
         content = filterConfig.getInitParameter("content");

    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding(encode);
        response.setCharacterEncoding(encode);
        response.setContentType(content);
        //過濾放行
        chain.doFilter(request, response);
    }
}

注意事項:

  • 過濾器本身是一個類,必須實現Filter介面
  • 在doFilter方法的最後一句,必須要有chain.doFilter(request, response);
  • 初始化引數不能寫死,而要放在配置檔案中。
  • 過濾器在伺服器啟動時就會被載入。

2、編寫配置檔案:

<!--    配置過濾器-->
    <filter>
        <filter-name>filter</filter-name>
        <filter-class>com.servlet.study.TestFilter</filter-class>
        <!--    配置初始化屬性-->
        <init-param>
            <param-name>encode</param-name>
            <param-value>utf-8</param-value>
        </init-param>

        <init-param>
            <param-name>context</param-name>
            <param-value>text/html</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

監聽器

監聽器原理:

1、監聽器的概念:

web監聽器是一種Servlet中的特殊的類,它們能幫助開發者監聽web中的特定事件,比如ServletContext,HttpSession,ServletRequest的建立和銷燬;變數的建立、銷燬和修改等。可以在某些動作前後增加處理,實現監控。(觀察者模式的一種應用)

2、監聽器常用的用途

1.通常使用web 監聽器做以下的內容:2.統計線上人數,利用HttpSessionLisener

3.載入初始化資訊:利用ServletContextListener

4.統計網站訪問量

5.實現訪問監控(監聽request物件)—stuts2通過監聽器來實現訪問控制的3、監聽器的介面

3、實現線上人數統計功能

1、實現原理:
監聽session物件,當session建立的時候認為線上人數+1;當session銷燬的時候認為線上人數-1
2、建立監聽器:

public class OnlineListener implements HttpSessionListener {
    /**
     * session 建立時觸發
     */
    @Override
    public void sessionCreated(HttpSessionEvent sessionEvent) {
          //線上人數
        ServletContext application = sessionEvent.getSession().getServletContext();

        if(application.getAttribute("count")==null){
             application.setAttribute("count",0);
        }else {
            Integer c1 =  (Integer)application.getAttribute("count");
            application.setAttribute("count",c1+1);
        }

    }
    /**
     * session 銷燬時觸發
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent sessionEvent) {
        ServletContext application = sessionEvent.getSession().getServletContext();
        Integer c1 = (Integer)(application.getAttribute("count")) ;
        application.setAttribute("count", c1-1);
    }
}
public class TestSession extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

         //獲取使用者名稱和密碼
        String username = request.getParameter("username");
        String password = request.getParameter("password");

         //記錄使用者資訊到session
        HttpSession session = request.getSession();
        //將資料儲存到session中(儲存基本資訊)
        session.setAttribute("username", username);
        session.setAttribute("password", password);
        //監聽線上人數
        PrintWriter out = response.getWriter();
        out.println("線上:"+username);
        out.println("<br>線上人數:"+getServletContext().getAttribute("count"));

        System.out.println((String)session.getAttribute("username"));
        System.out.println((String)session.getAttribute("password"));

    }
}

.xml檔案配置:

<!--配置監聽器-->
<listener>
    <listener-class>com.servlet.study01.OnlineListener</listener-class>
</listener>

9、XML

xml簡介:

  1. XML–可擴充套件標記語言eXtensible Markup Language
  2. 由W3C組織釋出,目前推薦遵守的是W3C組織於2000年釋出的XML1.0規範
  3. XML的使命,就是以一個統一的格式,組織有關係的資料,為不同平臺下的應用程式服務
  4. XML用來傳輸和儲存資料,HTML用來顯示資料
  5. XML沒有預定義標籤,均為自定義標籤

xml用途:

  1. 配置檔案
    JavaWeb中的web.xml
    C3P0中的c3p0-config.xml
  2. 資料交換格式
    Ajax
    WebService
  3. 資料儲存
    儲存關係型資料

xml基本語法

  1. XML文件組成
    ①XML宣告
    version屬性指定XML版本,固定值是1.0
    encoding指定的字符集,是告訴解析器使用什麼字符集進行解碼,而編碼是由文字 編輯器決定的
    ②CDATA區
    當XML文件中需要寫一些程式程式碼、SQL語句或其他不希望XML解析器進行解析 的內容時,就可以寫在CDATA區中
    XML解析器會將CDATA區中的內容原封不動的輸出
    CDATA區的定義格式:<![CDATA[…]]>
  2. 語法規則
    ①XML宣告要麼不寫,要寫就寫在第一行,並且前面沒有任何其他字元
    ②只能有一個根標籤
    ③標籤必須正確結束
    ④標籤不能交叉嵌
    ⑤嚴格區分大小寫
    ⑥屬性必須有值,且必須加引號
    ⑦標籤不能以數字開頭
    ⑧註釋不能巢狀

xml解析

  1. XML解析是指通過解析器讀取XML文件,解釋語法,並將文件轉化成物件
  2. 常用的解析方式
    DOM(Document Object Model)
    SAX(Simple API for XML)
  3. DOM 和SAX解析的對比

在這裡插入圖片描述

  1. Dom4j解析示例

    解析:

    //1.建立解析器物件
    SAXReader saxReader = new SAXReader();
    //2.解析xml檔案獲取document物件
    Document document = saxReader.read("students.xml");
    //3.得到根元素
    Element root = document.getRootElement();
    

10、Ajax

  1. AJAX 是 Asynchronous JavaScript And XML 的簡稱。直譯為,非同步的JS和XML。
  2. AJAX的實際意義是,不發生頁面跳轉、非同步載入內容並改寫頁面內容的技術。
  3. AJAX也可以簡單的理解為通過JS向伺服器傳送請求。

非同步處理

  1. 同步處理
    AJAX出現之前,我們訪問網際網路時一般都是同步請求,也就是當我們通過一個頁面向伺服器傳送一個請求時,在伺服器響應結束之前,我們的整個頁面是不能操作的,也就是直觀上來看他是卡主不動的。
    這就帶來了非常糟糕的使用者體驗。首先,同步請求時,使用者只能等待伺服器的響應,而 不能做任何操作。其次,如果請求時間過長可能會給使用者一個卡死的感覺。最後,同步請求的最大缺點就是即使整個頁面中只有一小部分內容發生改變我們也要重新整理整個頁面。
  2. 非同步處理
    而非同步處理指的是我們在瀏覽網頁的同時,通過AJAX向伺服器傳送請求,傳送請求的過程中我們瀏覽網頁的行為並不會收到任何影響,甚至主觀上感知不到在向伺服器傳送請求。當伺服器正常響應請求後,響應資訊會直接傳送到AJAX中,AJAX可以根據伺服器響應的內容做一些操作。
    使用AJAX的非同步請求基本上完美的解決了同步請求帶來的問題。首先,傳送請求時不會影響到使用者的正常訪問。其次,即使請求時間過長,使用者不會有任何感知。最後,AJAX可以根據伺服器的響應資訊區域性的修改頁面,而不需要整個頁面重新整理。

非同步請求物件

XMLHttpRequest物件是AJAX中非常重要的物件,所有的AJAX操作都是基於該物件的。
XMLHttpRequest物件用來封裝請求報文,我們向伺服器傳送的請求資訊全部都需要封裝到該物件中。
這裡需要稍微注意一下,XMLHttpRequest物件並沒有成為標準,但是現在的主流瀏覽器都支援該物件,而一些如IE6的老版本瀏覽器中的建立方式有一些區別,但是問題不大。

使用JQuery框架來傳送非同步請求

  1. JQuery是當前比較主流的 JavaScript 庫,封裝了很多預定義的物件和實現函式,幫助使用者建立有高難度互動的頁面,並且相容大部分主流
    的瀏覽器.
    JQuery對同樣提供了對Ajax的支援,可以更加方便快速的進行Ajax的開發,相關的方法有$.get $.post $.ajax等.
    JQuery的物件的本質就是dom物件的陣列/集合

  2. JQuery物件與dom物件的相互轉換
    JS轉JQuery: var jObj = $(dObj);
    JQuery轉JS: var dObj = jObj[0] 或者 var dObj = jObj.get(0)

  3. . g e t 方 法 和 .get方法和 .get.post方法

  4. $.ajax方法
    jQuery 底層 AJAX 實現。簡單易用的高層實現見 . g e t , . p o s t 等 。 . p o s t 等 。 . ∗ p ∗ ∗ o ∗ ∗ s ∗ ∗ t ∗ 等 。 . a j a x ( ) 返 回 其 創 建 的 X M L H t t p R e q u e s t 對 象 。 大 多 數 情 況 下 你 無 需 直 接 操 作 該 函 數 , 除 非 你 需 要 操 作 不 常 用 的 選 項 , 以 獲 得 更 多 的 靈 活 性 。 最 簡 單 的 情 況 下 , .get, . p o s t 等 。 .post 等。.*p**o**s**t*等。.ajax() 返回其建立的 XMLHttpRequest 物件。大多數情況下你無需直接操作該函式,除非你需要操作不常用的選項,以獲得更多的靈活性。最簡單的情況下, .get,.post.post.post.ajax()XMLHttpRequest.ajax()可以不帶任何引數直接使用。
    $.ajax方法的引數

  5. 具體的示例程式碼

    $.ajax({
    
        url:"http://www.microsoft.com", //請求的url地址
    
        dataType:"json", //返回格式為json
    
        async:true,//請求是否非同步,預設為非同步,這也是ajax重要特性
    
        data:{"id":"value"}, //引數值
    
        type:"GET", //請求方式
    
        beforeSend:function(){
            //請求前的處理
        },
    
        success:function(req){
            //請求成功時處理
        },
    
        complete:function(){
            //請求完成的處理
        },
        error:function(){
    
            //請求出錯處理
        }
    
    });
    

11、JSP

定義:

JSP(Java Server Pages)是JavaWeb伺服器端的動態資源,它與html頁面的作用是相同的,顯示資料和獲取資料。

jsp: 作為請求發起頁面,例如顯示錶單、超連結。
作為請求結束頁面,例如顯示資料。

Servlet:
作為請求中處理資料的環節。

jsp的組成

  • jsp = html + java指令碼 + jsp標籤(指令)

  • jsp中可直接使用的物件一共有9個,被稱之為9大內建物件

  • 3種java指令碼:
    <%…%>:寫java程式碼片段,(類似方法)
    <%=…%>:用於輸出,用於輸出一條表示式(或變數)的結果。
    <%!…%>:宣告,用來建立類的成員變數和成員方法(類似與類)

  • jsp註釋:<%– … –%>

當伺服器把jsp編譯成java檔案時已經忽略了註釋部分!
jsp程式碼:

<%@ page language="java" import="java.util.*" import="java.text.*"
	contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>JSP Hello World</title>
		<style type="text/css">
			p{
				font-size: 35px;
				font-family: 宋體;
				color: blue;
			}
		</style>
	</head>
	<body>
		<h2 align="left" style="color: red;">無所成之事不可逆也</h2>
		<h2 align="left" style="color: red;">斷劍重鑄之日,騎士歸來之時</h2>

		<p>您好 JSP</p>
		
		<%--以下為Java程式碼--%>
		<%
		   Date date=new Date();
	       SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	       String time=simpleDateFormat.format(date);
           out.println(time);
        %>
	</body>
</html>

12、JSTL

Java Server Pages Standard Tag Libray(JSTL):JSP 標準標籤庫,是一個定製標籤類庫的集合,用 於解決一些常見的問題,例如迭代一個對映或者集合、條件測試、XML 處理,甚至資料庫和訪問資料庫 操作等。

首先我們需要去官網下載最新版本的DTD檔案http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/ 並且將檔案中的jstl.jar拷貝到專案的lib中。

jstl核心標籤

使用taglib指令匯入標籤庫:

除了JSP動作標籤外,使用其他第三方的標籤庫都需要:

  • 導包;
  • 在使用標籤的JSP頁面中使用taglib指令匯入標籤庫;

下面是匯入JSTL的core標籤庫:

<%@ taglib prefix="c"uri="http://java.sun.com/jstl/core" %>
  • prefix=“c”:指定標籤庫的字首,這個字首可以隨便給值,但大家都會在使用core標籤庫時指定字首為c;
  • uri=“http://java.sun.com/jstl/core”:指定標籤庫的uri,它不一定是真實存在的網址,但它可以讓JSP找到標籤庫的描述檔案;

4、core標籤庫常用標籤:

(1)out和set標籤

<c:out value=”aaa”/>輸出aaa字串常量
<c:out value=”${aaa}”/>與${aaa}相同
<c:out value=”${aaa}” default=”xxx”/>當${aaa}不存在時,輸出xxx字串
<%request.setAttribute(“a”,“”);%><c:out value="${a }" default=“xxx” escapeXml=“false” />當escapeXml為false,不會轉換“<”、“>”。這可能會受到JavaScript攻擊。
<c:set var=”a” value=”hello”/>在pageContext中新增name為a,value為hello的資料。
<c:set var=”a” value=”hello” scope=”session”/>在session中新增name為a,value為hello的資料。

(2)remove標籤

<c:remove var=“a” scope=”page”/>刪除pageContext中name為a的資料

(3)url標籤:該標籤會在需要重寫URL時新增。

<c:url value="/"/>輸出上下文路徑:/專案名/
<c:url value="/" var=“a” scope=“request”/>把本該輸出的結果賦給變數a。範圍為request
<c:url value="/AServlet"/>輸出:/專案名/AServlet
<c:url value="/AServlet"><c:param name=“username” value=“abc”/><c:param name=“password” value=“123”/>輸出:/專案名/AServlet?username=abc&password=123 如果引數中包含中文,那麼會自動使用URL編碼!

(4)if標籤:

if標籤的test屬性必須是一個boolean型別的值,如果test的值為true,那麼執行if標籤的內容,否則不執行。

<c:set var="a" value="hello"/>
<c:if test="${not empty a }">
	<c:out value="${a }"/>
</c:if>

(5)choose標籤:

choose標籤對應Java中的if/else if/else結構。when標籤的test為true時,會執行這個when的內容。當所有when標籤的test都為false時,才會執行otherwise標籤的內容。

<c:set var="score" value="${param.score }"/>
<c:choose>
	<c:when test="${score > 100 || score < 0}">錯誤的分數:${score }</c:when>
	<c:when test="${score >= 90 }">A級</c:when>
	<c:when test="${score >= 80 }">B級</c:when>
	<c:when test="${score >= 70 }">C級</c:when>
	<c:when test="${score >= 60 }">D級</c:when>
	<c:otherwise>E級</c:otherwise>
</c:choose>

(6)forEach標籤:

forEach當前就是迴圈標籤了,forEach標籤有多種兩種使用方式:

  • 使用迴圈變數,指定開始和結束值,類似for(int i = 1; i <= 10; i++) {};
  • 迴圈遍歷集合,類似for(Object o : 集合);

迴圈變數:

<c:set var="sum" value="0" /> 
<c:forEach var="i" begin="1" end="10"> 
	<c:set var="sum" value="${sum + i}" /> 
</c:forEach>
<c:out value="sum = ${sum }"/>
<c:set var="sum" value="0" />
<c:forEach var="i" begin="1" end="10" step ="2">
	<c:set var="sum" value="${sum + i}" />
</c:forEach>
<c:out value="sum = ${sum }"/>

遍歷集合或陣列方式:

<%
String[] names = {"zhangSan", "liSi", "wangWu", "zhaoLiu"};
pageContext.setAttribute("ns", names);
%>
<c:forEach var="item" items="${ns }">
	<c:out value="name: ${item }"/><br/>
</c:forEach>

遍歷List:

<%
	List<String> names = new ArrayList<String>();
	names.add("zhangSan");
	names.add("liSi");
	names.add("wangWu");
	names.add("zhaoLiu");
	pageContext.setAttribute("ns", names);
%>
<c:forEach var="item" items="${ns }">
	<c:out value="name: ${item }"/><br/>
</c:forEach>

遍歷Map:

<%
	Map<String,String> stu = new LinkedHashMap<String,String>();
	stu.put("number", "N_1001");
	stu.put("name", "zhangSan");
	stu.put("age", "23");
	stu.put("sex", "male");
	pageContext.setAttribute("stu", stu);
%>
<c:forEach var="item" items="${stu }">
	<c:out value="${item.key }: ${item.value }"/><br/>
</c:forEach>

forEach標籤還有一個屬性:varStatus,這個屬性用來指定接收“迴圈狀態”的變數名,例如:<forEach varStatus=”vs” …/>,這時就可以使用vs這個變數來獲取迴圈的狀態了。

  • count:int型別,當前以遍歷元素的個數;
  • index:int型別,當前元素的下標;
  • first:boolean型別,是否為第一個元素;
  • last:boolean型別,是否為最後一個元素;
  • current:Object型別,表示當前專案。
<c:forEach var="item" items="${ns }" varStatus="vs">
	<c:if test="${vs.first }">第一行:</c:if>
	<c:if test="${vs.last }">最後一行:</c:if>
	<c:out value="第${vs.count }行: "/>
	<c:out value="[${vs.index }]: "/>
	<c:out value="name: ${vs.current }"/><br/>
</c:forEach>

5、fmt標籤庫常用標籤:

fmt標籤庫是用來格式化輸出的,通常需要格式化的有時間和數字。

格式化時間:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
......
<%
	Date date = new Date();
	pageContext.setAttribute("d", date);
%>

<fmt:formatDate value="${d }" pattern="yyyy-MM-dd HH:mm:ss"/>

格式化數字:

<%
	double d1 = 3.5;
	double d2 = 4.4; 
	pageContext.setAttribute("d1", d1);
	pageContext.setAttribute("d2", d2);
%>
<fmt:formatNumber value="${d1 }" pattern="0.00"/><br/>

<fmt:formatNumber value="${d2 }" pattern="#.##"/>

13、EL表示式

目的:

​ 簡化jsp頁面,減少HTML程式碼與java程式碼的耦合。(減少在jsp頁面中的Java程式碼)

基本語法

${EL表示式}

運算子

" . “和” [] "。這兩個運算子都是取屬性

${user.username}

${user[“username”]}

3.執行運算

1、語法:${運算表示式}

2、常見運算子:==(eq) !=(ne) <(lt) >(gt) <=(le) >=(ge) &&(and) ||(or) !(not)

3、判斷是否為空:${empty name }

​ 作用1:判斷物件是否存在,返回true和false

​ 作用2:判斷集合陣列中是否存在元素,返回true和false

​ 作用3:判斷字串是否是空串(null),返回true和false

4、三目運算子:${name == null ? “null” : name }

EL表示式的作用域

Page --> request --> session -->application

例如: ${username}這個表示式,會首先從page 的屬性中去找username,如果找到那麼輸出;如果沒有找到,那麼繼續到request物件中去找,一直到找到為止。如果到application中都沒有找到,那麼輸出空。

例:

session.setAttribute(“uname”,“張三”);

request.setAttribute(“uname”,“李四”);

${uname}

上面這個程式輸出結果:“李四”,而不會輸出“張三”。

其他物件

物件名用法等價JSP程式碼或作用
param${param.name}request.getParameter(name)
paramValues${paramValues.name}request.getParameterValues(name)//返回一個字串陣列
header${header.name}request.getHeader(name)
headerValues${headerValues.name}request.getHeaderValues(name)
cookie${cookie.name.value}request.getCookie()
initParam${initParam.name}ServletContext.getInitparameter(name)
pageContext${pageContext.request.contextPath}獲取WEB應用(專案的根路徑)
pageContext${pageContext.request.sessionid}獲取sessionId
pageContext${pageContext.request.remoteAddr}獲取主機名

EL表示式的原理和注意點

原理:EL表示式在獲取某個物件的屬性值時,先將某個屬性值首字母變成大寫,然後加上get字首,拼接成getter方法,通過反射將該物件構建出來,然後再對該物件執行getter方法,這與私有屬性並沒有關係,

所以要注意,JavaBean的屬性名要小寫,且要有getter方法,不然會報錯。

相關文章