如何避免在JSP页面中使用scriptlet?

我被告知在我的JSP页面中使用scriptlets(<%= …%>)并不是一个好主意。

有人可以多一点java / jsp的经验,请给我一些指示,如何改变这个代码,所以更多的“最佳实践”,无论可能是什么?

这个JSP实际上是我的sitemesh主装饰页面。 基本上我的网页devise有一个标签条和一个子菜单,我希望以某种方式突出显示当前标签,并通过查看当前的请求URI显示正确的子菜单。

<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %> <html> <head> <title>My Events - <decorator:title /></title> <link href="<%= request.getContextPath() %>/assets/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="tabs"> <a <%= request.getRequestURI().contains("/events/") ? "class='selected'" : "" %> href='<%= request.getContextPath() %>/events/Listing.action'>Events</a> <a <%= request.getRequestURI().contains("/people/") ? "class='selected'" : "" %> href='<%= request.getContextPath() %>/people/Listing.action'>People</a> </div> <div class="submenu"> <% if(request.getRequestURI().contains("/events/")) { %> <a href="Listing.action">List of Events</a> |<a href="New.action">New Event</a> <% } %> <% if(request.getRequestURI().contains("/people/")) { %> <a href="Listing.action">List of People</a> |<a href="New.action">New Person</a> <% } %> &nbsp; </div> <div class="body"> <decorator:body /> </div> </body> </html> 

谢谢大家

如果你亲眼看到它可以完全没有 scriptlet的话,我认为它更有帮助。

这里有jstl-1.2.jar重写,其中包括JSTL (只需在/WEB-INF/lib放置jstl-1.2.jar ) 核心和函数 taglib:

 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <html> <head> <title>My Events - <decorator:title /></title> <link href="${pageContext.request.contextPath}/assets/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="tabs"> <a ${fn:contains(pageContext.request.requestURI, '/events/') ? 'class="selected"' : ''} href="${pageContext.request.contextPath}/events/Listing.action">Events</a> <a ${fn:contains(pageContext.request.requestURI, '/people/') ? 'class="selected"' : ''} href="${pageContext.request.contextPath}/people/Listing.action">People</a> </div> <div class="submenu"> <c:if test="${fn:contains(pageContext.request.requestURI, '/events/')}"> <a href="Listing.action">List of Events</a> |<a href="New.action">New Event</a> </c:if> <c:if test="${fn:contains(pageContext.request.requestURI, '/people/')}"> <a href="Listing.action">List of People</a> |<a href="New.action">New Person</a> </c:if> &nbsp; </div> 

这里有一个更优化的重写,注意我使用c:set为“caching”expression式的结果以供重用,而且我使用HTML <base>标记来避免在每个链接中放置上下文path(只要使网页中的所有相对URL相对于它 – 没有领先的斜线!):

 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> <c:set var="isEvents" value="${fn:contains(pageContext.request.requestURI, '/events/')}" /> <c:set var="isPeople" value="${fn:contains(pageContext.request.requestURI, '/people/')}" /> <html> <head> <title>My Events - <decorator:title /></title> <base href="${pageContext.request.contextPath}"> <link href="assets/styles.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="tabs"> <a ${isEvents ? 'class="selected"' : ''} href="events/Listing.action">Events</a> <a ${isPeople ? 'class="selected"' : ''} href="people/Listing.action">People</a> </div> <div class="submenu"> <c:if test="${isEvents}"> <a href="Listing.action">List of Events</a>|<a href="New.action">New Event</a> </c:if> <c:if test="${isPeople}"> <a href="Listing.action">List of People</a>|<a href="New.action">New Person</a> </c:if> &nbsp; </div> 

