服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - 编程技术 - 版本历史&代码示例之:Servelt、JSP、EL表达式

版本历史&代码示例之:Servelt、JSP、EL表达式

2021-09-14 01:04BAT的乌托邦YourBatman 编程技术

Servlet是一种基于Java的动态Web资源动态Web资源技术,类似的技术还有ASP、PHP等。Servlet规范由Sun Microsystems公司创建,1.0版于1997年6月完成。从2.3版开始,该规范是在JCP下开发。

版本历史&代码示例之:Servelt、JSP、EL表达式

正文

版本历史&代码示例之:Servelt、JSP、EL表达式

Servlet

Servlet是一种基于Java的动态Web资源动态Web资源技术,类似的技术还有ASP、PHP等。

  1. <!-- javax命名空间版本(Tomcat 9.x及以下版本支持) --> 
  2. <dependency> 
  3.     <groupId>javax.servlet</groupId> 
  4.     <artifactId>javax.servlet-api</artifactId> 
  5.     <version>4.0.1</version> 
  6.     <scope>provided</scope> 
  7. </dependency> 
  8.  
  9. <!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) --> 
  10. <dependency> 
  11.     <groupId>jakarta.servlet</groupId> 
  12.     <artifactId>jakarta.servlet-api</artifactId> 
  13.     <version>5.0.0</version> 
  14.     <!-- <version>4.0.4</version> 此版本命名空间同javax --> 
  15.     <scope>provided</scope> 
  16. </dependency> 

版本历史

Servlet规范由Sun Microsystems公司创建,1.0版于1997年6月完成。从2.3版开始,该规范是在JCP下开发。

版本 发布日期 隶属于 JSR版本 焦点说明
1.0 1997.06 - - 首个版本,由Sun公司发布
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,增加了关于Session的Listener(如HttpSessionListener)
2.4 2003.08 J2EE 1.4 JSR 154 没增加大的新内容,对不严格的地方加了些校验,如:对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 史上最大变革。动态链接库和插件能力(Spring MVC利用此能力通过ServletContainerInitializer进行全注解驱动开发)、模块化开发、异步Servlet、安全性、新的文件上传API、支持WebSocket,新的注解(@WebServlet、@WebFilter、@WebListener),可脱离web.xml全注解驱动,此版本功能已经很完整了,应用的主流
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。从而支持服务器推技术,新的映射发现接口HttpServletMapping可用来提高内部的运行效率
5.0 2020.11 Jakarta EE 9 JSR 369 同Servlet 4.0(只是命名空间从javax.*变为了jakarta.*而已)

