【方向盘】版本历史&代码示例之:Servelt、JSP、EL表达式

工具好,也要用得巧。
本文已被https://yourbatman.cn收录;女娲Knife-Initializr工程可公开访问啦;程序员专用网盘https://wangpan.yourbatman.cn;公号后台回复“专栏列表”获取全部小而美的原创技术专栏

你好,我是方向盘(YourBatman、方哥)。笔者的公号(Java方向盘)是保留地,只分享原创,不转载、不发商务广告!!!

✍前言

若你还不太清楚Java EE是什么,可先移步这里:什么是Java EE?

最近一段时间,将Java EE/Jakarta EE进行了科普,almost也许可能大概是全网最全的,颇受好评。本专栏全部内容可点击上方专栏标题查看,这里做简单陈列:

本以为科普到这就差不多了告一段落的,直到有小伙伴私信我说:看了这么多但依旧不知道Java EE如何使用?当头棒喝,作为一名Javaer,其实天天都在使用着Java EE。只是在Spring框架的襁褓之下,它优秀的抽象能力甚至让开发者感知不到底层技术的存在。

在这里插入图片描述
本着管生管养,管杀管埋的初心,决定再续写几篇,针对每一项(主流)Java技术给出示例,主要包括这几个方面:

  • 版本历史
  • 生存现状
  • 实现(框架)
  • 代码示例
所属专栏
相关下载
版本约定
  • Java EE:6、7、8
  • Jakarta EE:8、9、9.1

✍正文

在这里插入图片描述

Servlet

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

<!-- javax命名空间版本(Tomcat 9.x及以下版本支持) -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

<!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) -->
<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>5.0.0</version>
    <!-- <version>4.0.4</version> 此版本命名空间同javax -->
    <scope>provided</scope>
</dependency>

✌版本历史

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

版本发布日期隶属于JSR版本焦点说明
1.01997.06--首个版本,由Sun公司发布
2.01997.08--
2.11998.11--新增了RequestDispatcher, ServletContext等
2.21999.08J2EE 1.2-成为J2EE的一部分。在.war文件中引入了self-contained Web applications的概念
2.32001.08J2EE 1.3JSR 53增加了Filter,增加了关于Session的Listener(如HttpSessionListener)
2.42003.08J2EE 1.4JSR 154没增加大的新内容,对不严格的地方加了些校验,如:对web.xml使用XML Schema
2.52005.09Java EE 5JSR 154最低要求JDK 5。注解支持(如@WebService、@WebMethod等,注意不是@WebServlet这种哦)
3.02009.12Java EE 6JSR 315史上最大变革。动态链接库和插件能力(Spring MVC利用此能力通过ServletContainerInitializer进行全注解驱动开发)、模块化开发、异步Servlet、安全性、新的文件上传API、支持WebSocket,新的注解(@WebServlet、@WebFilter、@WebListener),可脱离web.xml全注解驱动,此版本功能已经很完整了,应用的主流
3.12013.5Java EE 7JSR 340新增非阻塞式IO。Spring的Web Flux若要运行在Servlet容器,至少需要此版本,因为从此版本起才有非阻断输入输出的支持
4.02017.09Java EE 8JSR 369支持Http/2。从而支持服务器推技术,新的映射发现接口HttpServletMapping可用来提高内部的运行效率
5.02020.11Jakarta EE 9JSR 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等。

✌代码示例

导入依赖包:

  1. scope一般provided即可,因为Web容器里会自带此Jar
  2. Spring Boot场景下无需显示导入,因为Tomcat已内嵌(相关API)
servlet-api的GAV

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

