重拾Java Web應用的基礎體系結構

智慧zhuhuix發表於2020-08-25

一、背景

  • Spring生態的強大與完善,使得大多數的Java程式設計師,在剛剛接觸Java Web應用開發時,往往依賴於SSM、SpringBoot等各種高階框架。
  • Java Web的基礎的體系結構是什麼?到底是怎麼運作的?這些高階的框架與基礎的體系結構之間是什麼關係?
  • 只有真正理清了這些底層基礎的結構,才能完全理解高階框架的設計原理,在使用框架開發專案時做到事半功倍。
  • 本文旨在暫時拋開這些高階框架,重走Java Web底層之路。

二、Web應用

  • Web應用的基礎模型
  1. 使用者通過Web瀏覽器向某個Web應用發出一個請求
  2. Web伺服器得到請求後,處理並查詢資源,並向Web瀏覽器返回一個響應結果。
    在這裡插入圖片描述

2.1 HTML

  • Web伺服器需要對客戶端的請求提供響應內容,Web瀏覽器需要將這些響應內容呈現給使用者。兩者需要形成統一的對話語言,Web應用中形成的共同的語言被稱為HTML(HyperText Markup Language:超文字標記語言)。

  • HTML包含數十個標記,數千種標記屬性,能過這些標記定義了網頁內容的含義和結構;正是無數個具有相互連結的HTML網頁構成了我們現在的網際網路世界。

標記 描述
html 定義HTML文件的邊界
head 定義HTML文件頭部的邊界
body 定義HTML文件本體的邊界
tile 定義HTML文件本體的標題
form 定義一個表單
a 定義一個超連結
... ...
<!-- HTML基礎 -->
<html>
  <head>
    <title>歡迎</title>
  </head>
  <body>
   <a href="https://www.baidu.com">百度</a>
  </body>
</html>

2.2 HTTP

  • Web瀏覽器與Web伺服器之間相互通訊同樣需要建立統一的協議:Web應用的標準協議被稱為HTTP(Hyper Text Transfer Protocol)超文字傳輸協議。
  • HTTP協議規定了超文字傳輸所要遵守的規則:HTTP請求可發起常用的GET或者POST請求;HTTP的響應中可以包含HTML內容。
    在這裡插入圖片描述
curl https://www.baidu.com -v
<!-- 通過HTTP向URL地址www.baidu.com發起 GET請求-->
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.baidu.com
> Accept: */*
<!-- Web伺服器HTTP響應-->
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Connection: keep-alive
< Content-Length: 2443
< Content-Type: text/html
< Date: Tue, 25 Aug 2020 04:04:01 GMT
< Etag: "588603eb-98b"
< Last-Modified: Mon, 23 Jan 2017 13:23:55 GMT
< Pragma: no-cache
< Server: bfe/1.0.8.18
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
< 
<!DOCTYPE html>
<!--STATUS OK-->
<html>
<head>
...
    <title>百度一下,你就知道</title>
</head>
<body link=#0000cc>
    ...
</body>
</html>

2.3 URL

  • Web應用上的每個資源都有唯一的地址進行定位,被稱為URL(Uniform Resource Locatiors)統一資源定位符。
    1. URL中可包含額外的引數,會追加到URL的最後,以?開頭,以&分隔各個引數,如:http://www.web.com:8080/welcome/hello.html?name=jack&age=20
    2. Web伺服器中的應用一般預設在80埠執行,埠號為80的在URL中可省略不書寫。
      在這裡插入圖片描述

2.4 Servlet

  • Servlet是Server Applet的簡寫,也被稱為執行在服務端的小程式,通過Servlet程式可以生成動態Web內容,實現Java Web伺服器功能的擴充套件。
  • Servlet需要依付於Servlet容器(比如Tomcat等)才能執行
    在這裡插入圖片描述

2.4.1 編寫第一個Servlet程式

  • Java Servlet是一個介面,定義了Java類被瀏覽器訪問到的規則。

  • Java程式設計師自定義一個類,實現Servlet介面並重寫介面中的方法,Web伺服器(如Tomcat等)就可以識別並執行這個程式。

  • 建立JavaEE專案
    在這裡插入圖片描述
    在這裡插入圖片描述

  • 定義一個類,實現Servlet介面,實現或重寫介面中的方法

/**
 * HttpServlet
 *
 * @author zhuhuix
 * @date 2020-08-25
 */
public class HttpServletDemo extends HttpServlet {

    // 重寫Get請求方法
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 業務邏輯處理
        LocalDate date = LocalDate.now();

