日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

后端学习 - JavaWeb

發布時間:2023/12/4 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 后端学习 - JavaWeb 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

技術體系

文章目錄

  • 一 HTML
    • 1 網頁的組成部分
    • 2 HTML 概述
    • 3 HTML 標簽
    • 4 常用標簽
    • 5 表單與表單的提交
  • 二 CSS
    • 1 語法格式
    • 2 使用方法
  • 三 JavaScript
    • 1 概述
    • 2 與 HTML 結合的兩種方式
    • 3 變量類型及特殊值
    • 4 關系、邏輯運算
    • 5 數組
    • 6 函數
    • 7 事件
    • 8 DOM (Document Object Model)
    • 9 DOM實例:驗證用戶名是否有效
  • 四 Tomcat
  • 五 Servlet
    • 1 舉例:向數據庫中添加表單信息
    • 2 Servlet 的繼承關系
    • 3 Servlet 的生命周期
    • 4 HTTP 協議與 Session會話跟蹤
    • 5 服務器端內部轉發、重定向
    • 6 Servlet 保存作用域
    • 7 Servlet 的 init 方法與初始化參數設置
    • 8 ServletContext
  • 六 Thymeleaf
    • 1 配置過程
    • 2 Servlet 優化 - 合并同類方法
    • 3 Servlet 優化 - dispatchedServlet
  • 七 MVC
    • 1 概念
    • 2 降低各層間的耦合 - IOC 與 DI
    • 3 IOC 與 DI 的實現過程
  • 八 Filter
    • 1 概述
    • 2 使用 Filter 實現事務的原子性
  • 九 Listener
  • 十 總結

一 HTML

1 網頁的組成部分

  • 內容(結構):在頁面中可以看到的數據。我們稱之為內容。一般使用 HTML 技術展示。
  • 表現:內容在頁面上的展示形式,比如布局,顏色,大小等等。一般使用CSS 技術實現。
  • 行為:頁面中元素與輸入設備交互的響應。一般使用 JavaScript 技術實現。

2 HTML 概述

  • Hyper Text Markup Language (超文本標記語言),網頁文件本身是一種文本文件,通過在文本文件中添加標記符,可以告訴瀏覽器如何顯示其中的內容。
  • HTML 文件不需要編譯,直接由瀏覽器進行解析執行。
  • 書寫規范:大致由 head 和 body 兩部分組成。
<html lang="en"> <!-- 頁面開始 --><head> <!-- HEAD --><meta charset="UTF-8"><title> 我的標題 </title></head><body> <!-- BODY -->hello!</body></html> <!-- 頁面結束 -->

3 HTML 標簽

  • 標簽名對大小寫不敏感。
  • 雙標簽的格式:<標簽名> 封裝的數據 </標簽名>
    單標簽的格式:<標簽名/>
  • 標簽擁有自己的屬性,分為基本屬性和事件屬性。屬性必須有值,屬性值必須加引號。
  • 雙標簽必須正確關閉,不能交叉嵌套。
  • 想顯示“轉義字符”的問題(比如想打印出左尖括號<),用實體名稱解決(對應的實體名稱是&lt;)。
<body onclick="alert('警告')"> <!-- 帶有事件屬性 -->點擊body部分會出現警告 <hr/> <!-- 單標簽 --><font color="blue"> 藍色的字體 </font> <!-- 雙標簽,帶有基本屬性 --></body>

4 常用標簽

重點是超鏈接、表格、表單

<!--標題標簽,最大是h1,最小是h6,對齊可以選擇 left/ center/ right--> <h1 align="center"> 標題 </h1><!--字體--> <font color="red" size="7"> 字體 </font><!--超鏈接,可選參數 target (_self 在當前頁面跳轉,_blank 在新頁面跳轉...)--> <a href="www.baidu.com" target="_blank"> 超鏈接 </a><!--無序列表(有序將ul改為ol)--> <ul><li> item1 </li><li> item2 </li> </ul><!--圖片img標簽是圖片標簽,用來顯示圖片src屬性可以設置圖片的路徑width屬性設置圖片的寬度height屬性設置圖片的高度border屬性設置圖片邊框大小alt屬性設置當指定路徑找不到圖片時,用來代替顯示的文本內容絕對路徑的正確格式是: http://ip:port/工程名/資源路徑 --> <img src="./imgs/1.jpg" width="100" height="200"/><!--表格table 標簽是表格標簽border 設置表格標簽width 設置表格寬度height 設置表格高度align 設置表格相對于頁面的對齊方式cellspacing 設置單元格間距tr 是行標簽th 是表頭標簽td 是單元格標簽align 設置單元格文本對齊方式b 是加粗標簽如果要實現跨行、跨列,改變 td 的 colspan、rowspan 屬性 --> <table align="center" border="1" width="300" height="300" cellspacing="0"><tr><th>1.1</th><th>1.2</th><th>1.3</th></tr><tr><td>2.1</td><td>2.2</td><td>2.3</td></tr><tr><td>3.1</td><td>3.2</td><td>3.3</td></tr> </table><!--iframe標簽,在原頁面之上顯示一個小的頁面其中的 name 屬性可以作為超鏈接的 target 屬性,點擊超鏈接后將在 iframe 中顯示--> <iframe src="1.html" width="500" height="400" name="abc"></iframe> <a href="2.html" target="abc"> 超鏈接 </a>