如果您收集所有“硬编码”值(如eventspeople以及将应用程序范围内的Map链接到Map中,并在每个JSTL <c:forEach>以显示选项卡,则实际上可以进行优化。

至于你真正的问题,你可以通过在webapp的web.xml添加以下条目来禁用 scriptlet(并获得有关使用它的运行时错误)。 这可能有助于发现监督脚本。

 <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <scripting-invalid>true</scripting-invalid> </jsp-property-group> </jsp-config> 

要了解关于EL的更多信息,请查看Java EE教程第二部分第五章 。 隐式EL对象,如${pageContext}在这里描述。 要了解关于JSTL的更多信息,请查看Java EE教程第二部分第七章 。 请注意,JSTL和EL是两个独立的东西。 JSTL是一个标准的taglib ,EL只是允许以编程方式访问后端数据。 虽然它通常用在像JSTL这样的标签库中,但它也可以在模板文本中单独使用。

另外,是<%= request.getContextPath() %>一个可以接受的脚本的使用,这是不是皱起了眉头?

这可能是一个不受欢迎的意见,但如果你所做的只是简单的条件和文本插入,我不能find脚本的使用过错。 (注意如果

我可能会使用JSTL和expression式语言,但主要是因为它可以less打字,IDE支持可能会更好(但一个好的JSP IDE也可以find缺less的左括号和类似的东西)。

但从根本上(如“保持模板逻辑”)我没有看到任何区别

 <% if(request.getRequestURI().contains("/events/")) { %> 

 ${fn:contains(pageContext.request.requestURI, '/events/') 

这不是对你的问题的直接回答(并且已经有好几个好的,所以我不会试图添加它),但是你提到了:

有人可以多一点java / jsp的经验,请给我一些指示,如何改变这个代码,所以更多的“最佳实践”,无论可能是什么?

在我看来,关于JSP的最佳实践是它应该被严格地用作模板引擎 ,而不是更多(即没有业务逻辑)。 正如许多人所指出的那样,使用JSTL绝对可以帮助您达到目标,但即使使用JSTL,在JSP中执行操作也很容易。

我个人喜欢遵循Terence Parr在JSP中进行开发时强化模板引擎中的严格模型 – 视图分离的规则。 文中提到了模板引擎(分离模型和视图)的目的,以及一个好的模板引擎的特点。 它很好地研究了JSP,指出了它不是一个好的模板引擎。 毫不奇怪,JSP基本上是太强大了,并且允许开发人员做太多。 我强烈build议阅读这篇文章,它会帮助你将自己限制在JSP的“好”部分。

如果您只阅读该论文中的一个部分,请阅读第7章,其中包含以下规则:

  1. 该视图无法通过直接更改模型数据对象或调用模型上导致副作用的方法来修改模型。 也就是说,模板可以访问模型中的数据并调用方法,但是这样的引用必须是无副作用的。 这个规则部分是因为数据引用必须是不依赖于命令的。 参见7.1节。
  2. 该视图无法对依赖的数据值进行计算,因为计算可能在将来发生变化,无论如何它们都应该整齐地封装在模型中。 例如,该视图无法将图书销售价格计算为“$ price * .90”。 为了独立于模型,该观点不能对数据的含义做出假设。
  3. 该视图不能比较依赖的数据值 ,但可以testing数据的属性,例如多值数据值的存在/不存在或长度。 因为医生喜欢降低最大收缩压对我们,所以像$ bloodPressure <120这样的testing必须转移到模型中。 视图中的expression式必须replace为模拟布尔值(如$ bloodPressureOk!= null)的值存在的testing模板输出可以以模型数据和计算为条件,条件只需要在模型中计算。 即使简单的testing,使负值红色应该在模型中计算; 正确的抽象层次通常是更高的层次,比如“部门x正在亏损”。
  4. 该视图不能做出数据types的假设。 例如,当视图假定数据值是一个date时,某些types的假设是显而易见的,但是会出现更细微的types假设:如果模板假定$ userID是一个整数,则程序员不能将该值更改为非在模型中没有打破模板的数字。 这个规则禁止数组索引,例如colorCode [$ topic]和$ name [$ ID]。视图进一步不能调用具有参数的方法,因为除静态或dynamic外,还有一个假定的参数types,除非可以保证模型方法只是把它们当作对象。 除了graphicsdevise师不是程序员, 期待他们调用方法并知道要传递什么是不现实的。
  5. 来自模型的数据不得包含显示或布局信息。 该模型不能将任何显示信息传递给伪装成数据值的视图。 这包括不传递模板的名称以应用于其他数据值。

顺便提一下,Terence创build了自己的模板引擎,称为String Template ,据说在执行这些规则方面确实做得很好。 我没有亲身经历,但是很想在我的下一个项目上看看。

Scriptlets不是世界上最糟糕的事情。 一个重要的考虑是要考虑谁来维护代码。 如果其网页devise师没有太多的Java经验,那么使用标签库可能会更好。 但是,如果Java开发人员正在进行维护,那么使用scriptlet可能会更容易。

如果最终使用标签库和JSTL,则期望维护者也学习标签库并了解JSTL。 有些开发人员可以,因为这是他们想要或已经拥有的技能,但对于一些只需要每隔几个月处理一次JSP的开发人员来说,使用写得很好的书写脚本可能会很不痛苦,熟悉Java。

您可能想要使用标记库开始。 您可以使用标准标记库JSTL来执行大部分需要脚本的常见事情。 还有很多其他更丰富的标签库,像struts2框架或apache一样使用。

例如

  <c:if test="${your condition}"> Your Content </c:if> 

将取代你的if语句。

JScript语言是JScript语言的首选替代scheme。 这里是一个很好的概述。 你需要像这样添加taglib:

 <%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c' %> 

作为一个例子,JSTL提供了一堆隐含的对象,给你你需要的东西; 你想要的是pageContext.request

所以你可以用${pageContext.request.requestURI}replace<%request.getRequestURI%>

你可以使用<c:if>标签来完成条件。

你需要使用一些Web框架。 或者至less有一些方便的taglib。 或者像FreeMarker这样的模板工具。

广告框架:

如果你喜欢JSP的编码方式,那么我build议使用Struts 2

 <s:if test="%{false}"> <div>Will Not Be Executed</div> </s:if> <s:elseif test="%{true}"> <div>Will Be Executed</div> </s:elseif> <s:else> <div>Will Not Be Executed</div> </s:else> 

然后是面向组件的JSF

如果你喜欢OOP并用Java编码所有东西,可以试试Apache Wicket (我最喜欢的)或Google Web Toolkit