您的位置:寻梦网首页编程乐园Java天地JSP 专辑JSP001 HTML 离线版
Java 天地
JSP001 HTML 离线版
精选文章 >> 深入研究 >> 困扰JSP的一些问题(jsp和宏之间的争议)

由 webmaster 发布于: 2001-01-20 16:12

Blueski编译


(编者按:此文通过jsp和template engines的比较,提示了目前jsp的一些不足。后者也是一项基于servlets的技术,有些类似于宏,可以简化开发,但后来没有得到应有的重视和发展。)


如今每一个使用servlets的开发者都知道JSP,一种由Sun公司发明并花费大量精力加以推行并建构在servlet技术之上的web技术。JSP将servlet中的html代码脱离了出来,从而可以加速web应用开发和页面维护。实际上,由Sun发布的官方 "应用开发模型"文档上说得更远: "JSP技术应该被视为标准,而servlets在多数情况下可视为一种补充。" ( Section 1.9, 1999/12/15听取意见版 )。

本文的目的在于听取对该申明的合理性的评估 -- 通过比较JSP和另一项基于servlets的技术: template engines(模板引擎)。

直接使用Servlets的问题

 

起初,servlets被发明,整个世界都看到了它的优越。基于servlet的动态网页可以被快速执行,可以在多个服务器之间轻易转移, 并且可以和后台数据库完美地集成。 Servlets被广泛接受成为一种web服务器端的首选平台。
但是,通常通过简单方式即可实现的html代码现在却要让程序员通过 out.println()调用每一行HTML行,这在实际的 servlet应用中成为了一个严重问题。 HTML内容不得不通过代码来实现, 对于大的HTML页来说不啻是一项繁重费时的工作。另外,负责网页内容的人员不得不请开发人员来进行所有的更新。为此,人们寻求这一种更好的解决方式。

JSP到!


JSP 0.90出现了。在这种技术中你可以将Java代码嵌入到HTML文件,服务器将自动为页面创建一个 servlet。 JSP被认为是一种写servlet的简易方式。所有HTML可以直接得到而不必通过out.println()调用,而负责页面内容的人员可以直接修改HTML而不必冒破坏Java代码的风险。
但是,让页面美术设计师和开发人员在同一文件上工作并不理想,让Java嵌入HTML被证明是就象将HTML 嵌入Java一样令人尴尬。读取一堆很乱的代码仍然是一件困难的事情。

于是,人们在使用jsp方面变得成熟,更多地使用了JavaBeans。 Beans包含了jsp所需的业务逻缉代码。JSP中的大多数代码都可以取出来放到bean中去,而只留下极少的标记用于调用bean。


最近,人们开始认为这种方式下的JSP页面真的很象是视图(view)。它们成为一个用于显示客户端请求的结果的组件。于是人们会想,为什么不直接对view发送请求呢? 目标view如果对该请求不合适又将如何? 说到底,很多的请求有多种可能来取得结果view视图。例如,同一请求可能产生成功的页面,数据库例外出错报告,或者是缺少参数的出错报告。同一请求可能产生一个英文页面也可能是西班牙文页面,这取决于客户端的locale。为什么客户端必须直接将请求发送给view?为什么客户端不应该将请求发送给一些通用的服务器组件并让服务器来决定JSP view的返回?


这使很多人接受了已被称为"Model 2"的设计, 这是在JSP 0.92中定义的基于model-view-controller的模型。在这种设计中,请求被发送到一个servlet控制器,它执行了商业逻缉并产生一个相近的数据"model"来用于显示。这一数据随后通过内部送到一个JSP "view"来进行显示,这样看起来JSP页就象是一个普通的嵌入的JavaBean。 可以根据负责控制的servlet的内部逻辑来选择适当的JSP页面进行显示。这样,JSP文件成为了一个漂亮的template view。这就是另一种发展,并被另外一些开发者所推崇至今--->>

进入Template Engines


