我被告知在我的JSP页面中使用scriptlet(<%= ...%>)并不是一个好主意。
对于有更多java / jsp经验的人,请给我一些关于如何更改此代码的指示,以便更多“最佳实践”,无论可能是什么?
这个JSP实际上是我的sitemesh主装饰页面。基本上我的网页设计有一个标签条和一个子菜单,我希望通过查看当前的请求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>
<% } %>
</div>
<div class="body">
<decorator:body />
</div>
</body>
</html>
全部谢谢
答案 0 :(得分:42)
我认为如果你亲眼看到它实际上可以完全没有 scriptlet,那么它会有所帮助。
这是一对一的重写,在其他JSTL的帮助下(只需在/WEB-INF/lib
)jstl-1.2.jar
和core taglib中删除functions:
<%@ 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>
</div>
这是一个更优化的重写,请注意我使用c:set
来“缓存”表达式结果以便重用,并且我使用HTML <base>
标记来避免在每个链接中放置上下文路径(只需网页中的相对网址相对于它 - 没有前导斜杠!):
<%@ 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>
</div>
如果您收集所有“硬编码”值(如events
和people
)并在应用程序范围内的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 tutorial part II chapter 5。 ${pageContext}
描述了隐式EL对象,例如{{1}}。要了解有关JSTL的更多信息,请查看here。请注意,JSTL和EL是两个独立的东西。 JSTL是标准taglib ,EL只允许以编程方式访问后端数据。虽然它通常用在像JSTL这样的taglib中,但它也可以在模板文本中单独使用。
答案 1 :(得分:9)
顺便说一下,
<%= request.getContextPath() %>
是否可以接受使用那些不那么皱眉的小脚本?
这可能是一个不受欢迎的意见,但如果您所做的只是简单的条件和文本插入,我在使用scriptlet时找不到太多错误。 (注意 if )
我可能会使用JSTL和表达式语言,但主要是因为它可以减少输入,并且IDE支持可能更好(但是一个好的JSP IDE也可以找到缺少的右括号和类似的东西)。
但从根本上说(如“保持模板中的逻辑”)我看不出
之间的任何区别<% if(request.getRequestURI().contains("/events/")) { %>
和
${fn:contains(pageContext.request.requestURI, '/events/')
答案 2 :(得分:6)
这不是你问题的直接答案(并且已经有好几个,所以我不会尝试添加它),但你提到了:
有人可以使用更多java / jsp 经验请给我一些 关于如何更改此代码的指针 所以它更“最佳实践”,无论如何 那可能是?
在我看来,关于JSP的最佳实践是它应该严格地用作模板引擎,而不是更多(即没有业务逻辑)。正如许多人所指出的那样,使用JSTL肯定会帮助你实现目标,但即使使用JSTL,在JSP中也很容易做到。
我个人喜欢在JSP开发时遵循Terence Parr在Enforcing Strict Model-View Separation in Templating Engines中规定的规则。本文提到了模板引擎的目的(分离模型和视图),以及良好的模板引擎的特性。它需要仔细研究JSP,并指出它不是一个好的模板引擎。毫不奇怪,JSP基本上太强大,并且允许开发人员做太多。我强烈建议您阅读本文,它将帮助您将自己局限于JSP的“好”部分。
如果您只阅读该论文中的一个部分,请阅读第7章,其中包括以下规则:
- 视图无法通过直接更改模型来修改模型 数据对象或通过调用方法 引起副作用的模型。 也就是说,模板可以访问数据 从模型和调用方法,但 这些参考必须是副作用 自由。这个规则部分产生 因为数据引用必须是 为了不敏感。见7.1节。
- 视图无法对依赖数据执行计算 值因为计算可能 改变未来,他们应该 整齐地封装在模型中 任何情况。例如,视图不能 计算书籍销售价格为 “$价格* 0.90”。独立于 模型,视图无法制作 关于数据含义的假设。
- 视图无法比较相关数据值,但可以测试 数据的属性,如 是否存在或长度 多值数据值。测试就像 $ bloodPressure&lt; 120必须转移到 医生喜欢保留的模型 降低最大收缩压 在我们身上视图中的表达式必须是 替换为a的存在测试 模拟布尔值的值 $ bloodPressureOk!= null模板输出 可以以模型数据和条件为条件 计算,有条件的 必须在模型中计算。甚至 做出负值的简单测试 红色应该在模型中计算; 正确的抽象级别是usu- 某种更高层次的盟友 “部门x正在赔钱。”
- 视图无法进行数据类型假设。某些类型的假设是 当视图假设数据时显而易见 例如,value是一个日期,但更多 细微类型的假设:如果a 模板假设$ userID是 整数,程序员不能 将此值更改为非数字值 在模型中没有打破 模板。此规则禁止数组 索引,如colorCode [$ topic]和 $ name [$ ID]视图进一步不能 调用带有参数的方法 (静态或动态)有 假定的论证类型,除非一个 可以保证模型方法 仅将它们视为对象。 除了图形设计师不是 程序员;期待他们调用 方法,知道要传递的是什么 不现实的。
- 模型中的数据不得包含显示或布局信息。 模型无法通过任何显示 伪装成视图的信息 数据值。这包括不通过 要应用的模板的名称 其他数据值。
醇>
顺便提一下,Terence已经创建了自己的模板引擎String Template,据称它可以很好地执行这些规则。我没有个人经验,但我很乐意在下一个项目中查看。
答案 3 :(得分:6)
Scriptlet并不是世界上最糟糕的事情。一个重要的考虑因素是考虑谁将维护代码。如果它的Web设计人员没有太多的Java经验,那么最好使用标记库。但是,如果Java开发人员正在进行维护,那么使用scriptlet可能会更容易。
如果您最终使用标记库和JSTL,那么您希望维护者也可以学习标记库并了解JSTL。一些开发人员可以很好地使用它,因为它是他们想要或已经拥有的技能,但对于一些只需要每隔几个月左右处理一次JSP的开发人员来说,使用写得很好的清晰编写的scriptlet就不那么痛苦了。 ,熟悉的Java。
答案 4 :(得分:3)
您可能希望从使用标记库开始。您可以使用标准标记库JSTL来完成您需要编写的大多数常见内容。还有许多其他更丰富的标记库,如struts2框架或apache中使用的那样。
e.g。
<c:if test="${your condition}">
Your Content
</c:if>
会替换你的if语句。
答案 5 :(得分:3)
scriptlet的首选替代方法是JSTL表达式语言; here是一个很好的概述。你需要像这样添加taglib:
<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c' %>
作为一个例子,JSTL提供了一堆隐式对象,可以为您提供所需的东西;你想要的是pageContext.request
。
因此,您可以将<%request.getRequestURI%>
替换为${pageContext.request.requestURI}
。
您可以使用<c:if>
标记进行条件化。
答案 6 :(得分:2)
您需要使用一些Web框架。或者至少是一些方便的taglib。或者像 FreeMarker 这样的模板练习。
广告框架:
如果您喜欢JSP编码方式,那么我建议 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 。