5 表單與表單的提交

表單類型單獨列出,可以使用 table 實現對齊。

<!-- 要順利提交表單,需要為所有項加上 value 或者 name 屬性 --><form action="http://localhost:8080" method="post">姓名:<input type="text" value="默認姓名"/></br>密碼:<input type="password" value="default"/></br><!-- name 屬性用于分組,同一組的選項互斥-->性別:<input type="radio" name="sex" checked="checked"/><input type="radio" name="sex"/></br>愛好:<input type="checkbox" checked="checked"/>跑步 <input type="checkbox"/>跳繩</br>國籍:<select><option>--請選擇--</option><option selected="selected">CHN</option><option>USA</option></select><br/>簡介:<textarea rows="10" cols="20">默認簡介</textarea><br/>附件:<input type="file"/></br><input type="reset" value="重置"><input type="submit" value="提交"></form>

  • form 標簽的 action 屬性設置提交的服務器地址,method 屬性設置提交的方式 GET(默認) 或 POST
  • GET 請求的特點是:
  • 瀏覽器地址欄中的地址是:服務器地址 + ? + 請求參數(請求參數的格式是 name=value&name=value)
  • 不安全
  • 有數據長度的限制
  • POST 請求的特點:
  • 瀏覽器地址欄中只有服務器地址(action的屬性值)
  • 相對于GET請求要安全
  • 理論上沒有數據長度的限制
  • 表單提交的時候,數據沒有發送給服務器的三種情況:
  • 表單項沒有name屬性值
  • 單選 radio 、復選 checkbox、下拉列表中的 option 標簽 都需要添加value屬性,以便發送給服務器
  • 表單項不在提交的form標簽中

二 CSS

1 語法格式

/* 標簽名選擇器,樣式綁定標簽 */ label_name { property1: val1;property2: val2; }/* id選擇器,樣式綁定具體的id,id是人為設定的,每個實例不相同*/ #id {property1: val1;property2: val2; }/* class選擇器,樣式綁定標簽分配的class,可以多個實例綁定一個class */ .class class_name {property1: val1;property2: val2; }/* 組合選擇器,選擇器間是并的關系 */ 選擇器1, 選擇器2 ... {property1: val1;property2: val2; }

2 使用方法

<head> <!-- HEAD --><meta charset="UTF-8"><title> my_title </title>/* 導入已經寫好的CSS文件(推薦) */<link rel="stylesheet" type="text/CSS" href="mycss.css">/* 或者把CSS寫到此處的 style 標簽中 */<style type="text/css">label_name { property1: val1;property2: val2;}</style></head>

三 JavaScript

1 概述

  • JS 運行在客戶端,需要運行瀏覽器來解析執行 JavaScript 代碼,和 Java 并無直接關系。
  • JS 是弱類型的語言,Java 是強類型的語言。強弱的差別在于定義變量后,變量的數據類型是否可變。
  • 特點是 交互性(信息的動態交互)、安全性(不允許直接訪問本地硬盤)、跨平臺性(只要是可以解釋 JS 的瀏覽器都可以執行,和平臺無關)。

2 與 HTML 結合的兩種方式

  • 在 HTML 文件中的 head 部分,用 script 標簽寫入;
  • 在 script 標簽中導入 JS 文件。

上述兩種方法不能寫在一個標簽里。

<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">alert('JS嵌入方式1');</script><script src="myjs.js"></script> <!-- 文件內容: alert('JS嵌入方式2'); --> </head>

3 變量類型及特殊值

關鍵字 對應類型
number數值類型
string字符串類型
object對象類型
bool布爾類型
function函數類型



特殊值 含義
undefined未定義,所有 JS 變量未賦于初始值的時候,默認值都是 undefined
null
NaN非數字非數值