使用template engine来代替通常目的的JSP, 接下去的设计将变得简单,语法更简单,出错信息更易读,工具也更用户化。 一些公司已经做了这样的引擎,最著名的可能是WebMacro (http://webmacro.org, from Semiotek),他们的引擎是免费的。
开发者应该明了,选定一个template engine来取代JSP提供了这么一些技术优势,这也正是jsp的一些不足之处:

问题 #1: Java代码太模板化了


虽然被认为是不好的设计,JSP仍试图将Java代码加入web页面。这有些象是Java曾经做的,即对C++的简化修改,template engines也通过将jsp中的较低层的源码移去来使之简化。Template engines实行了更好的设计。


问题 #2: 要求Java代码


在JSP页中要求写一些Java代码。例如,假设某页要决定当前web应用中根的上下文从而导向其主页,
在JSP中最好使用如下Java代码:

<a href="<%= request.getContextPath() %>/index.html">Home page</a>

你可以试图避免 Java代码,而使用 <jsp:getProperty> 标记但这将给你六下难以阅读的字串:

<a href="<jsp:getProperty name="request"
property="contextPath"/>/index.html">HomePage</a>

使用template engine则没有Java代码和难看的语法。这里是同样要求下在WebMacro中的写法:

<a href="$Request.ContextPath;/index.html">Home page</a>

在WebMacro中, ContextPath 作为 $Request变量的一个属性,使用类似Perl的语法。其它er template engines使用了其它的语法类型。

再看另 一个例子,假设一个高级的"view"需要设定一个cookie来记录用户缺省的颜色配置 -- 这种任务看起来大概只能由view而不是servlet控制器来完成。在JSP中要有这样的Java代码:

<% Cookie c = new Cookie("colorscheme", "blue"); response.addCookie(c); %>

在WebMacro中则没有Java代码:

#set $Cookie.colorscheme = "blue"

作为最后一个离子,假如又要重新找回原来的cookie中的颜色配置。对于JSP,我们可以认为也有一个相应的工具类来提供帮助,因为用getCookies()直接做这样低层的会变得可笑而且困难。在JSP中:

<% String colorscheme = ServletUtils.getCookie(request, "colorscheme"); %>

在WebMacro中没有对工具类的需要,通常是:

$Cookie.colorscheme.Value

对写jsp的图形艺术师,又是哪一种语法更容易学习呢?

JSP 1.1 引入了自定义标记(custom tags)允许任意的和HTML相似的标记在JSP页面中在后台执行Java代码,这将具有一定的价值,但前提是要有一个广泛知晓的,全功能的,可以免费得到的,标准化的标记库。目前还没有出现这样的标记库。

问题 #3: 简单工作仍然很累人


即使是很简单的工作,例如包含 header和 footer,在JSP中仍然很很困难。 假设有一个 "header"和一个 "footer"模板要包含到所有页面,而每一个模板要在content中包含当前的页标题。
在JSP中最佳办法是:
<% String title = "The Page Title"; %>
<%@ include file="/header.jsp" %>
...你的页面内容...
<%@ include file="/footer.jsp" %>

页面设计者要记住不能遗漏第一行的分号并要将title定义为一个字符串。此外, /header.jsp和/footer.jsp必须在根目录下并且必须是可存取的完整文件。
在WebMacro中包含headers和footers做起来比较简单:

#set $title = "The Page Title"
#parse "header.wm"
Your content here
#parse "footer.wm"

这里对设计者来说没有要牢记的分号或对title的定义, .wm文件可以放在可自定义的搜索路径下。


问题 #4: 很粗的循环


在JSP中循环很困难。这里是用JSP重复打印出每一个ISP对象名字。
<%
Enumeration e = list.elements();
while (e.hasMoreElements()) {
out.print("The next name is ");
out.println(((ISP)e.nextElement()).getName());
out.print("<br>");
}
%>

也许什么时候会有用户自定义标记来做这些循环。对"if"也是如此。JSP页可能看上去成了很古怪的java代码。而同时,webmacro循环很漂亮:
#foreach $isp in $isps {
The next name is $isp.Name <br>
}

如果必要的话,#foreach指令可被自定义的 #foreach-backwards指令很容易地取代。
用jsp的话很可能变这样:(这里是一个可能的 <foreach>标记)

<foreach item="isp" list="isps">
The next name is <jsp:getProperty name="isp" property="name"/> <br>
</foreach>

设计者当然地回选择前者。


问题 #5: 无用的出错信息


