漫谈JSP

前言

以前倒是知道JSP概念,但只能算是大概中的大概。今天因缘际会,又大致去查了些资料,然后就知道了个大概。比起JSP本身的语法规则,我对其由盛及衰的发展历史,倒表现出更大的兴趣。

古堡小船

JSP

全称JavaServer Pages,即Java服务器页面。它是一种 动态 网页技术标准,是一种服务器端的脚本语言(以Java作为脚本语言),但却和PHP ASP有着本质的区别,JSP本质上就是一种Java Servlet

JSP技术使用JSP标签在HTML网页中插入Java代码,也就是将Java代码和特定变动内容嵌入到静态的页面中,实现以静态页面为模板,动态生成其中的部分内容。标签通常以<%开头,以%>结束。

JSP标签有多种功能,比如访问数据库、访问JavaBeans组件等,还可以在不同的网页中传递控制信息和共享信息。

语法标准

一个JSP页面可以被分为以下几部分:

  • 静态数据,如HTML
  • JSP指令,如include指令
  • JSP脚本元素(标签)和变量,如脚本变量request
  • JSP动作,如jsp:forward
  • 用户自定义标签

执行过程

通常我们在JSP文件中写Html代码,于是在使用上可以把它当作Html文件。比如我们访问某个网站的首页http://yourdomainname:8080/index.jsp,请求的就是这个JSP文件,这里理解上就可以认为JSP文件是一种动态资源Html/CSS文件、图片等属于静态资源)。

当用户请求JSP文件时,服务器内部会经历一次JSP(动态资源)到HTML(静态资源)的转换,服务器会自动帮我们把JSP中的HTML片段和数据拼接成静态资源响应给浏览器。

网络服务器需要一个 JSP 引擎,也就是一个容器来处理 JSP 页面。容器负责截获对 JSP页面的请求。也就是说,JSP文件是运行在服务端而不是客户端的。

  • JSP转换为Servlet

JSP文件在运行时会被JSP引擎(引擎jspServlet本身也是Servlet,负责解释和执行JSP页面)转换成更原始的Servlet代码(.java后缀即java源文件)。在转换时,如果发现JSP文件中有任何语法错误,则中断转换过程,并向服务端和客户端输出错误信息。

注:servlet是用Java语言编写的服务器端程序。主要功能是和浏览器进行交互,生成页面展示。

  • 转换为.class文件

JSP被JSP引擎转换为Servlet后,将被编译成Servlet的class文件(字节码文件)。也就是通常的.java文件到.class文件的编译过程。

  • Servlet容器处理

.jsp文件转换之后的.class文件能够被JVM(Java虚拟机)执行,通过加载类、初始化、实例化等步骤,将执行结果(Html代码-静态文件)传递给(处理这个jsp请求的Servlet程序中的)response对象,进而通过Web服务器响应给浏览器。

  • 浏览器解析Html

浏览器只能够处理并渲染静态资源。虽然请求的是.jsp文件,但是获得的响应是完完全全的Html文件,于是解析Html代码并将请求的页面显示。

JSP、PHP与ASP

  • PHP

PHP是一种嵌入HTML页面中的脚本语言,使Web开发者能够快速地写出动态产生页面。

PHP语法简单,非常易学易用,很利于快速开发各种功能不同的定制网站(APACHE+PHP+MYSQL搭配),但因为结构上的缺陷,使的PHP在复杂的大型项目上的开发和维护都比较困难。

  • ASP

ASP(Active Server Pages)是微软的Windows IIS系统自带的脚本语言,利用它可以执行动态的Web服务应用程序。

和PHP一样,ASP简单而易于维护,很适合小型网站应用,通过DCOM和MTS技术,ASP甚至还可以完成小规模的企业应用,但ASP的致命缺点就是不支持跨平台的系统,在大型项目开发和维护上非常困难。

  • JSP

JSP(JavaServer Pages)是Sun公司推出的一种动态网页技术。JSP本身虽然也是脚本语言(以Java作为脚本语言),但是却和PHP、ASP有着本质的区别。PHP和ASP都是由语言引擎解释执行程序代码,而JSP代码却被编译成Servlet并由Java虚拟机执行,这种编译操作仅在对JSP页面的第一次请求时发生。因此普遍认为JSP的执行效率比PHP和ASP都高。

JSP是一种服务器端的脚本语言,最大的好处就是开发效率较高,但是因为其业务规则代码与页面代码混为一团,不利于维护,因此并不适应大型应用的要求,取而代之的是基于MVC的Web架构。

MVC的核心思想是将应用分为模型、视图和控制器三部分。模型是指应用程序的数据,以及对这些数据的操作;视图是指用户界面;控制器负责用户界面和程序数据之间的同步。通过MVC的Web架构,可以弱化各个部分的耦合关系,并将业务逻辑处理与页面以及数据分离开来,这样当其中一个模块的代码发生改变时,并不影响其他模块的正常运行,所以基于MVC的Web架构更适应于大型应用开发的潮流。

星球

由盛及衰

故事背景

1995年,SUN公司发布了Java。创始人之一望着手中的咖啡,灵机一动,取名Java。宣传口号是”一次编写,到处运行”(Write Once, Run Anywhere)。

