新聞中心
[[423628]]
正文
Servlet
Servlet是一種基于Java的動態(tài)Web資源動態(tài)Web資源技術(shù),類似的技術(shù)還有ASP、PHP等。

javax.servlet javax.servlet-api 4.0.1 provided jakarta.servlet jakarta.servlet-api 5.0.0 provided
版本歷史
Servlet規(guī)范由Sun Microsystems公司創(chuàng)建,1.0版于1997年6月完成。從2.3版開始,該規(guī)范是在JCP下開發(fā)。
| 版本 | 發(fā)布日期 | 隸屬于 | JSR版本 | 焦點說明 |
|---|---|---|---|---|
| 1.0 | 1997.06 | - | - | 首個版本,由Sun公司發(fā)布 |
| 2.0 | 1997.08 | - | - | |
| 2.1 | 1998.11 | - | - | 新增了RequestDispatcher, ServletContext等 |
| 2.2 | 1999.08 | J2EE 1.2 | - | 成為J2EE的一部分。在.war文件中引入了self-contained Web applications的概念 |
| 2.3 | 2001.08 | J2EE 1.3 | JSR 53 | 增加了Filter,增加了關(guān)于Session的Listener(如HttpSessionListener) |
| 2.4 | 2003.08 | J2EE 1.4 | JSR 154 | 沒增加大的新內(nèi)容,對不嚴格的地方加了些校驗,如:對web.xml使用XML Schema |
| 2.5 | 2005.09 | Java EE 5 | JSR 154 | 最低要求JDK 5。注解支持(如@WebService、@WebMethod等,注意不是@WebServlet這種哦) |
| 3.0 | 2009.12 | Java EE 6 | JSR 315 | 史上最大變革。動態(tài)鏈接庫和插件能力(Spring MVC利用此能力通過ServletContainerInitializer進行全注解驅(qū)動開發(fā))、模塊化開發(fā)、異步Servlet、安全性、新的文件上傳API、支持WebSocket,新的注解(@WebServlet、@WebFilter、@WebListener),可脫離web.xml全注解驅(qū)動,此版本功能已經(jīng)很完整了,應(yīng)用的主流 |
| 3.1 | 2013.5 | Java EE 7 | JSR 340 | 新增非阻塞式IO。Spring的Web Flux若要運行在Servlet容器,至少需要此版本,因為從此版本起才有非阻斷輸入輸出的支持 |
| 4.0 | 2017.09 | Java EE 8 | JSR 369 | 支持Http/2。從而支持服務(wù)器推技術(shù),新的映射發(fā)現(xiàn)接口HttpServletMapping可用來提高內(nèi)部的運行效率 |
| 5.0 | 2020.11 | Jakarta EE 9 | JSR 369 | 同Servlet 4.0(只是命名空間從javax.*變?yōu)榱?code>jakarta.*而已) |
Spring Boot相關(guān):
- 2.0.0.RELEASE版本(2018.05):正式內(nèi)置Servlet 3.1,畢竟Spring Web Flux從此版本開始(Spring 5)
- 2.1.0.RELEASE版本(2018.10):升級到Servlet 4.x,直到現(xiàn)在(2.6.x)也依舊是4.x版本
- 2.2.0.RELEASE版本(2019.10):開始支持jakarta.servlet這個GAV,(和javax.servlet)二者并行
- 2.5.0/2.6.0版本(2021.05):無變化
- 3.0.0版本(預(yù)計2022.12):基于Spring 6.x、Jakarta EE 9,基于GraalVM全面擁抱云原生的新一代框架
說明:Spring Boot 2.6和2.7都還會基于Spring Framework 5.3.x內(nèi)核。Spring Framework 6.0版本在2021年9月正式拉開序幕,將基于全新的Jakarta EE 9(命名空間為jakarta.*,不向下兼容)平臺開發(fā),相應(yīng)的Spring Boot 3也會基于此內(nèi)核
生存現(xiàn)狀
隨著Spring 5的發(fā)布推出WebFlux,Servlet技術(shù)從之前的必選項變?yōu)榭蛇x項。
但考慮到業(yè)務(wù)開發(fā)使用WebFlux收益甚微但開發(fā)調(diào)試成本均增加,因此實際情況是基于Servlet的Spring MVC技術(shù)依舊是主流,暫時地位不可撼動,依舊非?;钴S。
實現(xiàn)(框架)
由于Servlet由Web容器負責(zé)創(chuàng)建并調(diào)用,因此只要實現(xiàn)了Servlet規(guī)范的Web容器均可作為它的實現(xiàn)(框架),如Tomcat、Jetty、Undertow、JBoss、Glassfish等。
代碼示例
導(dǎo)入依賴包:
scope一般provided即可,因為Web容器里會自帶此Jar
Spring Boot場景下無需顯示導(dǎo)入,因為Tomcat已內(nèi)嵌(相關(guān)API)
- servlet-api的GAV
繼承HttpServlet寫一個用于處理Http請求的Servlet處理器
- /**
- * 在此處添加備注信息
- *
- * @author YourBatman. Send email to me
- * @site https://yourbatman.cn
- * @date 2021/9/12 06:23
- * @since 0.0.1
- */
- @WebServlet(urlPatterns = {"/hello"})
- public class HelloServlet extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- resp.getWriter().write("hello servlet...");
- }
- }
IDEA添加(外置)Tomcat 9.x版本,以war包形式部署到Tomcat(小提示: war ),并啟動Tomcat
瀏覽器http://localhost:8080/hello即可完成正常訪問。
說明:自Servlet 3.0之后,web.xml部署描述符并非必須(全注解即可搞定)
工程源代碼:https://github.com/yourbatman/BATutopia-java-ee
JSP
Java Server Page的簡稱。那么,有了Servlet為何還需要JSP?其實它倆都屬于動態(tài)Web技術(shù),只是Servlet它用于輸出頁面簡直太繁瑣了(每一句html都需要用resp.getWriter()逐字逐句的輸出),所以才出現(xiàn)了JSP技術(shù)來彌補其不足。
它使用JSP標簽在HTML網(wǎng)頁中插入Java代碼。語法格式為:<% Java代碼 %>。它有九大內(nèi)置對象這么一說:
- 1、request:請求對象。javax.servlet.http.HttpServletRequest
- 2、response:響應(yīng)對象。javax.servlet.http.HttpServletResponse
- 3、session:會話對象。javax.servlet.http.HttpSession
- 4、application:應(yīng)用程序?qū)ο?。javax.servlet.ServletContext
- 5、config:配置對象。javax.servlet.ServletConfig
- 6、page:頁面對象。當前jsp程序本身,相當于this
- 7、pageContext:頁面上下文對象。javax.servlet.jsp.PageContext
- 8、out:輸出流對象,用于輸出內(nèi)容到瀏覽器。javax.servlet.jsp.jspWriter
- 9、exception:異常對象,只有在包含isErrorPage=”true”的頁面中才可以被使用。java.lang.Throwable
除了Servlet。與JSP 強相關(guān) 的技術(shù)還有EL表達式和JSP標簽(JSTL),下面會接著介紹。
javax.servlet.jsp javax.servlet.jsp-api 2.3.3 provided jakarta.servlet.jsp jakarta.servlet.jsp-api 3.0.0 provided
版本歷史
由于JSP的本質(zhì)就是Servlet,它的的版本號需要與Servlet對應(yīng)看待。
| 版本 | 發(fā)布日期 | JSR版本 | 對應(yīng)Servlet版本 |
|---|---|---|---|
| JSP 1.1 | 2000.07 | JSR 906 | Servlet 2.2 |
| JSP 1.2 | 2002.06 | JSR 53 | Servlet 2.3 |
| JSP 2.0 | 2003.11 | JSR 152 | Servlet 2.4 |
| JSP 2.1 | 2005.09 | JSR 245 | Servlet 2.5 |
| JSP 2.2 | 2009.12 | JSR 245(升級版) | Servlet 3.0 |
| JSP 2.3 | 2013.05 | JSR 372(升級版) | Servlet 3.1 |
| JSP 3.0 | 2020.11 | ----(Jakarta旗下) | Servlet 5.x |
Spring Boot相關(guān):Spring Boot從1.x版本開始就一直沒有“帶”JSP一起玩,若要Spring Boot支持JSP需要特殊開啟。
JSP 2.0是個重要版本,最重要的特性就是開始支持EL表達式了,可以用它來訪問應(yīng)用程序數(shù)據(jù)。JSP 2.3版本可斷定是最后一個版本,因為JSP已走到盡頭,成為歷史。
生存現(xiàn)狀
JSP誕生之后,程序員寫頁面寫得確實很爽了。但是,它帶來了壞處:很多程序員同學(xué)將業(yè)務(wù)邏輯、頁面展示邏輯都往JSP塞,耦合在一起,導(dǎo)致JSP扛不住了,更重要的是程序員扛不住了,非常凌亂。
雖然后面出現(xiàn)了EL表達式和JSTL標簽來幫助程序員不要在JSP里寫Java代碼,但只要不是強制的你能限制住自由的程序員么?然后呢,后來出現(xiàn)了Freemarker和Velocity這種模板引擎,使得程序員沒有辦法在頁面上寫Java代碼了,達到了分離的效果。
模板引擎出現(xiàn)后,JSP的地位已經(jīng)岌岌可危了。但真正殺死它的還是前端的崛起,從而進入前后端完全分離的狀態(tài),至此基本可以宣布JSP(甚至包括模板引擎)的死亡。
所以JSP目前的生存狀態(tài)是:基本死亡狀態(tài)。你看,這不Spring Boot(默認)都不帶他玩了嘛~
實現(xiàn)(框架)
與Servlet相同的Web容器。
代碼示例
導(dǎo)包。由于我們不可能直接使用JSP的API,因此99.9999%情況下無需導(dǎo)包。
- 無需導(dǎo)包
創(chuàng)建webapp內(nèi)容文件夾。這點很重要,因為是要創(chuàng)建一個web文件夾,以IDEA為例:在jsp-demo工程下添加web模塊圖片圖片完成后工程目錄結(jié)構(gòu)如下:
完成后工程目錄結(jié)構(gòu)如下:
值得一提的是:web目錄名稱叫什么無所謂(只是很多喜歡叫webapp、webroot等),重要的是要有這個小圓點。不乏聽見不少小伙伴說這個目錄名必須叫webapp,其實它名字叫什么、甚至位置放在哪都無所謂,重要是找得到就行。掌握原理,一通百通。
這里附上HelloJsp的內(nèi)容:
- /**
- * 在此處添加備注信息
- *
- * @author YourBatman. Send email to me
- * @site https://yourbatman.cn
- * @date 2021/9/12 06:26
- * @since 0.0.1
- */
- @WebServlet(urlPatterns = {"/hellojsp"})
- public class HelloJsp extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- RequestDispatcher requestDispatcher = request.getRequestDispatcher("hello.jsp");
- // 放在WBE-INF下面的.jsp頁面必須通過Servlet轉(zhuǎn)發(fā)才能訪問到,更加安全
- // RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/hello.jsp");
- requestDispatcher.forward(request, response);
- }
- }
以war包形式部署至Tomcat圖片瀏覽器訪問下面兩個路徑均可得到響應(yīng)結(jié)果:
- http://localhost:8080/hellojsp:請求 -> Servlet轉(zhuǎn)發(fā) -> jsp頁面(即使jsp頁面放到WEB-INF目錄下依舊可訪問)
- http://localhost:8080/hello.jsp:請求 -> jsp頁面(此直接方式只能訪問非WEB-INF目錄下的jsp文件)
頁面響應(yīng):
再強調(diào)一遍:自Servlet 3.0之后,web.xml部署描述符并非必須。即使有jsp頁面也是一樣~~~
工程源代碼:https://github.com/yourbatman/BATutopia-java-ee
EL表達式
Expression Language表達式語言。EL表達式語言的靈感來自于ECMAScript和XPath表達式語言(表達式語言當然還有比較著名的Spring的SpEL,以及OGNL),它提供了在 JSP 中簡化表達式的方法,目的是替代掉在Jsp里寫Java代碼,讓Jsp的代碼更加簡化。
基本語法為:${EL表達式 },只能讀取數(shù)據(jù)不能設(shè)置數(shù)據(jù)(設(shè)置數(shù)據(jù)用JSP內(nèi)或者Servlet里的Java代碼均可)
請務(wù)必注意,基本語法中右邊的}的前面有個空格,使用時請務(wù)必注意
在EL中有四大域?qū)ο蠛?1大內(nèi)置對象這么一說:
- 請求參數(shù)
- 1、param 包含所有的參數(shù)的Map,可以獲取參數(shù)返回String。其底層實際調(diào)用request.getParameter()
- - name=${param.name }
- 2、paramValues 包含所有參數(shù)的Map,可以獲取參數(shù)的數(shù)組返回String[]。其底層實際調(diào)用request.getParameterValues()
- - hobby[0]=${paramValues.hobby[0] }
- 頭信息
- 3、header 包含所有的頭信息的Map,可以獲取頭信息返回String。
- - ${header.Connection }
- 4、headerValues 包含所有的頭信息的Map,可以獲取頭信息數(shù)組返回String[]。
- - ${headerValues["user-agent"][0] }
- Cookie
- 5、cookie包含所有cookie的Map,key為Cookie的name屬性值
- - ${cookie.JSESSIONID.name }
- 初始化參數(shù)
- 6、iniParam 包含所有的初始化參數(shù)(一般配在web.xml里)的Map,可以獲取初始化的參數(shù)
- - ${initParam.username} ${initParam.password}
- 四大作用域(重點)
- 7、pageScope 包含page作用域內(nèi)的Map
- - ${pageScope.name }
- 8、requestScope 包含request作用域內(nèi)的Map
- - ${requestScope.name }
- 9、 包含session作用域內(nèi)的Map
- - ${sessionScope.name }
- 10、applicationScope 包含application作用域內(nèi)的Map
- - ${applicationScope.name }
- 頁面上下文
- 11、pageContext 包含頁面內(nèi)的變量的Map,可獲取JSP中的九大內(nèi)置對象
- - ${pageContext.request.scheme }
- - ${pageContext.session.id}
javax.el javax.el-api 3.0.0 jakarta.el jakarta.el-api 4.0.0 - 除此之外,還可以通過Tomcat的GAV直接導(dǎo)入,版本號同Tomcat
org.apache.tomcat tomcat-el-api Tomcat版本號 - 嵌入式Tomcat提供的實現(xiàn)
org.apache.tomcat.embed tomcat-embed-el Tomcat版本號 - 另外,還有二合一的GAV:3.x版本的API和impl實現(xiàn)都在一個jar里。
- 4.x使用jakarta.*命名空間,并且API分離(依賴于)jakarta.el-api
org.glassfish jakarta.el 4.0.2
值得注意的是,EL并非Web獨享而是可獨立使用,因此它的scope用默認的即可。另外,這只是API,并非Impl實現(xiàn),是不能直接運行的,否則會遇到類似如下異常:
- Caused by: javax.el.ELException: Provider com.sun.el.ExpressionFactoryImpl not found
- at javax.el.FactoryFinder.newInstance(FactoryFinder.java:101)
- ...
版本歷史
EL從JSP 2.0版本開始引入,用于在JSP頁面獲取數(shù)據(jù)的簡單方式。因此它是隨著JSP的發(fā)展而出現(xiàn)的,只是可獨立使用而已。
| 版本 | 發(fā)布日期 | JSR版本 | 對應(yīng)JSP版本 | 對應(yīng)Servlet版本 |
|---|---|---|---|---|
| EL 2.0 | 2003.11 | JSR 152 | JSP 2.0 | Servlet 2.4 |
| EL 2.2 | 2009.12 | JSR 245 | JSP 2.2 | Servlet 2.5 |
| EL 3.0 | 2013.05 | JSR 341 | JSP 2.3 | Servlet 3.1 |
| EL 4.0 | 2020.10 | 納入Jakarta | JSP 3.0 | Servlet 5.0 |
EL表達式3.0于2013年4月份發(fā)布(可認為是最后一次功能升級),它的新特性包括:字符串拼接操作符、賦值(以前只能讀取,現(xiàn)在可以賦值啦)、分號操作符、對象方法調(diào)用(以前只能用JavaBean屬性導(dǎo)航)、Lambda表達式、靜態(tài)字段/方法調(diào)用、構(gòu)造器調(diào)用、Java8集合操作。具體就不一一舉例了,詳細情況可閱讀我收錄的JSR文檔。
生存現(xiàn)狀
隨著JSP的消亡,EL的存在感越來越弱。
好在它可以作為單獨的表達式語言使用,有Hibernate Validator對它是強依賴,所以生命力還行。但由于Hibernate Validator里使用得簡單,所以EL并沒有必要再更新(動力不足)。
實現(xiàn)(框架)
EL大部分情況下伴隨著JSP一起使用,所以交由Web容器去解析實現(xiàn)。
另外,EL作為一種表達式語言,也可以作為”工具“供以使用,比如著名的Hibernate Validator內(nèi)部就依賴于EL表達式語言來書寫校驗規(guī)則(所以它在編譯期就強依賴于EL的API)。
代碼示例
在JSP中使用EL是由org.apache.tomcat:tomcat-jasper-el或者org.apache.tomcat.embed:tomcat-embed-jasper完成和JSP的整合,以及解析支持的。在JSP頁面里使用方式由于已經(jīng)過時(主要是使用示例一搜一大把),這里為了節(jié)約篇幅,就略了哈。
如果把EL當做工具使用的話(比如Hibernate Validator用來錯誤消息里插值用),需要了解一些API和常見用法,演示一下:
導(dǎo)包:
- 上面的GAV隨便選一個(記得太impl實現(xiàn),推薦org.glassfish:jakarta.el)
直接使用API書寫Demo
- /**
- * 在此處添加備注信息
- *
- * @author YourBatman. Send email to me
- * @site https://yourbatman.cn
- * @date 2021/9/12 10:12
- * @since 0.0.1
- */
- public class ElDemo {
- public static void main(String[] args) {
- ExpressionFactory factory = ELManager.getExpressionFactory();
- StandardELContext elContext = new StandardELContext(factory);
- // 將instance轉(zhuǎn)為對應(yīng)類型
- ValueExpression valueExpression = factory.createValueExpression("18", Integer.class);
- System.out.println(valueExpression.getValue(elContext));
- // 計算表達式的值
- valueExpression = factory.createValueExpression(elContext, "${1+1}", Integer.class);
- System.out.println(valueExpression.getValue(elContext));
- // 方法調(diào)用
- // MethodExpression methodExpression = factory.createMethodExpression(elContext, "${Math.addExact()}", Integer.class, new Class[]{Integer.class, Integer.class});
- // System.out.println(methodExpression.invoke(elContext, new Object[]{1, 2}));
- }
- }
- 運行,結(jié)果輸出:
- 18
- 2
工程源代碼:https://github.com/yourbatman/BATutopia-java-ee
總結(jié)
現(xiàn)在越來越卷的IT行業(yè),衡量一個求職者的專業(yè)能力,深度往往比廣度更為重要。
正所謂這輩子聽過很多大道理,卻依舊過不好這一生;技術(shù)也一樣,聽過/知道過/使用過很多技術(shù),但依舊寫不出好的代碼。究其原因,就是理解不深刻。
自上而下的用,自底向上的學(xué),這是我個人一直秉承的一個觀念。知道一門技術(shù)、使用一門技術(shù)一般幾個小時or幾天就能大概搞定(畢竟如果一門技術(shù)入門很難的話也幾乎不太可能大眾化的流行起來),而理解一門技術(shù)的單位可能就是月、甚至是年了,這需要靜下心來學(xué)習(xí)和研究。
新聞名稱:版本歷史&代碼示例之Servelt、JSP、EL表達式
URL網(wǎng)址:http://www.dlmjj.cn/article/cdodihh.html


咨詢
建站咨詢