JSP常有一些令人惊讶的出错信息。这是因为页面首先被转换成为一个servlet然后才进行编译。好的JSP 工具可以相对增加找到出错位置的可能性,但即使是最好的工具也无法使所有出错信息都能容易地被读懂。由于转化的过程,一些错误对工具来说可能根本不可能被识别。
例如,假设JSP页面需要建立一个对所有页通用的标题。以下代码并没有错:

<% static String title = "Global title"; %>

但Tomcat会提供以下出错信息:
work/%3A8080%2F/JC_0002ejspJC_jsp_1.java:70: Statement expected.
static int count = 0;
^

此信息认为以上脚本被放入 _jspService()方法而静态变量不允许放入方法中。该语法应该是 <%! %>。页面设计者很难读懂这些出错信息。即使最好的平台在这方面也做得很不够。即使所有 Java代码都从页中移出也无法解决问题。另外,以下表达式有什么错?

<% count %>
tomcat给出:
work/8080/_0002ftest_0002ejsptest_jsp_0.java:56: Class count not found in
type declaration.
count
^
work/8080/_0002ftest_0002ejsptest_jsp_0.java:59: Invalid declaration.
out.write("\r\n");
^

换句话说,只是遗失了一个标记而已。应该是 <%= count %>。


由于template engine可以在template文件中直接产生而没有任何戏剧性的向代码转化,所以可以非常容易地给出适当的出错报告。 依次类推,当c语言的命令被打入Unix shell的命令行, 你并不希望shell 会生成一个C程序来运行这个命令,而只是需要shell简单地解释命令并加以执行,如有错误也直接给出。
问题 #6: 需要一个编译器


JSP需要一个置放在webserver中的编译器。由于Sun拒绝放弃包含了他们的javac编译器的tools.jar库, 这其中就变得有问题了。Web服务器可以包含进一个第三方的编译器如ibm的 jikes。但这样的编译器并不能在所有平台上顺利工作(用 C++写成的) 也不利于建立纯Java 的web服务器。 JSP有一个预编译选项可以起到一定作用,尽管并不完美。


问题 #7: 空间的浪费


JSP消耗了额外的内存和硬盘空间。对服务器上每30K的JSP文件,必须要有相应的大于30K的类文件产生。实际上使得硬盘空间加倍。考虑到JSP文件随时可以很容易地通过 <%@ include>包含一个大的数据文件,这样的关注有着很现实的意义。同时,每一个JSP的类文件数据必须加载到服务器的内存中,这意味着服务器的内存必须永远地将整个JSP文档树保存下去。少数一些JVM有能力将类文件数据从内存中移去;但是,程序员通常无法控制这样的规则来重新申明,而且对大的站点来说重新申明可能不是很有效。对template engines由于没有产生第二个文件,所以节省了空间。Template engines还为程序员提供对templates在内存中进行缓存的完全控制。


使用template engine也有一些问题:

Template的问题 #1: 没有严格定义


template engine该如何工作并没有严格定义。可是,但相对jsp来说,其实这并不很重要,和 JSP不同的是,template engines对web服务器没有任何特殊要求 -- 任何支持servlet的服务器都可以支持template engines (包括API 2.0服务器如Apache/JServ,它们并不能完全支持 JSP)! 如果为最好的template engine设计提供健康的竞争本可以引起一场耀眼的革新,特别是有开放源码的促进,(可以让思想相互推动和促进),那么今天的WebMacro就会象Perl一样,没有严格定义但公开源码组织的推动就是它的标准。


Template的问题 #2: 没有获得公认


Template engines并未被广泛知晓。JSP已经占据了极大的商业市场,并且深入人心。而使用g template engines只能是一种未被了解的替代技术。


Template的问题 #3: 尚未调配好


Template engines还没有被高度地调配好。没有对template engine 和JSP两者进行性能测试和比较。理论上说一个调配完好的template engine实现应该和一个调配好的JSP相匹配;但是,考虑到第三方为jsp已经作出了这么深远的推动,结果只有jsp被很好地调配好了。


JSP的角色


