您现在的位置是:亿华云 > 数据库

版本历史&代码示例之:WebSocket、JSTL

亿华云2025-10-03 06:19:22【数据库】6人已围观

简介前言你好,我是方同学(YourBatman)若你还不太清楚Java EE是什么,可先移步这里:什么是Java EE?紧接着上一篇讲完Servlet、JSP、EL表达式后,本文尝试把WebSocket和

前言

你好,版本我是历史方同学(YourBatman)

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

紧接着上一篇讲完Servlet、JSP、示例EL表达式后,版本本文尝试把WebSocket和JSTL再疏通疏通。历史

所属专栏

BATutopia-Java EE

相关下载

工程源代码:https://github.com/yourbatman/BATutopia-java-ee 【女娲Knife-Initializr工程】访问地址:http://152.136.106.14:8761 Java开发软件包(Mac):https://wangpan.yourbatman.cn/s/rEH0 提取码:javakit 程序员专用网盘上线啦,代码开放注册送1G超小容量,示例帮你实践做减法:https://wangpan.yourbatman.cn

版本约定

Java EE:6、版本7、历史8

Jakarta EE:8、代码9、示例9.1

正文

WebSocket

WebSocket是版本一种在单个TCP连接上进行全双工通信的协议。随着HTML5的历史诞生,WebSocket通信协议于2011年被IETF定为标准RFC 6455,代码并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket协议本质上是一个基于TCP的协议,它由通信协议和编程API组成,WebSocket能够在浏览器和服务器之间建立双向连接,以基于事件的方式,赋予浏览器实时通信能力。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。云服务器提供商在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。工作流程如下图:

Java API for WebSocket是Java的Web套接字,在2013年6月份伴随着Java EE 7推出(1.0版本),Java EE 8升级到1.1版本。

注意:WebSocket的Client可以是浏览器,也可是WebSocket的终端(如Java应用、Go应用)。

<!-- javax命名空间版本(Tomcat 9.x及以下版本支持) --> <dependency>     <groupId>javax.websocket</groupId>     <artifactId>javax.websocket-api</artifactId>     <version>1.1</version>     <scope>provided</scope> </dependency> <!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) --> <dependency>     <groupId>jakarta.websocket</groupId>     <artifactId>jakarta.websocket-api</artifactId>     <version>2.0.0</version>     <!-- <version>1.1.2</version> 此版本命名空间同javax -->     <scope>provided</scope> </dependency> 除此之外,一般情况下我们直接使用Web容器提供的Jar即可,如Tomcat <dependency>     <groupId>org.apache.tomcat.embed</groupId>     <artifactId>tomcat-embed-websocket</artifactId>     <version>Tomcat版本号</version> </dependency> <dependency>     <groupId>org.apache.tomcat</groupId>     <artifactId>tomcat-websocket</artifactId>     <version>Tomcat版本号</version> </dependency> 

版本历程

servlet-3.1版本开始支持。WebSocket 1.1 版与 1.0 版完全向后兼容,只在javax.websocket.Session中添加了两个方法:

<T> void addMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler) throws IllegalStateException; <T> void addMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler) throws IllegalStateException; 

生存现状

作为Http协议的“补充”,很好的弥补了其不足,在Web领域实时推送,也被称作Realtime技术。这种技术大大提升交互体验,拥有广泛的应用场景:在线聊天(如web版微信)、在线客服系统、评论系统等等。亿华云

总的来讲,WebSocket作为新贵,生存现状挺好,前景一片光明。

实现(框架)

WebSocket其实是构建在Http协议之上的,所以对于Java语言来讲它依旧由Web容器来提供实现。

概念区分:Web容器不一定是Servlet容器,而Servlet容器一定是Web容器

除此之外也有独立实现:

client端实现:org.eclipse.jetty.websocket:javax-websocket-client-impl server端实现:org.eclipse.jetty.websocket:javax-websocket-server-impl对于Client来讲,一般都是浏览器。

代码示例

前面有提到,WebSocket的Client端既可以是浏览器(现代的浏览器100%都支持此协议,若需要考虑浏览器兼容问题(比如国外现在依旧有使用老版IE浏览器的),可以使用socketio框架哈),也可以是Java应用。本示例就加点“难度”,用Java应用作为WebSocket的客户端。当然喽,服务端肯定也是Java应用呀。

