《jsp篇》jsp是什么?

前文链接:https://www.zhihu.com/question/437632592/answer/1677694755
链接:https://www.zhihu.com/question/23984162/answer/689106407

现在(2019)对于后端程序员来说,可以不学JSP。但是如果你是非科班,不论是在培训班还是自学,最好都了解一下。技术不扎实的培训班学员,基本很难找到一家可以让你专心写后端的公司,大部分人还是去了外包公司。而据我所知,现在仍有不少外包公司在用SSM+JSP+JQuery。

JSP离不开Servlet,学习它之前最好有Servlet基础。

Servlet与JSP的难点在于概念太多、太杂、太抽象。首先,你要过好几天才明白它是个什么东西、用来干嘛。其次,等你终于明白它是什么时,你又纳闷它整个流程是怎样的。就好比我现在问你,从浏览器地址栏键入url发起请求到服务器响应数据,中间Servlet和JSP都干了啥,你是否清楚?还有一个就是JSP比Servlet更容易让人迷糊,以至于我一度以为JSP是页面,它运行在客户端而不是在服务器端...等等,现在想来可能觉得云淡风轻,但是对于当时自学的我来说简直蛋疼。

文章比较长,但肯定充满诚意。看完基本就知道JSP的前世今生,请务必坚持看完。

主要内容介绍:

  • 动乱年代
  • JSP是什么
  • 一个Http请求的冒险之旅
  • JSP与AJAX+HTML
  • MVC模式与JAVAEE三层架构

动乱年代

在介绍JSP之前,必须要先来聊聊英雄们的故事。

1987年9月14日21时07分,有人从北京向海外发出了中国第一封电子邮件。邮件内容为“Across the GreatWall we can reach every corner in the world(越过长城,走向世界)”,这预示着,互联网时代悄然叩响了中国的大门。

让我们将目光从中国转向海外。上世纪的90年代,当时的互联网还是天地初开、一片混沌。而1995年以及随后的一年,可谓群雄逐鹿风起云涌,注定不平凡。而当时,我还在家里玩泥巴。

1995年5月,SUN公司发布了Java。名字取得很随意,据说是因为那群创始人当时正好在咖啡店激烈讨论取什么名字。其中有一个人望着手中的咖啡突然灵机一动:卧槽,就叫Java吧(爪哇岛盛产咖啡)。这就好比农村生娃,老爹一看,卧槽,这孩子骨骼惊奇,面相清秀,就叫...二狗子吧,的感觉一样一样的。几乎同年,也不知道稍早还是稍晚,反正不重要,PHP也发布了。当时的人们还不知道,它将被黑为“世界上最好的语言”。次年,一个叫布兰登·艾奇(Brendan Eich,1961年~)的技术员,应老板要求花了10+天,借鉴几大语言的优秀特性(包括Java),写出了LiveScript。而为了在发布时蹭Java热度扩大宣传,不惜改名JavaScript。所谓慢工出细活,所以...JavaScript只写了10多天,自然是...好在后来也挽救回来了,现在好歹是GitHub提交量最多的语言,而前端这几年也是火得不行。

我们知道,浏览器能通过解析html语句渲染出页面。比如:
image

那这些html语句是怎么来的呢?浏览器通过http请求向服务器请求某个页面,然后服务器根据浏览器的请求,通过http响应返回对应页面的html。服务器端是我们用Java开发的,它用什么响应这一大堆html语句?答案就是:Servlet!随手用MyEclipse新建一个Servlet,你会看到Servlet默认的模板是这样的:
image

Servlet的doGet()和doPost()方法体中有响应html片段的代码。这其实是上古时期开发习惯的“遗迹”。都2019年了,MyEclipse还自作聪明,以为你会在Servlet中手动输出HTML片段(也就是浏览器收到的HTML)。

诚然,在早期的JavaWeb开发中,我们的程序猿祖先确实有那么一段黑暗时光,但那是因为当时还没有现在这么多、这么好用的模板和框架。
image

在那个黑暗岁月,通常情况是美工写好html静态页面后,丢给Java程序员。Java程序猿在Servlet中调用Service拿到数据后,逐句复制html静态页面上的html语句到Servlet的中,根据情况将后端的数据与html片段拼接在一起,然后以诸如

 out.println("<span>用户名是:"+user.name+<"/span>");