Spring Boot相关:

  • 2.0.0.RELEASE版本(2018.05):正式内置Servlet 3.1,毕竟Spring Web Flux从此版本开始(Spring 5)
  • 2.1.0.RELEASE版本(2018.10):升级到Servlet 4.x,直到现在(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版本(预计2022.12):基于Spring 6.x、Jakarta EE 9,基于GraalVM全面拥抱云原生的新一代框架

说明:Spring Boot 2.6和2.7都还会基于Spring Framework 5.3.x内核。Spring Framework 6.0版本在2021年9月正式拉开序幕,将基于全新的Jakarta EE 9(命名空间为jakarta.*,不向下兼容)平台开发,相应的Spring Boot 3也会基于此内核

生存现状

随着Spring 5的发布推出WebFlux,Servlet技术从之前的必选项变为可选项。

但考虑到业务开发使用WebFlux收益甚微但开发调试成本均增加,因此实际情况是基于Servlet的Spring MVC技术依旧是主流,暂时地位不可撼动,依旧非常活跃。

实现(框架)

由于Servlet由Web容器负责创建并调用,因此只要实现了Servlet规范的Web容器均可作为它的实现(框架),如Tomcat、Jetty、Undertow、JBoss、Glassfish等。

代码示例

导入依赖包:

scope一般provided即可,因为Web容器里会自带此Jar

Spring Boot场景下无需显示导入,因为Tomcat已内嵌(相关API)

  1. servlet-api的GAV 

继承HttpServlet写一个用于处理Http请求的Servlet处理器

  1. /** 
  2.  * 在此处添加备注信息 
  3.  * 
  4.  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a> 
  5.  * @site https://yourbatman.cn 
  6.  * @date 2021/9/12 06:23 
  7.  * @since 0.0.1 
  8.  */ 
  9. @WebServlet(urlPatterns = {"/hello"}) 
  10. public class HelloServlet extends HttpServlet { 
  11.  
  12.     @Override 
  13.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
  14.         resp.getWriter().write("hello servlet..."); 
  15.     } 

IDEA添加(外置)Tomcat 9.x版本,以war包形式部署到Tomcat(小提示: war ),并启动Tomcat

版本历史&代码示例之:Servelt、JSP、EL表达式

浏览器http://localhost:8080/hello即可完成正常访问。

说明:自Servlet 3.0之后,web.xml部署描述符并非必须(全注解即可搞定)

工程源代码:https://github.com/yourbatman/BATutopia-java-ee

JSP

Java Server Page的简称。那么,有了Servlet为何还需要JSP?其实它俩都属于动态Web技术,只是Servlet它用于输出页面简直太繁琐了(每一句html都需要用resp.getWriter()逐字逐句的输出),所以才出现了JSP技术来弥补其不足。

它使用JSP标签在HTML网页中插入Java代码。语法格式为:<% Java代码 %>。它有九大内置对象这么一说:

  1. 1、request:请求对象。javax.servlet.http.HttpServletRequest 
  2. 2、response:响应对象。javax.servlet.http.HttpServletResponse 
  3. 3、session:会话对象。javax.servlet.http.HttpSession 
  4. 4、application:应用程序对象。javax.servlet.ServletContext 
  5. 5、config:配置对象。javax.servlet.ServletConfig 
  6. 6、page:页面对象。当前jsp程序本身,相当于this 
  7. 7、pageContext:页面上下文对象。javax.servlet.jsp.PageContext 
  8. 8、out:输出流对象,用于输出内容到浏览器。javax.servlet.jsp.jspWriter 
  9. 9、exception:异常对象,只有在包含isErrorPage=”true”的页面中才可以被使用。java.lang.Throwable 

除了Servlet。与JSP 强相关 的技术还有EL表达式和JSP标签(JSTL),下面会接着介绍。

  1. <!-- javax命名空间版本(Tomcat 9.x及以下版本支持) --> 
  2. <dependency> 
  3.     <groupId>javax.servlet.jsp</groupId> 
  4.     <artifactId>javax.servlet.jsp-api</artifactId> 
  5.     <version>2.3.3</version> 
  6.     <scope>provided</scope> 
  7. </dependency> 
  8.  
  9. <!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) --> 
  10. <dependency> 
  11.     <groupId>jakarta.servlet.jsp</groupId> 
  12.     <artifactId>jakarta.servlet.jsp-api</artifactId> 
  13.     <version>3.0.0</version> 
  14.     <!-- <version>2.3.6</version> 此版本命名空间同javax --> 
  15.     <scope>provided</scope> 
  16. </dependency> 

版本历史

由于JSP的本质就是Servlet,它的的版本号需要与Servlet对应看待。

版本 发布日期 JSR版本 对应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相关:Spring Boot从1.x版本开始就一直没有“带”JSP一起玩,若要Spring Boot支持JSP需要特殊开启。

JSP 2.0是个重要版本,最重要的特性就是开始支持EL表达式了,可以用它来访问应用程序数据。JSP 2.3版本可断定是最后一个版本,因为JSP已走到尽头,成为历史。

生存现状

JSP诞生之后,程序员写页面写得确实很爽了。但是,它带来了坏处:很多程序员同学将业务逻辑、页面展示逻辑都往JSP塞,耦合在一起,导致JSP扛不住了,更重要的是程序员扛不住了,非常凌乱。

虽然后面出现了EL表达式和JSTL标签来帮助程序员不要在JSP里写Java代码,但只要不是强制的你能限制住自由的程序员么?然后呢,后来出现了Freemarker和Velocity这种模板引擎,使得程序员没有办法在页面上写Java代码了,达到了分离的效果。

模板引擎出现后,JSP的地位已经岌岌可危了。但真正杀死它的还是前端的崛起,从而进入前后端完全分离的状态,至此基本可以宣布JSP(甚至包括模板引擎)的死亡。

所以JSP目前的生存状态是:基本死亡状态。你看,这不Spring Boot(默认)都不带他玩了嘛~

实现(框架)

与Servlet相同的Web容器。

代码示例

导包。由于我们不可能直接使用JSP的API,因此99.9999%情况下无需导包。

  1. 无需导包 

创建webapp内容文件夹。这点很重要,因为是要创建一个web文件夹,以IDEA为例:在jsp-demo工程下添加web模块图片图片完成后工程目录结构如下:

版本历史&代码示例之:Servelt、JSP、EL表达式

版本历史&代码示例之:Servelt、JSP、EL表达式

完成后工程目录结构如下:

版本历史&代码示例之:Servelt、JSP、EL表达式

值得一提的是:web目录名称叫什么无所谓(只是很多喜欢叫webapp、webroot等),重要的是要有这个小圆点。不乏听见不少小伙伴说这个目录名必须叫webapp,其实它名字叫什么、甚至位置放在哪都无所谓,重要是找得到就行。掌握原理,一通百通。

