【方向盘】版本历史&代码示例之:WebSocket、JSTL

简介: 通透,才能写出好代码
通透,是技术人应有的追求。
本文已被 https://yourbatman.cn收录; 女娲Knife-Initializr工程可公开访问啦;程序员专用网盘 https://wangpan.yourbatman.cn;公号后台回复“ 专栏列表”获取全部小而美的 原创技术专栏

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

✍前言

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

紧接着上一篇讲完Servlet、JSP、EL表达式后,本文尝试把WebSocket和JSTL再疏通疏通。
在这里插入图片描述

所属专栏

相关下载

版本约定

  • 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>

✌版本历程

版本 发布日期 JSR版本 对应Java EE版本
WS 1.0 2013.06 JSR 356 Java EE 7
WS 1.1 2017.08 JSR 356 Java EE 8
WS 2.0 2020.11 Jakarta管理 Java EE 9

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/FXP-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版本有强关系。

版本 发布日期 JSR版本 对应JSP版本 对应Servlet版本
JSTL 1.0 2002.07 JSR 52 JSP 1.2 Servlet 2.3
JSTL 1.1 2003.11 JSR 52 JSP 2.0 Servlet 2.4
JSTL 1.2 2006.05 JSR 52 JSP 2.1 Servlet 2.5
JSTL 2.0 2020.11 Jakarta管理 JSP 3.0 Servlet 5.0

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

✌生存现状

同JSP。

✌实现(框架)

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

✌代码示例

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

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

✍总结

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

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

本专栏文章

推荐阅读

在这里插入图片描述

我是方向盘(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 static static关键字在Spring里的应用
08 【方向盘】-Cors跨域 关于跨域请求问题,本专栏足矣
09 【方向盘】-Jackson Almost Maybe是最好的Jackson专栏
10 【方向盘】-Spring配置类 专讲@Configuration配置类,你懂的
11 【方向盘】-Spring技术栈 暂无所属小分类的,Spring技术栈大分类
12 【方向盘】-JDK 暂无所属小分类的,JDK技术栈大分类
13 【方向盘】-Servlet Servlet规范、Web相关内容专题
14 【方向盘】-Java EE 从Java EE到Jakarta EE,30年弹指一挥间
15 【方向盘】-工具/提效 开发工具、软件工具,目标是提效
16 【方向盘】-Spring技术栈新特性 Spring Framework、Spring Boot、Spring Cloud、Spring其它技术
17 【方向盘】-基本功 每个Javaer,都需要有扎实的基本功
... ... ...
99 源代码库 大多数专栏均配有源代码,都在这里
目录
相关文章
|
3月前
|
网络协议 安全 JavaScript
Web实时通信的学习之旅:WebSocket入门指南及示例演示
Web实时通信的学习之旅:WebSocket入门指南及示例演示
313 0
|
JavaScript
node.js: ws服务端和WebSocket客户端交互示例
node.js: ws服务端和WebSocket客户端交互示例
681 0
|
Cloud Native 前端开发 Go
探索 Golang 云原生游戏服务器开发,根据官方示例实战 Gorilla WebSocket 的用法
探索 Golang 云原生游戏服务器开发,根据官方示例实战 Gorilla WebSocket 的用法
704 0
|
Java Spring 开发工具
spring boot整合WebSocket示例
1.运行环境 开发工具:intellij idea JDK版本:1.8 项目管理工具:Maven 4.0.0 2.GITHUB地址 https://github.com/nbfujx/springBoot-learn-demo/tree/master/spring-boot-websocket .
1847 0
|
6月前
|
前端开发 网络协议 JavaScript
在Spring Boot中实现基于WebSocket的实时通信
在Spring Boot中实现基于WebSocket的实时通信
|
3月前
|
开发框架 前端开发 网络协议
Spring Boot结合Netty和WebSocket,实现后台向前端实时推送信息
【10月更文挑战第18天】 在现代互联网应用中,实时通信变得越来越重要。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为客户端和服务器之间的实时数据传输提供了一种高效的解决方案。Netty作为一个高性能、事件驱动的NIO框架,它基于Java NIO实现了异步和事件驱动的网络应用程序。Spring Boot是一个基于Spring框架的微服务开发框架,它提供了许多开箱即用的功能和简化配置的机制。本文将详细介绍如何使用Spring Boot集成Netty和WebSocket,实现后台向前端推送信息的功能。
748 1
|
3月前
|
前端开发 Java C++
RSocket vs WebSocket:Spring Boot 3.3 中的两大实时通信利器
本文介绍了在 Spring Boot 3.3 中使用 RSocket 和 WebSocket 实现实时通信的方法。RSocket 是一种高效的网络通信协议,支持多种通信模式,适用于微服务和流式数据传输。WebSocket 则是一种标准协议,支持全双工通信,适合实时数据更新场景。文章通过一个完整的示例,展示了如何配置项目、实现前后端交互和消息传递,并提供了详细的代码示例。通过这些技术,可以大幅提升系统的响应速度和处理效率。
|
5月前
|
开发框架 网络协议 Java
SpringBoot WebSocket大揭秘:实时通信、高效协作,一文让你彻底解锁!
【8月更文挑战第25天】本文介绍如何在SpringBoot项目中集成WebSocket以实现客户端与服务端的实时通信。首先概述了WebSocket的基本原理及其优势,接着详细阐述了集成步骤:添加依赖、配置WebSocket、定义WebSocket接口及进行测试。通过示例代码展示了整个过程,旨在帮助开发者更好地理解和应用这一技术。
456 1
|
5月前
|
小程序 Java API
springboot 微信小程序整合websocket,实现发送提醒消息
springboot 微信小程序整合websocket,实现发送提醒消息