创建demo项目,结构如下:

其中client为jar,源码下载server为war。

书写Server端代码,提供一个服务端点:

/**  * 在此处添加备注信息  *  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>  * @site https://yourbatman.cn  * @date 2021/9/12 15:29  * @since 0.0.1  */ @ServerEndpoint("/websocket/chat") public class WsServer {      // 当前连接上来的连接们(每一个连接都是一个WsServerDemo实例,包含一个Session会话)     private static Set<WsServer> webSocketSet = new CopyOnWriteArraySet<>();     // 会话     private Session session;     /**      * 建连成功的回调      */     @OnOpen     public void onOpen(Session session) {          this.session = session;         webSocketSet.add(this); // 保存当前连接         System.out.println("Server有新连接加入!当前在线人数为" + webSocketSet.size());     }     /**      * 连接关闭调用的方法      */     @OnClose     public void onClose() {          webSocketSet.remove(this);         System.out.println("Server有一连接关闭!当前在线人数为" + webSocketSet.size());     }     /**      * 收到客户端消息后调用的方法      */     @OnMessage     public void onMessage(String message) throws IOException {          System.out.println("Server来自客户端的消息:" + message);         sendMessage("会话[" + session.getId() + "]的消息已经收到,内容为:" + message);         // // =======群发消息=========         // for (WsServerDemo item : webSocketSet) {          //     try {          //         item.sendMessage(message);         //     } catch (IOException e) {          //         continue;         //     }         // }     }     /**      * 发生错误时调用      */     @OnError     public void onError(Throwable error) {          System.out.println("Server发生错误:" + error.getMessage());     }     /**      * 发送消息      */     public void sendMessage(String message) throws IOException {          this.session.getBasicRemote().sendText(message);     } } 

我这里简便起见,使用web容器直接实现。有兴趣/想深究websocket的同学,可使用org.eclipse.jetty.websocket:javax-websocket-server-impl通过API方式去启动Server,本文只演示用该方式启动client哈,二者兼顾嘛。

使用编程方式书写client端代码:

/**  * 在此处添加备注信息  *  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>  * @site https://yourbatman.cn  * @date 2021/9/12 15:31  * @since 0.0.1  */ @ClientEndpoint public class WsClient {      // 会话(与服务端建立的会话)     private Session session;     /**      * 建连成功的回调      */     @OnOpen     public void onOpen(Session session) throws IOException {          this.session = session;         System.out.println("Client连接到服务端成功,会话ID:" + session.getId());         sendMessage("这是一条来自Client端,会话["+session.getId()+"]的消息");     }     @OnMessage     public void onMessage(String message) {          System.out.println("Client端收到消息: " + message);     }     @OnClose     public void onClose() {          System.out.println("Client会话" + session.getId() + "已断开");     }     /**      * 发送消息      */     public void sendMessage(String message) throws IOException {          this.session.getBasicRemote().sendText(message);     } } 

用main方法启动Client端,去连接Server端并发送消息:

public class ClientApp {      private static URI uri = URI.create("ws://localhost:8080/websocket/chat");     private static Session session;     public static void main(String[] args) throws DeploymentException, IOException, InterruptedException {          WebSocketContainer container = ContainerProvider.getWebSocketContainer();         // 顺序执行5次会话,端口后再建立新会话         for (int i = 0; i < 5; i++) {              session = container.connectToServer(WsClient.class, uri);             session.close();             TimeUnit.SECONDS.sleep(2);         }     } } 

client端控制台日志:

Client连接到服务端成功,会话ID:1 Client端收到消息: 会话[0]的消息已经收到,内容为:这是一条来自Client端,会话[1]的消息 Client会话1已断开 Client连接到服务端成功,会话ID:2 Client端收到消息: 会话[1]的消息已经收到,内容为:这是一条来自Client端,会话[2]的消息 Client会话2已断开 Client连接到服务端成功,会话ID:3 Client端收到消息: 会话[2]的消息已经收到,内容为:这是一条来自Client端,会话[3]的消息 Client会话3已... 

server端控制台日志:

Server有新连接加入!当前在线人数为1 Server来自客户端的消息:这是一条来自Client端,会话[1]的消息 Server有一连接关闭!当前在线人数为0 Server有新连接加入!当前在线人数为1 Server来自客户端的消息:这是一条来自Client端,会话[2]的消息 Server有一连接关闭!当前在线人数为0 Server有新连接加入!当前在线人数为1 Server来自客户端的消息:这是一条来自Client端,会话[3]的消息 Server有一连接关闭!当前在线人数为0 

说明:本文特意使用Java应用作为Client端是想让你更深刻的理解WebSocket的用法,实际场景中,其实大都是B/S模式,通过JavaScript作为客户端建立连接(相对简单)。

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

JSTL

Java server pages standarded tag library,即JSP标准标签库。主要提供给Java Web开发人员一个标准通用的标签库,开发人员可以利用这些标签取代 JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。

JSTL强依赖于JSP的存在而存在。

JSTL和EL表达式的目的是一样的:取代JSP页面上写Java代码。它比EL更为强大些,可以完成一些结构化逻辑任务,如:迭代、条件判断、XML文档操作、国际化、SQL等,下面简要介绍其主要标签。

核心标签:也是著名C标签。在JSP文件开头引入c标签<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>,支持的常用函数有: 1. <c:out>:用于在页面输出  - <c:out value="expression" default="expression" escapeXml="boolean"/> 2. <c:if>:逻辑判断  - <c:if test="expression" var="name" scope="scope">          body content      </c:if> 3. <c:choose>:逻辑判断。when和otherwise的父标签 4. <c:when>: <c:otherwise>:  - <c:choose>        <c:when test="expression">            body content        </c:when>     ...      <c:otherwise>         body content     </c:otherwise>      </c:choose> 5. <c:foreach>:  - <c:forEach var="name" items="expression" varStatus="name" begin="expression" end="expression" step="expression">          body content      </c:forEach> 6. <c:url>:使用可选的查询参数创造一个URL地址 7. <c:set>:设置数据 8. <c:remove>:删除数据  格式化标签:可对数字、日期时间等格式化。<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>,主要函数: 1. <fmt:formatNumber>:格式化数字 2. <fmt:parseNumber>:解析字符串到数字、货币、百分比 3. <fmt:formatDate>: 4. <fmt:parseData>:  JSTL函数:一般用于辅助标签控制行为。<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>,主要函数: 1. fn:contains:判断字符串是否包含另外一个字符串   - <c:if test="${ fn:contains(name, searchString)}"> 2. fn:indexOf:子字符串在母字符串中出现的位置   - ${ fn:indexOf(name, -)} 3. fn:toLowerCase:转为小写  - ${ fn.toLowerCase(product.name)}  SQL标签,<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>。主要函数: 1. <sql:setDataSource>、<sql:query>、<sql:update>  XML标签,<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>。主要函数: 1. <x:parse>、<x:if>、<x:forEach> 

除此之外,还提供了扩展点:自定义标签。

<!-- javax命名空间版本(Tomcat 9.x及以下版本支持) --> <dependency>     <groupId>javax.servlet.jsp.jstl</groupId>     <artifactId>jstl-api</artifactId>     <version>1.2</version> </dependency> <!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) --> <dependency>     <groupId>jakarta.servlet.jsp.jstl</groupId>     <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>     <version>2.0.0</version>     <!-- <version>1.2.7</version> 此版本命名空间同javax --> </dependency> 

说明:之前可能需要有jstl.jar和standard.jar两个Jar,但从1.2版本后这一个GAV即可。当然喽,99.99%情况下该jar无需你导入,由web容器负责

版本历程

JSTL也依赖于JSP而存在,所以和JSP版本有强关系。

JSTL 1.2版本可断定是最后一个版本,因为JSP已走到尽头,所以它也会随之消亡。

生存现状

同JSP。

实现(框架)

与Servlet相同的Web容器,由Web容器提供解析能力。如tomcat的标签库实现:http://tomcat.apache.org/taglibs

代码示例

实在没有应用场景了,略。

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

总结

WebSocket作为长连接的轻量级解决方案,会是B/S的新宠,一举替掉之前的长轮训等方案。滚滚长江东逝水,这或许就印证着技术在进步,时代在发展。

作为老一辈程序员的我,对EL表达式、JSTL这类技术依旧有记忆存留,但新时代的程序员可能没有必要再接触。本文就当做自留地,封存这段学习的记忆吧。

本文转载自微信公众号「BAT的乌托邦」

很赞哦!(95)