/**
 * 在此处添加备注信息
 *
 * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>
 * @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(小提示:<packaging>war</packaging>),并启动Tomcat
在这里插入图片描述
浏览器http://localhost:8080/hello即可完成正常访问。

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

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

JSP

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

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

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

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

<!-- javax命名空间版本(Tomcat 9.x及以下版本支持) -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
    <scope>provided</scope>
</dependency>

<!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) -->
<dependency>
    <groupId>jakarta.servlet.jsp</groupId>
    <artifactId>jakarta.servlet.jsp-api</artifactId>
    <version>3.0.0</version>
    <!-- <version>2.3.6</version> 此版本命名空间同javax -->
    <scope>provided</scope>
</dependency>

✌版本历史

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

版本发布日期JSR版本对应Servlet版本
JSP 1.12000.07JSR 906Servlet 2.2
JSP 1.22002.06JSR 53Servlet 2.3
JSP 2.02003.11JSR 152Servlet 2.4
JSP 2.12005.09JSR 245Servlet 2.5
JSP 2.22009.12JSR 245(升级版)Servlet 3.0
JSP 2.32013.05JSR 372(升级版)Servlet 3.1
JSP 3.02020.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%情况下无需导包。

无需导包

创建webapp内容文件夹。这点很重要,因为是要创建一个web文件夹,以IDEA为例:在jsp-demo工程下添加web模块
在这里插入图片描述
在这里插入图片描述
完成后工程目录结构如下:
在这里插入图片描述
值得一提的是:web目录名称叫什么无所谓(只是很多喜欢叫webapp、webroot等),重要的是要有这个小圆点。不乏听见不少小伙伴说这个目录名必须叫webapp,其实它名字叫什么、甚至位置放在哪都无所谓,重要是找得到就行。掌握原理,一通百通。

这里附上HelloJsp的内容:

/**
 * 在此处添加备注信息
 *
 * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>
 * @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转发才能访问到,更加安全
        // RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/hello.jsp");
        requestDispatcher.forward(request, response);
    }
}

以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/FXP-java-ee

EL表达式

Expression Language表达式语言。EL表达式语言的灵感来自于ECMAScriptXPath表达式语言(表达式语言当然还有比较著名的Spring的SpEL,以及OGNL),它提供了在 JSP 中简化表达式的方法,目的是替代掉在Jsp里写Java代码,让Jsp的代码更加简化。

基本语法为:${EL表达式 },只能读取数据不能设置数据(设置数据用JSP内或者Servlet里的Java代码均可)

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

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

  • 请求参数
1、param 包含所有的参数的Map,可以获取参数返回String。其底层实际调用request.getParameter()
	- name=${param.name }
2、paramValues 包含所有参数的Map,可以获取参数的数组返回String[]。其底层实际调用request.getParameterValues()
	- hobby[0]=${paramValues.hobby[0] }
  • 头信息
3、header 包含所有的头信息的Map,可以获取头信息返回String- ${header.Connection }
4、headerValues 包含所有的头信息的Map,可以获取头信息数组返回String[]- ${headerValues["user-agent"][0] }
  • Cookie
5、cookie包含所有cookie的Map,key为Cookie的name属性值
	- ${cookie.JSESSIONID.name }
  • 初始化参数
6、iniParam 包含所有的初始化参数(一般配在web.xml里)的Map,可以获取初始化的参数
	- ${initParam.username} ${initParam.password}
  • 四大作用域(重点)
7、pageScope 包含page作用域内的Map
	- ${pageScope.name }
8、requestScope 包含request作用域内的Map
	- ${requestScope.name }
9、 包含session作用域内的Map
	- ${sessionScope.name }
10、applicationScope 包含application作用域内的Map
	- ${applicationScope.name }
  • 页面上下文
11、pageContext 包含页面内的变量的Map,可获取JSP中的九大内置对象
	- ${pageContext.request.scheme }
	- ${pageContext.session.id}
<!-- javax命名空间版本(Tomcat 9.x及以下版本支持) -->
<dependency>
    <groupId>javax.el</groupId>
    <artifactId>javax.el-api</artifactId>
    <version>3.0.0</version>
</dependency>

<!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) -->
<dependency>
    <groupId>jakarta.el</groupId>
    <artifactId>jakarta.el-api</artifactId>
    <version>4.0.0</version>
    <!-- <version>3.0.3</version> 此版本命名空间同javax -->
</dependency>

除此之外,还可以通过Tomcat的GAV直接导入,版本号同Tomcat
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-el-api</artifactId>
    <version>Tomcat版本号</version> <!-- 9.x版本是javax.*,10.x以及后面是jakarta.* -->
</dependency>
嵌入式Tomcat提供的实现
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-el</artifactId>
    <version>Tomcat版本号</version> <!-- 9.x版本是javax.*,10.x以及后面是jakarta.* -->
</dependency>

另外,还有二合一的GAV:3.x版本的API和impl实现都在一个jar里。
4.x使用jakarta.*命名空间,并且API分离(依赖于)jakarta.el-api
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.el</artifactId>
    <version>4.0.2</version>
    <!-- <version>3.0.3</version> 此版本命名空间同javax -->
</dependency>

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

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页面获取数据的简单方式。因此它是随着JSP的发展而出现的,只是可独立使用而已。

版本发布日期JSR版本对应JSP版本对应Servlet版本
EL 2.02003.11JSR 152JSP 2.0Servlet 2.4
EL 2.22009.12JSR 245JSP 2.2Servlet 2.5
EL 3.02013.05JSR 341JSP 2.3Servlet 3.1
EL 4.02020.10纳入JakartaJSP 3.0Servlet 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和常见用法,演示一下:

导包:

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

直接使用API书写Demo

/**
 * 在此处添加备注信息
 *
 * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>
 * @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转为对应类型
        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));

        // 方法调用
        // 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}));
    }

}

运行,结果输出:
18
2

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

✍总结

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

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

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

本专栏文章

推荐阅读

我是方向盘(YourBatman):前25年不会写Hallo World、早已毕业的大龄程序员。高中时期《梦幻西游》骨灰玩家,网瘾失足、清考、延期毕业、房产中介、保险销售、送外卖…是我不可抹灭的黑标签

  • 🎓2013.07 清考、毕业答辩3次未通过、延期毕业
  • 🏷2013.08-2014.07 宁夏中介公司卖二手房1年,毕业后第1份工作
  • ️️🏷2014.07-2015.05 荆州/武汉,泰康人寿卖保险3月、饿了么送外卖2月,还有炸鸡排、直销等第2345份工作
  • 🏷2015.08 开始从事Java开发,闯过外包,呆过大厂!擅长抽象思维,任基础架构团队负责人
  • 🏷2021.08 因“双减政策”失业!历经9面,终获美团外卖L8的offer
  • 🙅🏻‍♀️Java架构师、Spring开源贡献者、CSDN博客之星年度Top 10、领域建模专家、写作大赛1/2届评委
  • 📚高质量代码、规范践行者;DDD领域驱动深度实践;即将出版书籍《Spring奇淫巧技》

在这里插入图片描述

序号专栏名称简介
01【方向盘】-程序人生程序人生,人生程序
02【方向盘】-资讯/新特性IDEA、JDK、Spring技术栈…新特性
03【方向盘】-IntelliJ IDEA熟练使用IDEA就相当拥有物理外挂,助你高效编码
04【方向盘】-Bean Validation熟练掌握数据校验,减少90%的垃圾代码
05【方向盘】-日期时间帮你解决JDK Date、JSR 310日期/其实 的一切问题
06【方向盘】-Spring类型转换Spring类型转换-框架设计的基石
07【方向盘】-Spring staticstatic关键字在Spring里的应用
08【方向盘】-Cors跨域关于跨域请求问题,本专栏足矣
09【方向盘】-JacksonAlmost Maybe是最好的Jackson专栏
10【方向盘】-Spring配置类专讲@Configuration配置类,你懂的
11【方向盘】-Spring技术栈暂无所属小分类的,Spring技术栈大分类
12【方向盘】-JDK暂无所属小分类的,JDK技术栈大分类
13【方向盘】-ServletServlet规范、Web相关内容专题
14【方向盘】-Java EE从Java EE到Jakarta EE,30年弹指一挥间
15【方向盘】-工具/提效开发工具、软件工具,目标是提效
16【方向盘】-Spring技术栈新特性 Spring Framework、Spring Boot、Spring Cloud、Spring其它技术
17【方向盘】-基本功 每个Javaer,都需要有扎实的基本功
99源代码库大多数专栏均配有源代码,都在这里
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值