4 關系、邏輯運算

  • ==比較兩個變量的值是否相等(比如,“123”==123是成立的), ===比較兩個變量的類型和值是否相等;
  • JS 中所有變量都可以作為布爾值使用,0、null、undefined、空串 都認為是 false;
  • ||(或) &&(與) 具有短路特性,返回值為第一個導致結果的變量。

5 數組

  • 數組不會出現越界的問題。在超過原來長度的位置賦值時,會進行自動擴容(讀操作不會擴容)。
// 數組定義 var arr = [1, "abc"];// 數組遍歷 for (var i = 0; i < arr.length; i++) {alert(arr[i]) }// 自動擴容,下標2、3、4的元素均為undefined arr[5] = 2;

6 函數

  • JS 不允許函數重載。一個函數名只能對應一個具體實現。
function noParam() {alert('無參函數調用');}noParam();function withParam(a, b) {alert("有參函數調用" + a + b);}withParam(1, 2);function withReturn(a, b) {alert("有參有返回值函數調用");return a + b;}alert(withReturn(10, 5));
  • 隱形參數 arguments 將所有實參組織為一個數組,通過下標可以訪問所有參數。
function testInvisibleParams() {var res = 0;for (var i = 0; i < arguments.length; i++) {res += arguments[i];}return res;}alert(testInvisibleParams(1, 2, 3, 4));

7 事件

  • 常用事件
事件操作
onload(加載完成)常用做頁面 JS 代碼初始化操作
onclick(單擊)按鈕的點擊響應操作
onblur(失去焦點)輸入框失去焦點后驗證其輸入內容是否合法
onchange(內容發生改變)下拉列表和輸入框內容發生改變后操作
onsubmit(表單提交)表單提交前,驗證所有表單項是否合法
  • 事件需要進行注冊才能使用:
    • 靜態注冊:通過 HTML 標簽的事件屬性,直接賦于事件響應后的代碼;
    • 動態注冊:先通過 JS 代碼得到標簽的 dom 對象,然后再通過 dom 對象.事件名 = function(){} 這種形式賦于事件響應后的代碼。


  • onload 事件
<html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onloadEvent() {alert("靜態注冊onload事件,需要在body標簽下添加 οnlοad='onloadEvent' ")}window.onload = function () {alert("動態注冊onload事件")}</script> </head> <body></body> </html>
  • onclick 事件
<html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onclickEvent() {alert("靜態注冊onclick事件")}window.onload = function () {<!-- document對象表示整個頁面,通過id獲取button對象 -->var btn2_obj = document.getElementById("btn2");<!-- 綁定行為 -->btn2_obj.onclick = function () {alert("動態注冊onclick事件")}}</script> </head> <body><button onclick="onclickEvent()">靜態注冊的按鈕</button><button id="btn2">動態注冊的按鈕</button> </body> </html>
  • onblur 事件(同上)
<html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onblurEvent() {console.log("靜態失去焦點");}window.onload = function () {var pw = document.getElementById("p");pw.onblur = function () {console.log("動態失去焦點");}}</script> </head> <body>賬戶:<input type="text" onblur="onblurEvent()"/>密碼:<input type="password" id="p"/> </body> </html>
  • onchange 事件,綁定的是 select 而非 option 標簽
<html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onchangeEvent() {alert("靜態注冊onchange");}window.onload = function () {var select2 = document.getElementById("s");select2.onchange = function () {alert("動態注冊onchange")}}</script> </head> <body>選擇1:<select onchange="onchangeEvent()"><option>選項11</option><option>選項12</option></select>選擇2:<select id="s"><option>選項21</option><option>選項22</option></select> </body> </html>
  • onsubmit 事件,綁定的是表格而非按鈕,返回 false 則不會提交表單
<html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function onsubmitEvent() {alert("靜態注冊onsubmit");<!--如果發現不合法,返回false,阻止提交-->return false;}window.onload = function () {var form2 = document.getElementById("f");form2.onsubmit = function () {alert("動態注冊onsubmit");<!--如果發現不合法,返回false,阻止提交-->return false;}}</script> </head> <body><form action="http://localhost:8080" onsubmit="return onsubmitEvent()"> <!--靜態注冊 return 不能少--><input type="submit" value="靜態注冊提交"></form><form action="http://localhost:8080" id="f"><input type="submit" value="動態注冊提交"></form> </body> </html>

8 DOM (Document Object Model)

  • 簡單來說,將整個 HTML 文件視為一個 document 對象,并把其中所有的標簽對象化,形成了樹型結構。
  • document 實例提供查詢方法,使用優先級從高到低:getElementByID(返回一個實例),getElementByName(可以數組形式返回多個實例),getElementByTagName(以數組形式返回指定標簽的對象)。注意:頁面加載完之后才能進行查詢!不僅限于放在 onload 事件中。
  • document 實例提供創建方法:createElement