这里附上HelloJsp的内容:

  1. /** 
  2.  * 在此处添加备注信息 
  3.  * 
  4.  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a> 
  5.  * @site https://yourbatman.cn 
  6.  * @date 2021/9/12 06:26 
  7.  * @since 0.0.1 
  8.  */ 
  9. @WebServlet(urlPatterns = {"/hellojsp"}) 
  10. public class HelloJsp extends HttpServlet { 
  11.  
  12.     @Override 
  13.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
  14.         RequestDispatcher requestDispatcher = request.getRequestDispatcher("hello.jsp"); 
  15.         // 放在WBE-INF下面的.jsp页面必须通过Servlet转发才能访问到,更加安全 
  16.         // RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/hello.jsp"); 
  17.         requestDispatcher.forward(request, response); 
  18.     } 

以war包形式部署至Tomcat图片浏览器访问下面两个路径均可得到响应结果:

  • http://localhost:8080/hellojsp:请求 -> Servlet转发 -> jsp页面(即使jsp页面放到WEB-INF目录下依旧可访问)
  • http://localhost:8080/hello.jsp:请求 -> jsp页面(此直接方式只能访问非WEB-INF目录下的jsp文件)

页面响应:图片

再强调一遍:自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表达式 },只能读取数据不能设置数据(设置数据用JSP内或者Servlet里的Java代码均可)

请务必注意,基本语法中右边的}的前面有个空格,使用时请务必注意

在EL中有四大域对象和11大内置对象这么一说:

  • 请求参数
  1. 1、param 包含所有的参数的Map,可以获取参数返回String。其底层实际调用request.getParameter() 
  2.  - name=${param.name } 
  3. 2、paramValues 包含所有参数的Map,可以获取参数的数组返回String[]。其底层实际调用request.getParameterValues() 
  4.  - hobby[0]=${paramValues.hobby[0] } 
  • 头信息
  1. 3、header 包含所有的头信息的Map,可以获取头信息返回String。 
  2.  - ${header.Connection } 
  3. 4、headerValues 包含所有的头信息的Map,可以获取头信息数组返回String[]。 
  4.  - ${headerValues["user-agent"][0] } 
  • Cookie
  1. 5、cookie包含所有cookie的Map,key为Cookie的name属性值 
  2.  - ${cookie.JSESSIONID.name } 
  • 初始化参数
  1. 6、iniParam 包含所有的初始化参数(一般配在web.xml里)的Map,可以获取初始化的参数 
  2.  - ${initParam.username} ${initParam.password
  • 四大作用域(重点)
  1. 7、pageScope 包含page作用域内的Map 
  2.  - ${pageScope.name } 
  3. 8、requestScope 包含request作用域内的Map 
  4.  - ${requestScope.name } 
  5. 9、 包含session作用域内的Map 
  6.  - ${sessionScope.name } 
  7. 10、applicationScope 包含application作用域内的Map 
  8.  - ${applicationScope.name } 
  • 页面上下文
  1. 11、pageContext 包含页面内的变量的Map,可获取JSP中的九大内置对象 
  2.  - ${pageContext.request.scheme } 
  3.  - ${pageContext.session.id} 
  1. <!-- javax命名空间版本(Tomcat 9.x及以下版本支持) --> 
  2. <dependency> 
  3.     <groupId>javax.el</groupId> 
  4.     <artifactId>javax.el-api</artifactId> 
  5.     <version>3.0.0</version> 
  6. </dependency> 
  7.  
  8. <!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) --> 
  9. <dependency> 
  10.     <groupId>jakarta.el</groupId> 
  11.     <artifactId>jakarta.el-api</artifactId> 
  12.     <version>4.0.0</version> 
  13.     <!-- <version>3.0.3</version> 此版本命名空间同javax --> 
  14. </dependency> 
  15.  
  16. 除此之外,还可以通过Tomcat的GAV直接导入,版本号同Tomcat 
  17. <dependency> 
  18.     <groupId>org.apache.tomcat</groupId> 
  19.     <artifactId>tomcat-el-api</artifactId> 
  20.     <version>Tomcat版本号</version> <!-- 9.x版本是javax.*,10.x以及后面是jakarta.* --> 
  21. </dependency> 
  22. 嵌入式Tomcat提供的实现 
  23. <dependency> 
  24.     <groupId>org.apache.tomcat.embed</groupId> 
  25.     <artifactId>tomcat-embed-el</artifactId> 
  26.     <version>Tomcat版本号</version> <!-- 9.x版本是javax.*,10.x以及后面是jakarta.* --> 
  27. </dependency> 
  28.  
  29. 另外,还有二合一的GAV:3.x版本的API和impl实现都在一个jar里。 
  30. 4.x使用jakarta.*命名空间,并且API分离(依赖于)jakarta.el-api 
  31. <dependency> 
  32.     <groupId>org.glassfish</groupId> 
  33.     <artifactId>jakarta.el</artifactId> 
  34.     <version>4.0.2</version> 
  35.     <!-- <version>3.0.3</version> 此版本命名空间同javax --> 
  36. </dependency> 

