Jave Web是java面向web開發的相關技術,他是相關技術的統稱,並不是指某一個單一的技術。
在我之前的部落格中(Java網路程式設計----透過實現簡易聊天工具來聊聊BIO模型 https://www.cnblogs.com/jilodream/p/17405923.htm),就已經寫到過java可以作為一個伺服器(如TCP/UDP),接收外部的請求。如使用TCP監聽埠,然後直接用web頁面請求該埠,那麼伺服器就會接收到相關的響應,接著做好業務處理,返回響應的請求即可。但是整個的業務流程太繁瑣了。我們不但要處理業務流程,還要控制請求會話,還要控制各種業務分支的處理,顯然這不是我們想要的。
於是聰明的開發者很快想到了-----解耦,業務人員只要編寫相關的業務即可,不需要關心繁瑣的網路細節處理,因此就誕生了servlet。開發人員只要實現servlet,而servlet和不同的路徑繫結。web請求後,由系統直接轉發到各自的Servlet,並由Servlet來處理相關業務即可。
那什麼是servlet呢?servlet 是Server Applet(伺服器應用程式)的簡寫,從名字我們就可以看出它是專門用來編寫伺服器端的應用程式。我們通常用它來處理伺服器中http請求的處理和響應。
它是一項很古老的技術,隨java誕生之初就已經問世,很多人甚至都不知Servlet是做什麼。那麼問題來了,我們為什麼還要學習和掌握Servlet呢?這主要是由於Servlet是javaEE的重要組成,是java web開發的重要基石。我們現在專案中常用到的Jsp、Springmvc、Springboot等框架,在處理網路請求的核心技術,仍然是Servlet。我們雖然不需要再繼續直面Servlet或更底層的技術進行開發,但是Servlet究竟是什麼樣的,如何執行,以及再新技術中承擔什麼樣的角色,這個卻是我們想要熟悉底層原理所必須要掌握的。
話不多說,想要使用Servlet,我們需要做兩步:
1、編寫Servlet相關業務程式碼
2、將業務程式碼打包放置在Tomcat中,由Tomcat來載入這些Servlet
第一步,試著來編寫一個Servlet
我們首先透過IDEA 新建一個web專案,此處我們選擇採用maven部署,搭建好之後專案整體的結構就如下面的檔案層級樹一樣了
E:.
├─.idea
├─.smarttomcat
│ └─PureJaveServlet
│ └─conf
└─src
└─main
├─java
│ └─org
│ └─example
├─resources
└─webapp
其中:
resources 一般是我們填寫的資源資訊,如圖片,業務配置檔案等,
webapp則會放置html、css等渲染檔案,還會放一些web元件(Servlet、Filter)的配置資訊。我們這裡只要知道作用即可。
src/main/java則是我們的業務程式碼。值得注意的是,我們要引入Servlet網路程式設計的相關依賴包,才能進行相關的web開發。預設的java SE是不包含這些開發包的。
在Servlet4.0之前,我們只使用javax相關的包,並且未來對接的是Tomcat 9.x及以下版本。(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )
在Servlet5.0之後,我們只使用javax相關的包,並且未來對接的是Tomcat 10.x及以後版本。
這裡我們使用高版本來學習,即jakarta版本,未來tomcat也需要使用高版本。
接著編寫POM檔案:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>org.example</groupId> 8 <artifactId>PureJaveServlet</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 <name>PureJaveServlet</name> 11 <packaging>war</packaging> 12 13 <properties> 14 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 15 <maven.compiler.target>11</maven.compiler.target> 16 <maven.compiler.source>11</maven.compiler.source> 17 <junit.version>5.9.2</junit.version> 18 </properties> 19 20 <dependencies> 21 <dependency> 22 <groupId>jakarta.servlet</groupId> 23 <artifactId>jakarta.servlet-api</artifactId> 24 <version>5.0.0</version> 25 <scope>provided</scope> 26 </dependency> 27 <dependency> 28 <groupId>org.junit.jupiter</groupId> 29 <artifactId>junit-jupiter-api</artifactId> 30 <version>${junit.version}</version> 31 <scope>test</scope> 32 </dependency> 33 <dependency> 34 <groupId>org.junit.jupiter</groupId> 35 <artifactId>junit-jupiter-engine</artifactId> 36 <version>${junit.version}</version> 37 <scope>test</scope> 38 </dependency> 39 <dependency> 40 <groupId>org.projectlombok</groupId> 41 <artifactId>lombok</artifactId> 42 <version>1.18.30</version> 43 </dependency> 44 <dependency> 45 <groupId>org.apache.commons</groupId> 46 <artifactId>commons-lang3</artifactId> 47 <version>3.13.0</version> 48 </dependency> 49 <!-- http客戶端 --> 50 <!-- fastjson --> 51 <dependency> 52 <groupId>com.alibaba</groupId> 53 <artifactId>fastjson</artifactId> 54 <version>1.2.83</version> 55 </dependency> 56 57 58 <dependency> 59 <groupId>com.fasterxml.jackson.core</groupId> 60 <artifactId>jackson-databind</artifactId> 61 <version>2.10.0</version> 62 </dependency> 63 <dependency> 64 <groupId>io.pebbletemplates</groupId> 65 <artifactId>pebble</artifactId> 66 <version>3.1.6</version> 67 </dependency> 68 <dependency> 69 <groupId>org.apache.maven.plugins</groupId> 70 <artifactId>maven-compiler-plugin</artifactId> 71 <version>3.10.1</version> 72 </dependency> 73 74 </dependencies> 75 76 <build> 77 <plugins> 78 <plugin> 79 <groupId>org.apache.maven.plugins</groupId> 80 <artifactId>maven-war-plugin</artifactId> 81 <version>3.3.2</version> 82 </plugin> 83 <plugin> 84 <groupId>org.apache.maven.plugins</groupId> 85 <artifactId>maven-compiler-plugin</artifactId> 86 <configuration> 87 <compilerArgs> 88 <arg>-parameters</arg> 89 </compilerArgs> 90 </configuration> 91 </plugin> 92 </plugins> 93 </build> 94 </project>
Servlet類
1 package org.example; 2 3 4 import jakarta.servlet.ServletException; 5 import jakarta.servlet.annotation.WebServlet; 6 import jakarta.servlet.http.HttpServlet; 7 import jakarta.servlet.http.HttpServletRequest; 8 import jakarta.servlet.http.HttpServletResponse; 9 10 import java.io.IOException; 11 import java.io.PrintWriter; 12 13 14 @WebServlet(urlPatterns = "/nihao") 15 public class HiServlet extends HttpServlet { 16 @Override 17 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { 18 String name = req.getParameter("name"); 19 resp.setContentType("text/html"); 20 PrintWriter out = resp.getWriter(); 21 out.println("<html><body>"); 22 out.println(String.format("<h1>Hello, %s </h1>", name)); 23 out.println("</body></html>"); 24 out.flush(); 25 } 26 }
1 package org.example; 2 3 import jakarta.servlet.annotation.WebServlet; 4 import jakarta.servlet.http.HttpServlet; 5 import jakarta.servlet.http.HttpServletRequest; 6 import jakarta.servlet.http.HttpServletResponse; 7 8 import java.io.IOException; 9 import java.io.PrintWriter; 10 11 /** 12 * @discription 13 */ 14 @WebServlet(urlPatterns = "/bye") 15 public class ByeServlet extends HttpServlet { 16 @Override 17 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { 18 String name = req.getParameter("name"); 19 resp.setContentType("text/html"); 20 PrintWriter out = resp.getWriter(); 21 out.println("<html><body>"); 22 out.println(String.format("<h1>bye bye, %s </h1>", name)); 23 out.println("</body></html>"); 24 out.flush(); 25 } 26 }
程式碼部分就結束了,我們觀察程式碼可以發現兩點:
1、所有的Sevlet都要繼承自HttpServlet。HttpServlet是一個抽象類,我們需要複寫抽象類中的抽象方法,以保證未來Tomcat等web伺服器在載入Servlet時,可以按照統一的規範查詢,執行。
我們在Servlet中重寫了doGet() 方法,表示處理該servlet路徑下的get請求,同理還可以重寫doPost doDelete doPut等方法,來處理對應的請求型別。
這裡我們很簡單,直接返回一段響應的html。
2、我們並沒有寫main方法,而是在Pom中標記我們的工程需要打包成一個war包。
第二步,配置tomcat
沒有main方法,我們如何啟動我們的java程式呢?我們通常是將其配置到tomcat的指定路徑中,啟動tomcat後,tomcat會載入war包中servlet的相關類,進行處理。
因此我們會將tomcat這樣的web伺服器稱之為Servlet容器。
我們首先從tomcat官網上(https://tomcat.apache.org/whichversion.html)下載一個與我們對應的servlet版本匹配的tomcat版本。
下載到本地之後解壓即可。
接著我們為了方便在IDEA中下載一個smart tomcat的元件,將該元件關聯好servlet程式碼和tomcat伺服器即可。
關鍵配置如下:
Tomcat server: 選擇我們下載好的tomcat伺服器,如果沒有下拉選項就選擇"Congure..."手動加一下。
Deployment dirctory:部署資料夾,(防盜連線:本文首發自http://www.cnblogs.com/jilodream/ )該配置指向前文專案結構樹種的webapp。
Use classpath of module:選擇當前專案
Context path:選擇上下文路徑(其實就是url的字首路徑),按照url規則隨便填,我這裡叫填的是/biubiubiu
server port:Servlet的伺服器埠,預設填8080
admin port:tomcat的管理埠 預設填8005,一般就是用於停掉tomcat(其實一般也不用)。
之後我們透過IDEA:拉起tomcat,載入servlet相關類和資源。
命令列輸入如下:
....
15-Nov-2024 10:34:38.099 資訊 [main] org.apache.coyote.AbstractProtocol.start 開始協議處理控制代碼["http-nio-8080"] 15-Nov-2024 10:34:39.831 資訊 [main] org.apache.catalina.startup.Catalina.start [4858]毫秒後伺服器啟動 http://localhost:8080/biubiubiu
執行效果如下:
有人會覺得透過下載並配置tomcat有點麻煩,我們如果想debug程式碼的話,就更麻煩了,有沒有簡單點的辦法:
其實除了下載tomcat,我們還可以透過程式碼的形式直接拉起tomcat。思路如下:
首先透過maven載入對應tomcat依賴,然後在main方法中建立tomcat例項,並且指定tomcat所需要的配置資訊,如資源和class路徑。然後透過start()方法啟動tomcat例項就可以了。
程式碼如下:
新搭建一個java web專案,Servlet類和工程結構我們保持不變還是和原來一樣
POM檔案
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>com.example</groupId> 8 <artifactId>demotom</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 <name>demotom</name> 11 <packaging>war</packaging> 12 13 <properties> 14 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 15 <maven.compiler.target>11</maven.compiler.target> 16 <maven.compiler.source>11</maven.compiler.source> 17 <tomcat.version>10.0.0</tomcat.version> 18 </properties> 19 20 <dependencies> 21 22 23 <dependency> 24 <groupId>org.apache.tomcat.embed</groupId> 25 <artifactId>tomcat-embed-core</artifactId> 26 <version>${tomcat.version}</version> 27 <scope>provided</scope> 28 </dependency> 29 <dependency> 30 <groupId>org.apache.tomcat.embed</groupId> 31 <artifactId>tomcat-embed-jasper</artifactId> 32 <version>${tomcat.version}</version> 33 <scope>provided</scope> 34 </dependency> 35 </dependencies> 36 37 <build> 38 <plugins> 39 <plugin> 40 <groupId>org.apache.maven.plugins</groupId> 41 <artifactId>maven-war-plugin</artifactId> 42 <version>3.3.2</version> 43 </plugin> 44 </plugins> 45 </build> 46 </project>
主類:
1 package com.example.demotom; 2 3 import org.apache.catalina.Context; 4 import org.apache.catalina.LifecycleException; 5 import org.apache.catalina.WebResourceRoot; 6 import org.apache.catalina.startup.Tomcat; 7 import org.apache.catalina.webresources.DirResourceSet; 8 import org.apache.catalina.webresources.StandardRoot; 9 10 import java.io.File; 11 12 /** 13 * @discription 14 */ 15 public class TomMain { 16 public static void main(String[] args) throws LifecycleException { 17 Tomcat tomcat = new Tomcat(); 18 tomcat.setPort(Integer.getInteger("port", 8080)); 19 tomcat.getConnector(); 20 String docBase = new File("src/main/webapp").getAbsolutePath(); 21 Context ctx = tomcat.addContext("", docBase); 22 WebResourceRoot resources = new StandardRoot(ctx); 23 String base = new File("target/classes").getAbsolutePath(); 24 resources.addJarResources(new DirResourceSet(resources, "/WEB-INF/classes", base, "/")); 25 ctx.setResources(resources); 26 tomcat.start(); 27 tomcat.getServer().await(); 28 } 29 }
啟動後控制檯輸出如下,我們可以看到8080埠已經被監聽:
"C:\Program Files\Java\jdk-11\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:51854,suspend=y,server=n -Dfile.encoding=UTF-8 -classpath ....
Connected to the target VM, address: '127.0.0.1:51854', transport: 'socket'
11月 15, 2024 10:47:54 上午 org.apache.coyote.AbstractProtocol init
資訊: Initializing ProtocolHandler ["http-nio-8080"]
11月 15, 2024 10:47:54 上午 org.apache.catalina.core.StandardService startInternal
資訊: Starting service [Tomcat]
11月 15, 2024 10:47:54 上午 org.apache.catalina.core.StandardEngine startInternal
資訊: Starting Servlet engine: [Apache Tomcat/10.0.0]
11月 15, 2024 10:47:56 上午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
警告: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [1,753] milliseconds.
11月 15, 2024 10:47:56 上午 org.apache.coyote.AbstractProtocol start
資訊: Starting ProtocolHandler ["http-nio-8080"]