<html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">window.onload = function () {var new_div = document.createElement("div");new_div.innerHTML = "你好";document.body.appendChild(new_div); <!-- 在加載完后執行 -->}</script> </head> <body></body> </html>

9 DOM實例:驗證用戶名是否有效

限制用戶名由數字和字母組成,長度區間為 [5, 12]

<html lang="en"> <head><meta charset="UTF-8"><title>Title</title><script>window.onload = function () {var tip = document.getElementById("tip");var btn = document.getElementById("btn");var text = document.getElementById("text");btn.onclick = function () {var input = text.value;var pattern = /^\w{5,12}$/;if (pattern.test(input)) { <!-- 匹配正則表達式 -->tip.innerHTML = "通過"; <!-- innerHTML 返回的是開始和結束標簽之間的值,可讀寫-->} else {tip.innerHTML = "不通過";}}}</script> </head> <body> <input type="text" id="text"> <span id="tip" style="color: brown"></span> <button id="btn">檢查</button> </body> </html>

四 Tomcat

  • 簡單來說,Tomcat 就是一個運行JAVA的網絡服務器。
  • HTML 文件通過本地訪問,使用的協議是 file,執行的操作是直接獲取并解析;
  • IDEA 2021.3.1 創建JavaWeb工程的方法
  • 通過WEB服務器訪問,使用的協議是 http,經過了客戶端請求與服務器響應的過程,執行操作如下圖:

五 Servlet