当然地,JSP在将来必然会有其地位。即使从名称上也可以看出JSP和ASP的相似性,它们只有一个字母的差别。所以如果要让使用asp的人们转向java,非常相似的jsp环境将对此起到很大的推动作用,和asp保持这种对应关系所能起到的作用应该也是被推出jsp的设计者重点考虑到的。
然而这里想要强调的一点是:有利于转入新环境的工作者,以及实际上是否是使用该环境的最佳方式,这两者是有很大不同的。

JSP日益显示出它正成为最重要的java技术之一, 它让人们离开ASP的世界 -- 由此,Sun将支持这一强有力的商业case, Java相关技术支持者也将给予更大力的支持。

可是,这并非java平台的最佳解决方案。这将使java解决方案变得好象是没有java的解决方案了。


原文如下:

The Problems with JSP
January 25, 2000
by Jason Hunter (www.servlets.com/soapbox/problems-jsp.html

By now almost everyone using servlets has heard about JavaServer Pages (JSP), a Sun-invented technology built on top of servlets. Sun has done a marvelous job promoting JSP as a way to get HTML out of servlet code, speeding web application development and improving web page maintenance. In fact, the official "Application Programming Model" document published by Sun has gone so far as to say, "JSP technology should be viewed as the norm while the use of servlets will most likely be the exception." (Section 1.9, December 15, 1999, Draft Release) This paper evaluates whether that claim is valid -- by comparing JSP to another technology built on servlets: template engines.

The Problem with Straight-up Servlets
In the beginning, servlets were invented, and the world saw that they were good. Dynamic web pages based on servlets executed quickly, could be moved between servers easily, and integrated well with back-end data sources. Servlets became widely accepted as a premiere platform for server-side web development.
However, the commonly-used simple approach to generating HTML content, having the programer write an out.println() call per HTML line, became a serious problem for real servlet use. HTML content had to be created within code, an onerous and time consuming task for long HTML pages. In addition, content creators had to ask developers to make all content changes. People searched for a better way.

Along Comes JSP
Around this time JSP 0.90 came along. With this new technology you could put snippets of Java code inside your HTML, and the server would automatically create a servlet from the page. This helped quite a lot. There was no attempt to hide the Servlet API; JSP was considered a "cheap" way for a Java programmer to write a servlet. All the HTML code could be included directly without out.println() calls and page creators could make changes to the HTML without serious risk of breaking the Java code.
But having artists and developers working on the same file wasn't ideal, and having Java inside HTML proved almost as awkward as having HTML inside Java. It could easily create a hard to read mess.

So people matured in their use of JSP and started to rely more on JavaBeans. Beans were written to contain business logic code needed by the JSP page. Much of the code inside the JSP page could be moved out of the page into the bean with only minimal hooks left behind where the page would access the bean.

More recently, people have started to note that JSP pages used this way are really a "view". They're a component used to display the results of a client request. So people thought, Why submit a request directly to a "view"? What if the targetted "view" isn't the proper view for that request? After all, many requests have several possible resulting views. For example, the same request might generate a success page, a database exception error report, or a required parameter missing error report. The same request might also generate a page in English or a page in Spanish, depending on the client's locale. Why must a client directly submit its request to a view? Shouldn't the client make a request to some general server component and let the server determine the JSP view to return?

This belief caused many people to adopt what has been called the "Model 2" design, named after an architecture laid out in the JSP 0.92 specification and based on the model-view-controller pattern. With this design, requests are submitted to a servlet "controller" that performs business logic and generates an appropriate data "model" to be displayed. This data is then passed internally to a JSP page "view" for rendering, where it appears to the JSP page like a normal embedded JavaBean. The appropriate JSP page can be selected to do the display, depending on the logic inside the controlling servlet. The JSP page becomes a nice template view. This was another improvement -- and where many serious developers stand today.

Enter Template Engines
But why suffer the complexity of JSP just to do templating? Might it not be better to use a dedicated template engine? By using a template engine intended for this exact use instead of the general-purpose JSP, the underlying design can be cleaner, the syntax clearer, the error messages more meaningful, and the tool more customizable. Several companies have built such engines, the most popular probably being WebMacro (http://webmacro.org, from Semiotek) whose engine is free.
Using a dedicated template engine instead of JSP offers several technical advantages that developers should be aware of:

Problem #1: Java Code Too Tempting
JSP makes it tempting to put Java code in the web page, even though that's considered bad design. Just as Java improves on C++ by removing the ability to use global variables and multiple inheritance, so do template engines improve on JSP by removing the ability to put raw code in the page. Template engines enforce good design.
Problem #2: Java Code Required
Doing mundane things in JSP can actually demand putting Java code in the page. For example, assume the page needs to determine the context root of the current web application to create a link to the web app home page:
In JSP this is best done using Java code:

<a href="<%= request.getContextPath() %>/index.html">Home page</a>
You can try to avoid Java code using the <jsp:getProperty> tag but that leaves you with the following hard-to-read string:

<a href="<jsp:getProperty name="request"
property="contextPath"/>/index.html">HomePage</a>
Using a template engine there's no Java code and no ugly syntax. Here's the same command written in WebMacro:

<a href="$Request.ContextPath;/index.html">Home page</a>
In WebMacro, ContextPath is seen as a property of the $Request variable, accessed using a Perl-like syntax. Other template engines use other syntax styles.

An another example where JSP requires Java code in the page, assume an advanced "view" needs to set a cookie to record the user's default color scheme -- a task that presumably should be done by the view and not the servlet controller. In JSP it requires Java code:

<% Cookie c = new Cookie("colorscheme", "blue"); response.addCookie(c); %>
In WebMacro there's no Java code:

#set $Cookie.colorscheme = "blue"

As a last example, assume it's time to retrieve the color scheme cookie. For the benefit of JSP, we can presume also there's a utility class available to help since doing this raw with getCookies() is ridiculously difficult. In JSP:

<% String colorscheme = ServletUtils.getCookie(request, "colorscheme"); %>
In WebMacro there's no need for a utility class and it's always:

$Cookie.colorscheme.Value
For graphics artists writing JSP pages, which syntax would be simpler to learn?
JSP 1.1 introduced custom tags (allowing arbitrary HTML-like tags to appear in JSP pages executing Java code on the backend) which may help with tasks like this, assuming there becomes a widely known, fully featured, freely available, standardized tag library. So far that has yet to occur.

Problem #3: Simple Tasks are Hard
Doing even a simple task such as header and footer includes is overly difficult with JSP. Assume there's a "header" template and a "footer" template to be included on all pages, and each template includes in its content the current page title.
In JSP the best way to do this is as follows:

<% String title = "The Page Title"; %>
<%@ include file="/header.jsp" %>
Your content here
<%@ include file="/footer.jsp" %>

Page creators must not forget the semi-colon in the first line and must make sure to declare title as a Java String. Plus, the /header.jsp and /footer.jsp must be made publicly accessible somewhere under the document root even though they aren't full pages themselves.
In WebMacro including headers and footers is done easily:

#set $title = "The Page Title"
#parse "header.wm"
Your content here
#parse "footer.wm"

There are no semi-colons or String types for designers to remember, and the .wm files are found in a customizable search path, not under the document root.
Problem #4: Lousy Looping
Looping is overly difficult in JSP. Here's the JSP code to iterate over a vector of ISP objects printing the name of each.
<%
Enumeration e = list.elements();
while (e.hasMoreElements()) {
out.print("The next name is ");
out.println(((ISP)e.nextElement()).getName());
out.print("<br>");
}
%>

Someday there will be custom tags for doing these loops. And custom tags for "if" checks too. And JSP pages may look like a grotesque Java reimplemented with tags. But meanwhile, the webmacro loop is already quite nice:
#foreach $isp in $isps {
The next name is $isp.Name <br>
}

The #foreach directive could be replaced by a custom #foreach-backwards directive fairly easily as well if such a thing were necessary.
Will custom tags really solve this problem? Probably not. Here's a possible <foreach> tag.

<foreach item="isp" list="isps">
The next name is <jsp:getProperty name="isp" property="name"/> <br>
</foreach>

Which would a graphics artist prefer?
Problem #5: Useless Error Messages
JSP page syntax errors can cause surprisingly odd and useless error messages. This is due to the fact the page is transformed into a servlet and then compiled. Good JSP tools can help narrow down errors to likely syntax error locations, but even the best of tools will probably have problems making all error messages meaningful. Some errors will just be impossible for tools to diagnose, due to the transformation.
For example, assume a JSP page needs to set a title common across all pages. What's wrong with the following?

<% static String title = "Global title"; %>

Well, the Tomcat reference implementation for JSP says this is wrong:
work/%3A8080%2F/JC_0002ejspJC_jsp_1.java:70: Statement expected.
static int count = 0;
^
This cryptic error is trying to say that scriptlets like the above are placed inside the _jspService() method and static variables aren't allowed inside methods. The syntax should be <%! %>. Page designers won't recognize this error, and programmers likely won't either without looking at the generated source. Even the best tools probably won't be much help with errors such as these.
Assuming all the Java code could be moved out of the page, that still doesn't solve this problem. What's wrong with this expression that prints the value of count?

<% count %>

The Tomcat engine says:
work/8080/_0002ftest_0002ejsptest_jsp_0.java:56: Class count not found in
type declaration.
count
^
work/8080/_0002ftest_0002ejsptest_jsp_0.java:59: Invalid declaration.
out.write("\r\n");
^
In other words, there's an equal sign missing. It should be <%= count %>.
Because a template engine can operate directly on the template file without any "magical" translation to code, it's far easier to properly report errors. To use an analogy: When commands are typed into a command line Unix shell written in C, you don't want the shell to create a C program to execute the command. You want the shell to simply interpret the command and behave accordingly, with direct error messages when necessary.

Problem #6: Need a Compiler
JSP requires a compiler be shipped with the webserver. That's problematic, especially since Sun doesn't give away the tools.jar library containing their javac compiler. Web servers can package an outside vendor's compiler such as IBM's jikes; however such compilers generally don't work on all platforms and (being written in C++) aren't much help to a pure-Java web server. JSP has a pre-compile option that can help some here, although that's a less than elegant solution.
Problem #7: Wasted Space
JSP consumes extra hard drive space and extra memory space. For every 30K JSP file on the server there must be a corresponding larger-than-30K class file created. This essentially doubles the hard drive requirements to store JSP pages. Considering how easily a JSP file can <%@ include> a large data file for display, this becomes a real concern. Also, each JSP's class file data must be loaded into the server's memory, meaning the server may eventually store the entire JSP document tree in memory. A few JVMs have the ability to remove class file data from memory; however, the programmer generally has no control over the rules for reclaiming and for large sites the reclaiming probably won't be aggressive enough. With template engines there's no need to duplicate the page data into a second file, so hard drive space is spared. Template engines also give the programmer full control over how templates are cached in memory.
There are also some downsides to using a template engine:

Template Problem #1: No Specification
No specification exists for how a template engine should behave. However, it's interesting to note that this is far less important than with JSP because, unlike JSP, template engines demand nothing special of the web server -- any server supporting servlets supports template engines (including API 2.0 servers like Apache/JServ which can't fully support JSP)! Healthy competition for the best template engine design could actually spark innovation, especially assuming open source implementations that can leverage each other's ideas and code. As it stands now, WebMacro exists like Perl, a tool where the open source implementation is the specification.
Template Problem #2: Not Widely Known
Template engines aren't widely known. JSP has had a tremendous amount of marketing and has gained terrific mind share. Using template engines is a relatively unknown alternative technique.
Template Problem #3: Not Yet Tuned
Template engines have yet to be highly tuned. No performance numbers have been taken comparing template engine and JSP performance. Theoretically a well tuned implementations of a template engine should match a tuned implementation of JSP; however in the world today, considering the effort third party vendors have given to JSP so far, the odds are good that JSP implementations are better tuned.
The Role of JSP
So is there a place for JSP in the future? Certainly. JSP is entirely relevant if what you're trying to do is wean people off of ASP. There's an extremely strong argument for providing something familiar looking in a new environment. This was one of the big motivations behind the creation of JSP, and that shows from the name -- it's no coincidence "JSP" is just one letter off from "ASP".
Yet there's a difference between what's suitable to someone who is new to an environment, and what's actually the best way to use that environment.

JSP is going to turn out to be one of the most important Java technologies for convincing people to leave the ASP world in favor of Java -- and hence there's a strong business case for Sun supporting it, and for any Java booster to support it.

However, that doesn't make it the best solution for the Java platform. That makes it the Java solution that is most like the non-Java solution.



资料来源: JSP001.com