注:一次编写,到处运行,也就是跨平台了。

几乎同年,后来被黑为“世界上最好的语言”PHP也发布了。WordPress和MediaWiki就是有出息的两个儿子。

也是1995年,一个名叫布兰登·艾奇的技术员,为应付任务花了10天设计出JavaScript(这名字就是蹭Java热度,JavaScript与Java只有半毛钱关系)。这个借鉴C、Java、Scheme和Self等语言设计出来的冬冬,初始版本很不好用,但好在后期救回来了,并逐渐走上人生巅峰。

注:一个完整的JavaScript实现应由三个部分组成:ECMAScript、DOM、BOM

出道往事

黑世纪–Servlet写Html代码

下述是MyEclipse新建Servlet时显示的模板。

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class HistoryServlet extends HttpServlet {

/**
* Constructor of the object.
*/
public HistoryServlet() {
super();
}

/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the GET method");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the POST method");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}

/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}

}

上古时代,就是这样一行一行写入Html代码到response对象中的。美工做好Html的静态页面,扔给Java程序员。Java程序员逐条拷贝Html代码,并于后端数据拼接,最后返回带数据的完整的Html。

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

出道–Servlet披着JSP的壳

友商PHP这时候就很优秀,它们选择在html页面中嵌入相应语言来引入动态数据。

细想起来,目标无非就是在最终输出的html的代码中嵌入后台数据。可以在Html文件中嵌入动态数据,也可以在动态页面中嵌入Html静态数据,殊途同归。

于是,JSP诞生了。虽然名字叫做JSP,但JSP实质上就是Servlet实例。暗世纪手动拷贝HTML代码的日子结束了,这些操作交给了JSP引擎(即jspServlet)去执行。

JSP = Html + Java片段。

<%@ page language="java" contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.py.vo.Member"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<base href="<%=basePath%>"/>
<title>电子商务网站</title>
<link href="css/style.css" rel="stylesheet" type="text/css" />
<script>
function quit() {
if (confirm("没有要买的东西了吗?")) {
window.location.href = "MemberServlet.do?method=logoutMember";
}
}
</script>
</head>
<body>
<div id="header">
<div class="logo">
<a href="index.jsp"><img src="images/logo.gif" width="135"
height="55" />
</a>
</div>
<form name="form" method="post"
action="GoodsServlet.do?method=selectByKeywords">
<div class="search">
<input type="text" class="input1" name="keywords"/> <input type="image"
src="images/icon_search.gif" class="input2" />
</div>
</form>
<%
if (session.getAttribute("member") == null) {
%>
<div class="login">
<a href="fg-memberLogin.jsp" class="a1">登录</a>
</div>
<%
} else {
Member member = (Member) session.getAttribute("member");
%>
<div class="login">
<font class="red"><%=member.getAccount()%></font>,欢迎回来&nbsp;&nbsp;<a
href="javascript:quit()">退出</a>
</div>
<%
}
%>
</div>
</body>
</html>

JSP特点

  • 跨平台(以Java作为脚本)
  • 业务代码分离(数据对象模型)
  • 组件重用(JavaBean)
  • 预编译(首次请求JSP是编译执行后,class文件被保存)

危机–优点也会是缺点

JSP文件能够同时写Html和Java,但是。

  1. 动态和静态资源放在一起,一旦服务器出现状况,前后台一起玩完,用户体验极差。

  2. 一旦jsp出现了问题,就需要前端后端发开人员一块来分析解决,效率低。

  3. jsp无法使用nginx等。

  4. jsp页面复杂,难以修改。

  5. 第一次加载jsp需要编译成servlet,时间久,而且业务量大的时候,jsp负担太大。

于是,前后端分离就出现了。

落寞–前后端分离燃烧起来

前后端分离其实就是后端工程师只关注于后端业务逻辑的开发,不再处理前端问题。前端工程师只关注于自己的页面开发。需要数据交互的时候,两者会有一份接口文档。

然后新兴SpringMVC、RestFul、Ajax …

注:MVC是WEB开发模式,并不是SpringMVC专属

然后前端也不再是Web页面,移动端又蓬勃起来…

JSP也就这样渐渐的完成它的时代使命,告别曾经辉煌过的舞台,偶尔在一些老旧的项目中散发着微光…

我的小结

JSP的盛衰似乎令人唏嘘,但这就是技术的发展与进步。它已经完成了它的使命,但这并不意味着JSP应该被描述过时或者应该被抛弃,在适当的场景JSP还是有用武之地的,就像PHP依然那么活跃。

具体的JSP技术与语法,是现在的我不需要去花时间看的。近来觉得编程里边的知识很丰富,面面俱到不大现实也不应该。可以知道很多,但是专注的点也就只能那么几个。正所谓涉猎广泛,重点捕捉。

然后就是觉得学习编程不再纯粹只是看技术细节,还需要提升一点看语言的设计以及系统的整体架构。当然我现在还不会,就怎么说呢,技术是看代码和写代码,思想是像写诗一样优雅的造轮子。

胡言胡语,小结完毕。

参考

知乎:浅谈JSP
曾经风光无限的jsp,为什么现在很少有人用了呢?
php与jsp的区别
再见,JSP

小黄人