的方式疯狂输出。
image

按这种方式,要想拼接数据并完整输出一个html页面,没个几百上千行out.println()是不可能的。所以基本上敲完两个页面两根手指就麻了。
image

而同时期的PHP,

http://ASP.Net

就优秀得多了,人家压根不搞你这繁琐的一套。它们选择在“html页面”中嵌入相应语言来引入动态数据,避免了手动拷贝html片段输出的尴尬局面。

因为仔细想来,我们的主要目的就是希望在最终输出的html的代码中嵌入后台数据罢了。除了把html语句拿出来放在Servlet里拼接好再输出这种方式外,我们有没有可能直接在html语句中写入动态数据呢?这也就是当时其他友商的做法。这几乎是完全相反的两种设计思路。
image

一部分Java程序员一看,就傻眼了:我靠,PHP还真是世界上最好的语言啊,Web开发竟然如此之简单!老子再也不想复制粘贴了!于是转向了PHP或者其他语言的开发。就这样,Java流失了一部分程序员。SUN公司一看,这不行啊,Java也要搞一个。于是,JSP应运而生。
image

JSP是个啥

JSP全称Java Server Page,直译就是“运行在服务器端的页面”。上面已经介绍过,我们可以直接在JSP文件里写HTML代码,使用上把它当做HTML文件。而且JSP中HTML/CSS/JS等的写法和HTML文件中的写法是一模一样的。

但它毕竟不是HTML,而且本质差了十万八千里。因为我们还可以把Java代码内嵌在JSP页面中,很方便地把动态数据渲染成静态页面。这一点,HTML打死都做不到。

当有人请求JSP时,服务器内部会经历一次动态资源(JSP)到静态资源(HTML)的转化,服务器会自动帮我们把JSP中的HTML片段和数据拼接成静态资源响应给浏览器。也就是说JSP运行在服务器端,但最终发给客户端的都已经是转换好的HTML静态页面(在响应体里)。服务器并没有把JSP文件发给浏览器(假装重要的事情已经说3遍)。

即:JSP = HTML + Java片段(各种标签本质上还是Java片段)
image

所谓的“JSP和HTML相似”只是JSP给我们的表面印象。我们还要继续往下挖一挖。实际上,JSP和HTML差远了。JSP本质是一个Java类(Servlet),是在服务器混的,只不过它输出结果是HTML。蜜蜂产出蜂蜜,但是蜜蜂不是蜂蜜啊!在揭开JSP真身之前,我们先来复习一下什么是Servlet。

Servlet是什么?

  • 一个Java类,运行在Servlet容器中(Tomcat)
  • 负责接收请求
  • 调用Service处理数据
  • 负责响应数据

image

再来看看张孝祥老师的心血之作(感谢网友孤傲苍狼整理):

image

image

image

至此,想必大家对Servlet是什么,主要做什么已经很清楚。接下来谈谈为什么说JSP本质就是一个Servlet。具体的源码我就不带大家看了,大致流程是这样的:

image

image

image

有点晕?来捋一捋。

原本,我们需要把美工的HTML代码一行行复制到Servlet中,然后拼接数据,最后向客户端响应拼接好的HTML页面。

image

后来我们嫌麻烦,搞了JSP,就可以不用一行行复制HTML代码了,而是在JSP中直接写HTML代码和Java代码,后期JSP编译成一个Servlet,通过Java代码获取后台数据后拼接到HTML片段中,最终通过out.println()输出。

image

现在可以回答上面的问题:为什么完全相反的两种设计理念却完成了同样的需求呢?答案可以有多种,但是其中一种就是:这两种殊途同归,最终实现是一样的,都是在一个Servlet中输出!

我们不妨打开index_jsp.java,观察index.jsp被翻译成Servlet后的源码,可以看到

image

也就是说,虽然我们不用像上古时期一样手动复制html语句到Servlet了,但是JSP编译后的Java类其实还是在out.println()输出。和我们手动复制是一样的结果。

而index_jsp.java这个类继承了HttpJspBase,而HttpJspBase间接实现了Servlet接口。所以可以说,index.jsp被翻译后的Java类也是一个Servlet,所以JSP本质也是一个Servlet。

绕了这么一大圈,我们终于明白:

原来,为了不让Java程序员一行行复制HTML代码到Servlet里,SUN公司干脆让Java程序员直接把HTML写在了Servlet里!但是毕竟SUN还没有那么明目张胆,好歹让这个Servlet伪装了一把,打扮成JSP,然后跟程序员说:看,我搞了个JSP,这家伙可牛逼了,你能在上面同时写HTML和Java代码哦。 得了吧,等你写完JSP,回头访问时,Tomcat就把这个JSP翻译成Servlet,原先写在JSP里的HTML代码就自动放在了out.println()里啦!相当于程序帮我做了“逐行复制HTML代码到Servlet”这一步。(想起来手就麻!)

至此,我们已经知道,JSP就是一个Servlet。那么丝毫不用怀疑,今后无论你在JSP看到什么奇奇怪怪的东西,只要不报错,说明JSP就有足够自信把它变成Java代码的一部分:

  • 要么被当成字符串输出(HTML片段)
  • 要么本身就是Java片段
  • 要么会转成Java片段(EL表达式)

image

image

所以,大家千万别把EL表达式想太难,记个语法,知道怎么用就行了。至于它怎么变成Java代码的,需要我们操心吗?

最后还要提醒一下EL表达式这些标签是在何时何地起作用的。很多人误以为EL表达式可以在浏览器起作用。根本原因还是对JSP不了解。JSP是服务器端的,所有操作必须在响应给浏览器之前做完。这些标签,会在JSP文件编译成Servlet时,自动转化为Java代码,然后对数据做处理。所以本质上和你在JSP页面写的<%%>之类的Java片段一样。它负责从变量(不确定的数)中取出数据,变成静态数据后(确定的数)贴在薄薄的一张HTML静态页面上。

想象一下,变量还未取出来之前,数据是立体的,圆鼓鼓的,而HTML静态页面则薄如一张纸。我们无法在二维面上放入三维物质。而EL表达式从变量取出来的数据则是一个常量,是个字符串一样的东西,可以轻轻地“贴”在HTML里。

至此,我们明白,JSP是立体的机器,在服务器内部,在服务器其他“同僚”的帮助下,生产一张张HTML静态页面让http带回去给浏览器显示。就像吐钞机与钞票的关系。

image

一个Http请求的冒险之旅

image

JSP与AJAX+HTML

其实请求、响应这么一来一回,无非要的就两样东西:数据+HTML骨架。如果把服务器端比作淘宝卖家,客户端(浏览器)比作买家,而数据和HTML则是一件商品的两个重要组成部件。那么我们很自然地能够想到,其实运输方式至少可以有两种:

1.卖家组装好商品后再发货(JSP)

2.卖家把部件拆开,运到之后买家自己组装(AJAX+HTML)

JSP是服务器端的,它的局限性在于数据必须在返回给客户端之前就“装载”完毕。不然HTML都已经发出去了,你就没办法跑到浏览器里把数据给它安上。

而有了AJAX,就可以实现零件发送、目的地组装了。

image

其实我对前端也不是很熟悉,只能给个大致的图。

再强调一点,虽然我们在浏览器地址栏输入localhost:8080/xxx/xxx.jsp,就显示出了当前页面,但那不是JSP页面,而是HTML页面。服务器并没有直接把JSP文件从服务端扔到客户端!JSP是Java Server Page,是服务器端的东西。服务器的东西永远不可能直接在浏览器运行。浏览器只能接受静态页面。

image

MVC模式与JAVAEE三层架构

image

聊这个,纯粹是因为很多朋友很容易搞错一个概念,认为MVC模式是JavaEE独有的开发模式。其实不是的。MVC是web开发都有的一种模式,比如PHP开发web时也有MVC模式。而三层架构则是JavaEE的:Controller/Service/Dao。分层开发是为了使代码逻辑更加清晰,也起到了一定的解耦合作用。

值得注意的是,MVC只是在web层。当然,如果站在更高的角度,可以看成这样:

image

看完本篇文章后,如果希望进一步了解Tomcat及Servlet的朋友,请移步:

https://zhuanlan.zhihu.com/p/54121733

https://zhuanlan.zhihu.com/p/65588465

posted @ 2024-02-04 17:05  Fusio  阅读(10)  评论(0编辑  收藏  举报