1 舉例:向數據庫中添加表單信息

  • 客戶端請求表單頁面 add.html(表單指定 action=“add”(可以自定義) method=“post”),服務器返回。
  • 客戶端填寫表單,使用 HttpRequest 實例提交給服務器。
  • 服務器的具有一個類 ,繼承自 HttpServlet 類,其中的 doPost() 方法定義了 post 請求的處理與返回過程,調用 DAO 將表單信息寫入數據庫。
  • //@WebServlet("/add") public class AddServlet extends HttpServlet {@Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// method=post 設置編碼方式防止亂碼,且在獲取參數的操作之前(放在首行)request.setCharacterEncoding("UTF-8");String name = request.getParameter("name");System.out.println(name);// 調用DAO// ...} }
  • 如何指定 action=“add” 與自定義類 AddServlet 的綁定?
    一種方式是使用 web.xml 配置(另一種是通過在 AddServlet 注釋 @WebServlet("/add") ):
  • <!--指定servlet信息--><servlet><servlet-name>AddServlet</servlet-name><servlet-class>com.atguigu.servlets.AddServlet</servlet-class></servlet><!--設定servlet映射--><servlet-mapping><servlet-name>AddServlet</servlet-name><url-pattern>/add</url-pattern> <!--action="add"--></servlet-mapping>

    2 Servlet 的繼承關系

    • 繼承關系: HttpServlet 具體實現類 -> GenericServlet 抽象類 -> Servlet 接口
    • Servlet中的核心方法:service()
    • 當收到請求,service 方法會自動響應(tomcat 容器調用),在 HttpServlet 中分析請求的方式:到底是get、post、head 等等,然后再決定調用具體的 doXX 的方法。
    • 在 HttpServlet 中,doXX 方法默認都是405(報錯信息是找不到方法實現),除非子類去實現對應的 doXX 方法,否則默認會報405錯誤。

    3 Servlet 的生命周期

    • 三個重要的方法:init、service、destory
    • 默認情況下, 第一次接收請求時,Servlet 會進行實例化(調用構造方法)、初始化(調用init())、然后服務(調用service());從第二次請求開始,每一次都是服務(調用service());當容器關閉時,其中的所有的 Servlet 實例會被銷毀(調用destroy())。
    • 如果需要提高響應速度,應該設置 Servlet 的初始化時機,在第一次請求之前執行實例化和初始化。具體做法是,在 web.xml 中的 <servlet> 中添加 <load-on-startup> 標簽。
    • Servlet 是單例的、線程不安全的。單例是指,對于一個確定的 Servlet 類型,所有的請求都是同一個 Servlet 實例去響應;由于 Servlet 線程不安全,所以盡量避免在其中設置成員變量,如果設置盡量不要讀寫。

    4 HTTP 協議與 Session會話跟蹤

    • HTTP 協議是無狀態的,需要通過會話跟蹤技術保存用戶的歷史信息。
    • HTTP 請求與響應報文的格式略。
    • 常用的API:
      request.getSession() -> 獲取當前的會話,沒有則創建一個新的會話
      request.getSession(true) -> 效果和不帶參數相同
      request.getSession(false) -> 獲取當前會話,沒有則返回null,不會創建新的
      session.getId() -> 獲取sessionID
      session.isNew() -> 判斷當前session是否是新的
      session.getMaxInactiveInterval() -> session的非激活間隔時長,默認1800秒
      session.setMaxInactiveInterval()
      session.invalidate() -> 強制讓會話立即失效

    5 服務器端內部轉發、重定向

    • 服務器端內部轉發對客戶端是不可見的,執行方法:request.getRequestDispatcher("...").forward(request, response)

    • 重定向對客戶端可見,并且會顯示地更改 URL,執行方法:response.sendRedirect("...")

    6 Servlet 保存作用域

  • request:一次請求響應內有效。
  • session:一次會話內有效。
  • application:一次應用內有效,除非關閉服務器。
  • public class Demo extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// request 級別req.setAttribute("property1", 1);// session 級別HttpSession session = req.getSession();session.setAttribute("property2", 2);// application 級別ServletContext servletContext = req.getServletContext();servletContext.setAttribute("property3", 3);} }

    7 Servlet 的 init 方法與初始化參數設置

    • 兩種 init 方法:
      如果需要進行一些初始化操作,重寫無參的 init 方法
    // Servlet中的初始化方法有兩個:init() , init(config)// 其中帶參數的方法代碼如下:public void init(ServletConfig config) throws ServletException {this.config = config ;init(); // *調用無參的init*}// 另外一個無參的init方法如下:public void init() throws ServletException{}
    • 初始化參數設置
    1. 通過 web.xml 配置<servlet><servlet-name>Demo01Servlet</servlet-name><servlet-class>com.atguigu.servlet.Demo01Servlet</servlet-class><!--設置參數--><init-param><param-name>hello</param-name><param-value>world</param-value></init-param></servlet>2. 通過注解 @Webservlet(urlPatterns = {"/demo01"} ,initParams = {@WebInitParam(name="hello",value="world")})
    • 讀取初始化參數:
    ServletConfig config = getServletConfig(); // 獲取config對象 config.getInitParameter("hello"); // 讀取初始化的值

    8 ServletContext

    • ServletContext是一個全局的儲存信息的空間,服務器開始就存在,服務器關閉才釋放(application級別)
    • 類似 session,可以想象成一個 map
    • 多個Servlet可以通過ServletContext對象來實現數據間的共享,如果是涉及到不同用戶共享數據,而這些數據量不大,同時又不希望寫入數據庫中,我們就可以考慮使用 ServletContext 實現
    • 初始化 ServletContext 時,不能寫在具體的某個 servlet 標簽中,因為它是全局的
    <!--寫在servlet之外--> <context-param><param-name>name</param-name><param-value>gavin</param-value> </context-param><servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.gavin.servlet.MyServlet</servlet-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </servlet>

    六 Thymeleaf

    1 配置過程

  • 添加依賴, maven 中添加:
  • <dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf</artifactId><version>3.0.14.RELEASE</version></dependency>
  • 新建一個類 ViewBaseServlet 繼承 HttpServlet
  • public class ViewBaseServlet extends HttpServlet {private TemplateEngine templateEngine;@Overridepublic void init() throws ServletException {// 1.獲取ServletContext對象ServletContext servletContext = this.getServletContext();// 2.創建Thymeleaf解析器對象ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);// 3.給解析器對象設置參數// ①HTML是默認模式,明確設置是為了代碼更容易理解templateResolver.setTemplateMode(TemplateMode.HTML);// ②設置前綴String viewPrefix = servletContext.getInitParameter("view-prefix");templateResolver.setPrefix(viewPrefix);// ③設置后綴String viewSuffix = servletContext.getInitParameter("view-suffix");templateResolver.setSuffix(viewSuffix);// ④設置緩存過期時間(毫秒)templateResolver.setCacheTTLMs(60000L);// ⑤設置是否緩存templateResolver.setCacheable(true);// ⑥設置服務器端編碼方式templateResolver.setCharacterEncoding("utf-8");// 4.創建模板引擎對象templateEngine = new TemplateEngine();// 5.給模板引擎對象設置模板解析器templateEngine.setTemplateResolver(templateResolver);}protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {// 1.設置響應體內容類型和字符集resp.setContentType("text/html;charset=UTF-8");// 2.創建WebContext對象WebContext webContext = new WebContext(req, resp, getServletContext());// 3.處理模板數據templateEngine.process(templateName, webContext, resp.getWriter());} }
  • 在 web.xml 配置前綴和后綴,根據邏輯視圖名稱得到物理視圖名稱。
    邏輯視圖名稱 : index
    物理視圖名稱 : view-prefix + 邏輯視圖名稱 + view-suffix
    真實的視圖名稱: / index .html
  • <context-param><param-name>view-prefix</param-name><param-value>/</param-value></context-param><context-param><param-name>view-suffix</param-name><param-value>.html</param-value></context-param>
  • 創建自定義的 Servlet 類,繼承 ViewBaseServlet,調用super.processTemplate("index",request,response); 定位到指定 HTML 頁面。
  • 對于跳轉到的 HTML 頁面,需要顯示查詢內容。設置 <html lang="en" xmlns:th="http://www.thymeleaf.org">,使用 thymeleaf 的標簽完成操作。

  • 2 Servlet 優化 - 合并同類方法

    • 之前的一個 Servlet 只提供一種方法,此處的改進是將同類的多種方法合并到一個 Servlet 中
    • 使用反射代替 switch-case
    @WebServlet("/fruit.do") public class FruitServlet extends ViewBaseServlet {private final FruitDAO fruitDAO = new FruitDAOImpl();/*** 設置一個Fruit 的 meta servlet*/@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {req.setCharacterEncoding("UTF-8");String operation = (String) req.getAttribute("operation");// 簡化了switch-caseMethod[] methods = this.getClass().getDeclaredMethods();for (Method method: methods) {method.setAccessible(true);if (operation.equals(method.getName())) {try {method.invoke(this, req, resp);return ;} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}throw new IOException("輸入操作錯誤"); // 對應default}private void insertFruit(HttpServletRequest request, HttpServletResponse response) {// ...}private void selectFruit(HttpServletRequest request, HttpServletResponse response) {// ...} }

    3 Servlet 優化 - dispatchedServlet

    • 相當于一個 meta 的 Servlet,稱為 DispatchedServlet,繼承自 ViewBaseServlet。合并所有種類的 Servlet,并將原來的 Servlet 轉為 Controller,剝奪其注釋 @WebServlet
    • 在 src 目錄下創建 applicationContext.xml,利用 bean 標簽,為參數名和 Controller 建立映射
    • DispatchedServlet 的 init 方法根據 xml 配置 Map<String,Object> beanMap
    <?xml version="1.0" encoding="utf-8"?><beans><!-- 這個bean標簽的作用是 將來servletpath中涉及的名字對應的是fruit,那么就要FruitController這個類來處理 --><bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"/> </beans>
    • 使用時,向 DispatchedServlet 傳遞參數,由其 service 方法負責解析,并根據 beanMap 調用指定的 Controller,具體步驟:
      • 獲取參數:獲取即將要調用的方法的參數簽名信息
      • 執行方法:Object returnObj = method.invoke(controllerBean , parameterValues);
      • 視圖處理:根據返回值調用重定向等 String returnStr = (String)returnObj; if(returnStr.startWith("redirect:")){ .... } else if.....

    七 MVC

    1 概念

    • MVC(Model–View–Controller)模式是軟件工程中的一種軟件架構模式,它把軟件系統分為三個基本部分:模型(Model)、視圖(View)和控制器(Controller)。
    • Controller 作為 Model 和 View 部分的“膠水”,本身不適合包含太多的邏輯。

    2 降低各層間的耦合 - IOC 與 DI

    • DI(Dependency Injection,依賴注入)是 IOC(Inversion of Control,控制反轉)最常用的方法。
    • IOC 是一種設計思想,核心是,將設計好的對象交給容器控制,而不是傳統的在對象內部直接控制。 把創建和查找依賴對象的控制權交給了容器,由容器進行注入組合對象,所以對象與對象之間是松散的耦合。
    • Spring 所倡導的開發方式就是如此,所有的類都會在 spring 容器中登記,告訴 spring 你是個什么東西,你需要什么東西,然后 spring 會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的創建、銷毀都由 spring 容器來控制,也就是說控制對象生存周期的不再是引用它的對象,而是 spring。對于某個具體的對象而言,以前是它控制其他對象,現在是所有對象都被 spring 控制,所以這叫控制反轉。
    • IOC 容器實際上就是 map(key,value),里面存的是各種對象(在 xml 里配置的 bean 節點、service、controller、component),在項目啟動的時候會讀取配置文件里面的 bean 節點,根據全限定類名使用反射創建對象并放到 map 里。


    通過 IOC 容器,上述過程轉為:

    • IoC的一個重點是在系統運行中,動態的向某個對象提供它所需要的其他對象。這一點是通過 DI 來實現的。在類中需要使用到的對象,全部通過反射從第三方容器注入而不是自己創建。
    • 比如對象A需要操作數據庫,以前我們總是要在A中自己編寫代碼來獲得一個 Connection 對象,有了 spring 只需要告訴 spring ,A中需要一個 Connection,至于這個 Connection 怎么構造,何時構造,A不需要知道。在系統運行時,spring 會在適當的時候制造一個 Connection,然后像打針一樣,注射到A當中,這樣就完成了對各個對象之間關系的控制。A需要依賴 Connection 才能正常運行,而這個 Connection 是由 spring 注入到A中的,依賴注入的名字就這么來的。

    3 IOC 與 DI 的實現過程

  • 對于 Servlet - Controller - Service - DAO 的結構,首先將用到的類,及其依賴關系,注冊到 applicationContext.xml 中。
  • <?xml version="1.0" encoding="utf-8"?><beans><!-- FruitDAO不依賴于其它組件 --><bean id="fruitDAO" class="com.atguigu.fruit.dao.impl.FruitDAOImpl"/><!-- FruitService依賴于FruitDAO(FruitService類包含FruitDAO屬性) --><bean id="fruitService" class="com.atguigu.fruit.service.impl.FruitServiceImpl"><!-- property標簽用來表示屬性;name表示屬性名;ref表示引用其他bean的id值--><property name="fruitDAO" ref="fruitDAO"/></bean><!-- FruitController依賴于FruitService(FruitController類包含FruitService屬性) --><bean id="fruit" class="com.atguigu.fruit.controllers.FruitController"><property name="fruitService" ref="fruitService"/></bean><!-- FruitServlet中具有 包含所有對象的 map,以BeanFactory作為 map 的包裝 --> </beans>
  • 使用 BeanFactory 讀取 xml 配置,填充 map,并設置依賴關系(比如 A 以 B 作為屬性,執行此過程前將屬性值設置為 null,在此過程將 A 的對應屬性設置為 B 的實例,完成依賴注入)
  • BeanFactory 實現:

    public class ClassPathXmlApplicationContext implements BeanFactory {private Map<String,Object> beanMap = new HashMap<>();public ClassPathXmlApplicationContext(){try {InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");//1.創建DocumentBuilderFactoryDocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();//2.創建DocumentBuilder對象DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;//3.創建Document對象Document document = documentBuilder.parse(inputStream);//4.獲取所有的bean節點NodeList beanNodeList = document.getElementsByTagName("bean");for(int i = 0 ; i<beanNodeList.getLength() ; i++){Node beanNode = beanNodeList.item(i);if(beanNode.getNodeType() == Node.ELEMENT_NODE){Element beanElement = (Element)beanNode ;String beanId = beanElement.getAttribute("id");String className = beanElement.getAttribute("class");Class beanClass = Class.forName(className);//創建bean實例Object beanObj = beanClass.newInstance() ;//將bean實例對象保存到map容器中beanMap.put(beanId , beanObj) ;//到目前為止,此處需要注意的是,bean和bean之間的依賴關系還沒有設置}}//5.組裝bean之間的依賴關系for(int i = 0 ; i<beanNodeList.getLength() ; i++){Node beanNode = beanNodeList.item(i);if(beanNode.getNodeType() == Node.ELEMENT_NODE) {Element beanElement = (Element) beanNode;String beanId = beanElement.getAttribute("id");NodeList beanChildNodeList = beanElement.getChildNodes();for (int j = 0; j < beanChildNodeList.getLength() ; j++) {Node beanChildNode = beanChildNodeList.item(j);if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){Element propertyElement = (Element) beanChildNode;String propertyName = propertyElement.getAttribute("name");String propertyRef = propertyElement.getAttribute("ref");//1) 找到propertyRef對應的實例Object refObj = beanMap.get(propertyRef);//2) 將refObj設置到當前bean對應的實例的property屬性上去Object beanObj = beanMap.get(beanId);Class beanClazz = beanObj.getClass();Field propertyField = beanClazz.getDeclaredField(propertyName);propertyField.setAccessible(true);propertyField.set(beanObj,refObj);}}}}} catch (ParserConfigurationException e) {e.printStackTrace();} catch (SAXException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();}}@Overridepublic Object getBean(String id) {return beanMap.get(id);} }
  • 重寫 Servlet 的 無參 init 方法和 service 方法。其中 init 方法負責獲取 BeanMap,service 方法負責解析方法調用,執行方法調用,處理返回值。
  • @WebServlet("*.do") public class DispatcherServlet extends ViewBaseServlet{private BeanFactory beanFactory ;public DispatcherServlet(){}public void init() throws ServletException {super.init();beanFactory = new ClassPathXmlApplicationContext();}@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//設置編碼request.setCharacterEncoding("UTF-8");//假設url是: http://localhost:8080/pro15/hello.do//那么servletPath是: /hello.do// 我的思路是:// 第1步: /hello.do -> hello 或者 /fruit.do -> fruit// 第2步: hello -> HelloController 或者 fruit -> FruitControllerString servletPath = request.getServletPath();servletPath = servletPath.substring(1);int lastDotIndex = servletPath.lastIndexOf(".do") ;servletPath = servletPath.substring(0,lastDotIndex);Object controllerBeanObj = beanFactory.getBean(servletPath);String operate = request.getParameter("operate");if(StringUtil.isEmpty(operate)){operate = "index" ;}try {Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();for(Method method : methods){if(operate.equals(method.getName())){//1.統一獲取請求參數//1-1.獲取當前方法的參數,返回參數數組Parameter[] parameters = method.getParameters();//1-2.parameterValues 用來承載參數的值Object[] parameterValues = new Object[parameters.length];for (int i = 0; i < parameters.length; i++) {Parameter parameter = parameters[i];String parameterName = parameter.getName() ;//如果參數名是request,response,session 那么就不是通過請求中獲取參數的方式了if("request".equals(parameterName)){parameterValues[i] = request ;}else if("response".equals(parameterName)){parameterValues[i] = response ;}else if("session".equals(parameterName)){parameterValues[i] = request.getSession() ;}else{//從請求中獲取參數值String parameterValue = request.getParameter(parameterName);String typeName = parameter.getType().getName();Object parameterObj = parameterValue ;if(parameterObj!=null) {if ("java.lang.Integer".equals(typeName)) {parameterObj = Integer.parseInt(parameterValue);}}parameterValues[i] = parameterObj ;}}//2.controller組件中的方法調用method.setAccessible(true);Object returnObj = method.invoke(controllerBeanObj,parameterValues);//3.視圖處理String methodReturnStr = (String)returnObj ;if(methodReturnStr.startsWith("redirect:")){ //比如: redirect:fruit.doString redirectStr = methodReturnStr.substring("redirect:".length());response.sendRedirect(redirectStr);}else{super.processTemplate(methodReturnStr,request,response); // 比如: "edit"}}}} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}} }

    八 Filter

    1 概述

    • 繼承自 Filter 類,具有 init, doFilter, destory 方法
    • 可以使用注解的形式 @WebFilter("fruit.do"),也可以在 web.xml 中配置
    • 使用注解形式,當具有多個 Filter 時,按照類名的字典序組織過濾順序
    @WebFilter("*.do") public class Demo01Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("before");//放行filterChain.doFilter(servletRequest,servletResponse);System.out.println("after");}@Overridepublic void destroy() {} }

    2 使用 Filter 實現事務的原子性

    • 利用 Filter 的機制,在放行之前撤銷 conn 的自動提交,在返回時手動執行提交,并在捕獲到異常時執行回滾
    • 要求事務執行的過程中,遇到的異常要層層向外拋出,直到被 Filter 捕獲,而不是就地解決
    • 將 conn 綁定 ThreadLocal 實例,再進一步保存到 ThreadLocalMap 中,保證了多個 DAO 共用同一個數據庫連接,不會因為連接的關閉而自動提交,破壞事務的原子性

    九 Listener

    • 監聽某個組件的某種行為,當這種行為被監聽到時,調用指定的方法
    • 可以用于完成初始化的創建,以及結束時的銷毀操作
    • 一個應用實例:IOC 容器的 beanMap,當監聽到 ServletContext 對象創建時,在監聽器內進行初始化,而非在 Servlet 的 init 方法中完成
    // 監聽上下文啟動,在上下文啟動的時候去創建IOC容器,然后將其保存到 application 作用域 // 后面DispatchedServlet 再從 application 作用域中去獲取IOC容器@WebListener public class ContextLoaderListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {//1.獲取ServletContext對象ServletContext application = servletContextEvent.getServletContext();//2.獲取上下文的初始化參數(bean類型以及依賴關系)String path = application.getInitParameter("contextConfigLocation");//3.創建IOC容器BeanFactory beanFactory = new ClassPathXmlApplicationContext(path);//4.將IOC容器保存到application作用域application.setAttribute("beanFactory", beanFactory);}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {// ...} }

    十 總結

    總結

    以上是生活随笔為你收集整理的后端学习 - JavaWeb的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。