从静态网站到JSP+Servlet+JavaBean
引言
从上世纪90年代至今,Web开发飞速发展。现在当你打开各种关于JavaWeb的网课时,时常会看到满屏“白学了”的弹幕,而这篇文章主要讲述的就是这些“白学”的内容😄。
静态网站
随着互联网的诞生和发展,静态网页率先出场。
它们通常由HTML编写,程序内容固定于文件之中,通过HTTP协议从服务器传输到客户端游览器进行展示。 这样的方式缺点是显而易见的(甚至直接写在了名字上),那就是不够“动态”,由于程序内容固定,网页展示的内容需要修改程序后重新展示才可得到更新,无法实时根据用户请求动态响应。
就比如一个在线购物平台,用户将商品加入购物车后,购物车页面却无法实时更新购物车内的商品数量和总价,用户端体验较差。由此,动态网站应运而生。
Servlet
为了应对动态网站的需求,Java首先推出Servlet接口,定义处理网络请求的规范。
| Servlet.class | |
|---|---|
需要注意的是,Servlet仅仅只是个规范,实现了Servlet接口的类,还不能直接处理网络请求。就好比你有一套如何写信的规范,但信怎么发到你手里和你怎么发出信,还是个问题。
怎么解决这个问题呢?我们需要一个信使!
这个信使需要做什么呢?
- 首先,它得收发信。
- 在HTTP协议中,“信”通过TCP/IP网络发送,“信使”需要能够监听网络端口,捕获到“信”。
- 其次,它得解析请求和处理响应。
- 由于客户游览器与服务器消息往来遵循HTTP协议,需要“信使”解析请求报文,知道“怎么发”(
GET还是POST)、“发去哪”(URL)、“内容主体是什么”(请求体)等;还需根据HTTP协议处理Servlet的响应。
为了得到有着上述作用的“信使”,早期Java开发人员需要利用Java自带的Socket类手动实现对HTTP请求的解析和相应逻辑,这里不做重点,实现方法可参考Socket实现简单的Web服务器。
可以想象得到,这样操作无疑是非常繁琐的。已知HTTP协议报文结构清晰以及监听网络的代码较为雷同重复,既然如此,为什么不制作一个程序封装这些操作呢?
Tomcat
Tomcat是一个开源、免费、轻量级的Servlet容器和Web服务器,它不仅能够高效地处理网络通信和HTTP协议解析,还能根据Servlet规范自动调用相应的Servlet来处理请求,极大地简化了JavaWeb开发的复杂度。
- Tomcat服务器接受客户游览器请求并做出响应的过程如下:
-
- 客户端访问Web服务器,发送HTTP请求
- Web服务器接收到请求后,传递给Servlet容器
- Servlet容器加载并实例化相应Servlet对象,然后向对象传递请求对象
Request和响应对象Response - Servlet实例根据请求对象作出相应处理,并构建响应对象
- Servlet实例将响应对象送回Web服务器,Web服务器处理后发送给客户端
下边是Tomcat的简单用例,详细用法可参照IDEA中使用Tomcat和Servlet。
| project/index.html | |
|---|---|
| localhost:8080/project/sd | |
|---|---|
可以看到,这样网页就实现了动态交互。整个过程大概遵循以下逻辑:
graph LR
A[游览器] -->|请求资源,发送Request|B{Tomcat服务器};
B -->|解析好Request后发送| C[对应Servlet];
C -->|返回Response| B;
B -->|依照HTTP协议处理响应,并发给游览器| A;
但解决这一切后,又有一个显著的问题摆在眼前,这代码也太难写了!
关于Tomcat和Servlet的其它知识
由于篇幅问题,很多有意思的东西都难以说明,如:
1. 会话跟踪技术中的Cookie和Session,以及它们的扩展token、JWT等等
2. JavaWeb三大组件(Servlet、Filter、Listener)中的Filter和Listener
3. 还有HTTP响应状态码、转发和重定向机制等等
感兴趣可以自行查找资源学习……
JSP
很明显,上边ServletDemo.class的代码有点难写,原因是它需要我们在Java中写HTML代码——
导致代码可读性异常得差。
针对这种情况,Sun Microsystems公司推出了Java Server Page(简称JSP)技术,以简化动态网页的开发。
JSP = Java + HTML,JSP允许将Java代码直接嵌入到HTML页面中,如下:
| 利用Java中Date类获取当前时间,嵌入HTML并在网页上输出 | |
|---|---|
- JSP脚本中
<%@...%>:用来设置JSP页面的属性,如<%@ page import="java.util.*" %><%...%>:内容会直接放在_jspService()方法中
你可能会问`_jspService()`是什么,其实你直接把它当做Servlet中的`service()`就行<%=...%>:作用等同于Servlet中response.getWriter().write(...)<%!...%>:内容会放在除_jspService()方法之外
比较难绷和抽象的是:JSP甚至允许Java代码不是连续的,你能想象一个for循环
{和}中间还可能会临时中断插入一段HTML代码吗……
根据上边描述,聪明的你应该会想到:其实,JSP本质上是个Servlet!
- 当请求JSP资源时,Tomcat会执行以下操作:
-
- 检查该JSP文件是否已经编译过。如是,则从缓存中取出直接使用;如否,则编译它
- Tomcat会解析JSP中的代码,将JSP文件编译为一个Servlet类
- 之后当其为正常的Servlet来使用
通过这种方式,JSP页面能够动态生成内容,同时保持代码的可读性和开发的便捷性。你程序员是爽了,那对于用户,还有哪些方面可以进一步提升体验呢?
EL表达式和JSTL标签库
为了进一步优化JSP代码,还出现了EL表达式和JSTL标签库
EL表达式:方便JSP获取数据,主要用于转发技术。
JSTL标签库:使Java代码HTML化,极大美观代码。
详见超链接。
AJAX
在一些网站的注册页面中,我们常常会发现,当输入用户名后,页面会立即提示该用户名是否可用,而不是要提交表单、请求资源后,页面刷新才给出提示。这种动态实时验证的功能就是通过AJAX(Asynchronous JavaScript and XML)实现的。
AJAX是一种在无需重新加载整个网页的情况下,能够与服务器进行异步数据交换并更新部分网页内容的技术。它允许网页在用户与页面交互的过程中,后台与服务器进行数据通信,从而实现动态更新页面内容的效果。
graph LR
A[游览器:处理前的页面] --> |发送资源请求|B{服务器处理};
B -->|处理完请求| C[游览器:刷新页面,得到处理后的页面];
graph LR
A[游览器:处理前的页面] --> |AJAX发送请求|B{服务器处理};
A --> |用户正常使用页面|D[游览器:即使处理中,也能正常与用户交互];
B -->|处理完请求| C[游览器:无需刷新页面,直接得到处理后的页面];
D --> |用户正常使用|C
- AJAX工作流程:
-
- 网页中发生事件,JavaScript创建
XMLHttpRequest类对象 - 该对象向服务器发送请求
- 服务器处理请求并将响应发送回网页
- 网页中发生事件,JavaScript创建
想象你和朋友约好通过写信的方式交流。传统的网页交互就像是你写了一封信,你要亲自送去并将回信带回来,整个过程是同步的,你无法在等待往返期间做其他事情。
而AJAX技术的出现,就好比你找了个中间邮递员。你把信交给邮递员(AJAX请求),邮递员会去送信并等待对方回复。在这期间,你可以继续做自己的事情。当邮递员拿到回信后,他会自动通知你(AJAX响应),你再根据回信内容采取下一步行动。
下边是AJAX使用的简单实例:
至此,现代网页的基本功能都已经有了实现。那么接下来该讨论如何优化开发结构的问题了。
AXIOS和JSON
AXIOS:AXIOS异步框架,可以简化AJAX请求的编写,提高代码的可读性和维护性。
JSON:全称JavaScript Object Notation(JavaScript对象表示法),其多用于作为数据载体,在网络中进行数据传输。
二者都是简化Web开发的好手,详见超链接。
JSP + Servlet + JavaBean
看到标题你可能会很疑惑,不是哥们,JavaBean是什么?
起初我也非常困惑,但后边了解后才知道这玩意基本天天见。
所谓JavaBean,就是如下般的类:
JavaBean
JavaBean的特点:
1. 字段访问权限私有
2. 具有默认构造方法
3. 具有Getter和Setter方法
4. 可序列化,实现了Serializable接口
作用:JavaBean通常用于Web开发当中,可以提高代码的可维护性和重用性。
| UserBean.class | |
|---|---|
三层架构和MVC设计模式
- 众所周知,软件架构通常为三层架构,三层架构将应用程序分为:
-
- 表现层:负责与用户进行交互,展示数据和接受用户的输入
- 业务逻辑层:负责处理应用程序的核心业务逻辑和规则
- 数据访问层:负责与数据库进行交互,执行数据的增删改查
而MVC(Model-View-Controller)设计模式便是一种针对表现层设计模式,将表现层开发分为三个主要组件:模型(Model)、视图(View)和控制器(Controller)。
在MVC中,JavaBean主要用于处理模型层的事务。 前文一直在弱化模型层的表现,原因是不想让文章太过臃肿。
在实际开发中,可以将MVC设计模式应用于表示层,而业务逻辑层和数据访问层则按照三层架构的方式进行设计。这样可以充分利用两种架构模式的优势,构建更加清晰、模块化和可维护的应用程序。
JSP + JavaBean (Model1)
针对MVC设计模式,JSP + JavaBean(简称Model1)风靡一时。
Model1中,JSP因其“Java+HTML”的特性,直接用于处理视图层(View)和控制层(Controller);而JavaBean则用于处理模型层(Model)。
graph LR
A[客户端游览器] --> |1.请求|B[JSP页面];
B <--> |2.与JavaBean交互|C[JavaBean];
C <--> |3.与数据库交互|D[Database];
B --> |4.响应|A
这样,开发实现初步解耦。但不难发现,虽然该模式编写代码较为容易,但JSP混杂了View层和Controller层,耦合程度还是太高。因此又提出了JSP+Servlet+JavaBean的Model2模式。
JSP+Servlet+JavaBean(Model2)
Model2中,添加了Servlet来作处理Controller层的主力,而JSP仅需要处理View层和少量Controller层即可。
这无疑是进步的,这样的模式下,JSP中可以大量减少Java的代码,达到仅使用EL表达式和JSTL就够的效果。
这样JSP中基本不涉及任何的业务逻辑,前端工程师可以在JSP中专注样式,后端工程师可以在Servlet和JavaBean中专注逻辑,实现进一步开发结构的解耦。
graph LR
A[客户端游览器] --> |1.请求|B[Servlet];
B <--> |2.与JavaBean交互|C[JavaBean];
C <--> |3.与数据库交互|D[Database];
B --> |4.转发或重定向|E[JSP页面];
E --> |5.响应|A
需要注意的是,Model2还不是一个完全标准的MVC设计模式,还可以继续与三层架构结合,将JavaBean继续分割成业务逻辑层和数据持久层……
纵观软件设计的发展,无非就是一个不断提升“高聚合,低耦合”的过程。而这个过程往往伴随着分层这一操作,因为在计算机领域,没有什么是加多一层不能解决的,如果有,那就两层……
尾言
至此,本篇文章就结束了。接下来就是各种框架的舞台了……
到时,我们会遇见灵活易用的前端框架Vue,还会学习将Java推至“神坛”的Spring全家桶——或许到那时,面对如此便捷的开发工具,你会发出和本文引言一样的疑惑:“白学了吗?”,答案请藏在心底。我不会说就是白学了🤡