值得注意的是,EL并非Web独享而是可独立使用,因此它的scope用默认的即可。另外,这只是API,并非Impl实现,是不能直接运行的,否则会遇到类似如下异常:

  1. Caused by: javax.el.ELException: Provider com.sun.el.ExpressionFactoryImpl not found 
  2.  at javax.el.FactoryFinder.newInstance(FactoryFinder.java:101) 
  3.  ... 

版本历史

EL从JSP 2.0版本开始引入,用于在JSP页面获取数据的简单方式。因此它是随着JSP的发展而出现的,只是可独立使用而已。

版本 发布日期 JSR版本 对应JSP版本 对应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月份发布(可认为是最后一次功能升级),它的新特性包括:字符串拼接操作符、赋值(以前只能读取,现在可以赋值啦)、分号操作符、对象方法调用(以前只能用JavaBean属性导航)、Lambda表达式、静态字段/方法调用、构造器调用、Java8集合操作。具体就不一一举例了,详细情况可阅读我收录的JSR文档。

生存现状

随着JSP的消亡,EL的存在感越来越弱。

好在它可以作为单独的表达式语言使用,有Hibernate Validator对它是强依赖,所以生命力还行。但由于Hibernate Validator里使用得简单,所以EL并没有必要再更新(动力不足)。

实现(框架)

EL大部分情况下伴随着JSP一起使用,所以交由Web容器去解析实现。

另外,EL作为一种表达式语言,也可以作为”工具“供以使用,比如著名的Hibernate Validator内部就依赖于EL表达式语言来书写校验规则(所以它在编译期就强依赖于EL的API)。

代码示例

在JSP中使用EL是由org.apache.tomcat:tomcat-jasper-el或者org.apache.tomcat.embed:tomcat-embed-jasper完成和JSP的整合,以及解析支持的。在JSP页面里使用方式由于已经过时(主要是使用示例一搜一大把),这里为了节约篇幅,就略了哈。

如果把EL当做工具使用的话(比如Hibernate Validator用来错误消息里插值用),需要了解一些API和常见用法,演示一下:

导包:

  1. 上面的GAV随便选一个(记得太impl实现,推荐org.glassfish:jakarta.el) 

直接使用API书写Demo

  1. /** 
  2.  * 在此处添加备注信息 
  3.  * 
  4.  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a> 
  5.  * @site https://yourbatman.cn 
  6.  * @date 2021/9/12 10:12 
  7.  * @since 0.0.1 
  8.  */ 
  9. public class ElDemo { 
  10.  
  11.     public static void main(String[] args) { 
  12.         ExpressionFactory factory = ELManager.getExpressionFactory(); 
  13.         StandardELContext elContext = new StandardELContext(factory); 
  14.  
  15.         // 将instance转为对应类型 
  16.         ValueExpression valueExpression = factory.createValueExpression("18"Integer.class); 
  17.         System.out.println(valueExpression.getValue(elContext)); 
  18.  
  19.         // 计算表达式的值 
  20.         valueExpression = factory.createValueExpression(elContext, "${1+1}"Integer.class); 
  21.         System.out.println(valueExpression.getValue(elContext)); 
  22.  
  23.         // 方法调用 
  24.         // MethodExpression methodExpression = factory.createMethodExpression(elContext, "${Math.addExact()}"Integer.class, new Class[]{Integer.class, Integer.class}); 
  25.         // System.out.println(methodExpression.invoke(elContext, new Object[]{1, 2})); 
  26.     } 
  27.  
  28.  
  29. 运行,结果输出: 
  30. 18 

工程源代码:https://github.com/yourbatman/BATutopia-java-ee

总结

现在越来越卷的IT行业,衡量一个求职者的专业能力,深度往往比广度更为重要。

正所谓这辈子听过很多大道理,却依旧过不好这一生;技术也一样,听过/知道过/使用过很多技术,但依旧写不出好的代码。究其原因,就是理解不深刻。

自上而下的用,自底向上的学,这是我个人一直秉承的一个观念。知道一门技术、使用一门技术一般几个小时or几天就能大概搞定(毕竟如果一门技术入门很难的话也几乎不太可能大众化的流行起来),而理解一门技术的单位可能就是月、甚至是年了,这需要静下心来学习和研究。

原文链接:https://mp.weixin.qq.com/s/j14hlm5qk2wf0Pi3fNUvFA

延伸 · 阅读

精彩推荐