        // 動態輸出HTML頁面
        PrintWriter out = resp.getWriter();
        out.println("<html>" +
                "<body>" +
                "<h1>"+date.toString()+"</h1> " +
                "<h2>hello world</h2> " +
                "</body>" +
                "</html>"
        );
    }
}

  • 在web.xml配置Servlet
<?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-name>http-demo</servlet-name>
        <servlet-class>demo.servlet.HttpServletDemo</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>http-demo</servlet-name>
        <url-pattern>/http-demo</url-pattern>
    </servlet-mapping>
</web-app>
  • 執行
    在這裡插入圖片描述
  • 訪問http://localhost:8080/servlet_war_exploded/http-demo路徑
    在這裡插入圖片描述

2.5 JSP

  • JSP(Java Server Pages)也是一種Java servlet,主要用於實現Java web應用程式的使用者介面部分。通過結合HTML程式碼、XHTML程式碼、XML元素以及嵌入JSP操作和命令來編寫JSP。簡而言之,就是在HTML網頁中嵌入了Java。
  • JSP頁面可以與處理業務邏輯的 Servlet 一起使用,這種模式被Java servlet 模板引擎所支援
<%@ page import="java.time.LocalDate" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <body>
  <h1><%= LocalDate.now()%></h1>
  <h2>hello world!!!</h2>
  </body>
</html>
public class HttpServletDemo extends HttpServlet {
    // 重寫Get請求方法
   @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	// 呼叫jsp頁面
        req.getRequestDispatcher("/index.jsp").forward(req,resp);
    }
}

2.6 容器

  • 容器就是程式執行時需要的環境;比如Tomcat就是一個Servlet/JSP的容器。
  • Servlet 容器具備管理Servlet物件的功能。
    1. 通訊支援:利用容器提供的方法,可以輕鬆實現Web伺服器與Servlet進行通訊,無需自己建立ServerSocket、監聽埠,位元組流傳輸等底層協議。
    2. 生命週期管理: 容器會負責Servlet的例項化、初始化、呼叫方法、釋放資源等控制。
    3. 多執行緒支援:容器接收到每個Servlet請求時建立新的執行緒,並協調執行緒執行。
    4. 配置式管理:利用容器支援的xml進行配置式管理,在環境改變時,無需硬性修改程式及編譯程式。

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

2.7 URL對映到Servlet

  • 通過JavaEE的XML配置部署檔案中的元素〈servlet〉〈servlet-mapping〉,把URL對映到對應的Servlet上。
    在這裡插入圖片描述

三、一個完整的Java Web基礎應用

在這裡插入圖片描述

在這裡插入圖片描述

/**
 * HttpServlet
 *
 * @author zhuhuix
 * @date 2020-08-25
 */
public class HttpServletDemo extends HttpServlet {

    // 重寫Get請求方法,返回一個表單頁面
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        req.getRequestDispatcher("/form.jsp").forward(req, resp);
    }

    // 重寫Post請求方法,提交表單上的資料,並返回結果頁面
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        Integer age = Integer.parseInt(req.getParameter("age"));
        if (name != null && age != null) {
            User user = new User(name, age);
            req.setAttribute("name", name);
            req.setAttribute("age", age);
            if (user.checkName()) {
                req.setAttribute("result","登記成功");
            }else {
                req.setAttribute("result","登記失敗:名稱中包含非法字元");
            }
            RequestDispatcher view = req.getRequestDispatcher("/result.jsp");
            view.forward(req, resp);
        }
    }
}

/**
 * 使用者類
 */
public class User {
    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    // 判斷名稱是否非法
    public Boolean checkName() {
        return !this.name.contains("admin");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

<?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-name>http-demo</servlet-name>
            <servlet-class>demo.servlet.HttpServletDemo</servlet-class>
        </servlet>

        <servlet-mapping>
            <servlet-name>http-demo</servlet-name>
            <url-pattern>/http-demo</url-pattern>
        </servlet-mapping>


</web-app>
<!--表單頁面-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登記使用者</title>
</head>
<body>
    <form method="post" action="http-demo">
        姓名:<input name="name" type="text"/><br>
        年齡:<input name="age" type="text"/><br>

            <input type="submit" title="提交" >

    </form>
</body>
</html>
<!--結果頁面-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登記結果</title>
</head>
<body>
    <h2>姓名:${name} 年齡:${age} ${result} </h2><br>
</body>
</html>

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

四、小結

  • 以上三個小節,只對Java Web中的基礎要素及這些要素組成的最小體系結構做了回顧。
  • Java EE中Web開發的要點還有很多,比如Servlet的請求與響應的具體細節、JSTL語法,過濾器與監聽器,Session與Cookie等。
  • 在重度依賴各種框架開發的今天,謹以此文拋磚引玉,讓我們先拋開框架,重拾基礎。

相關文章