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

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

如果有人有更多的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>
  <% } %>  
  &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为“缓存”表达式结果以供重用,并且我使用HTML <base>标记来避免将上下文路径放在每个链接中(只需使网页中的所有相对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中并在每个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教程第II部分第5章。隐式EL对象,如${pageContext}在这里描述。 要了解关于JSTL的更多信息,请查阅Java EE教程第二部分第7章。请注意,JSTL和EL是两个独立的东西。 JSTL是一个标准的taglib,EL只是允许以编程方式访问后端数据。 虽然它通常用于像JSTL这样的taglib,但它也可以在模板文本中单独使用。


另外, <%= request.getContextPath() %>可接受的scriptlet的使用是不会皱眉的吗?

这可能是一个不受欢迎的观点,但是如果你所做的只是简单的条件和文本插入,我在使用scriptlet时就找不到太多的错误。 (注意如果)

我可能会使用JSTL和表达式语言,但主要是因为它可能更少打字,并且IDE支持可能会更好(但一个好的JSP IDE也可以找到缺少的右括号和类似的东西)。

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

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

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

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

如果有人有更多的java / jsp经验,请给我一些关于如何更改此代码的指示,以便更好地实现它,无论这可能是什么?

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

我个人喜欢遵循在JSP中开发时由Terence Parr实施严格的模板引擎中的模型 - 视图分离中规定的规则。 本文提到模板引擎的目的(分离模型和视图)以及良好模板引擎的特性。 它仔细研究了JSP并指出了它不是一个好的模板引擎。 毫不奇怪,JSP基本上太强大了,并且允许开发人员做太多。 我强烈建议阅读本文,它将帮助您将自己限制在JSP的“良好”部分。

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

  • 该视图无法通过直接更改模型数据对象或调用模型上导致副作用的方法来修改模型。 也就是说,模板可以访问模型中的数据并调用方法,但是这种引用必须是无副作用的。 这个规则部分是因为数据引用必须是不依赖于命令的。 参见7.1节。
  • 该视图无法对依赖的数据值执行计算,因为计算可能在将来发生变化,并且在任何情况下都应该整齐地封装在模型中。 例如,该视图无法将图书销售价格计算为“$ price * .90”。 为了独立于模型,该观点不能对数据的含义做出假设。
  • 该视图不能比较依赖的数据值 ,但可以测试数据的属性,例如多值数据值的存在/不存在或长度。 由于医生喜欢降低最大收缩压,因此必须将$ bloodPressure <120等测试转移到模型中。 必须将视图中的表达式替换为模拟布尔值(例如$ bloodPressureOk!)的值存在的测试!= null模板输出可以以模型数据和计算为条件,条件只需要在模型中计算。 即使是简单的测试,使负值红色应在模型中计算; 正确的抽象层次通常是更高的层次,比如“部门x正在亏损”。
  • 该视图不能进行数据类型假设。 例如,当视图假定数据值是日期时,某些类型的假设是显而易见的,但是会出现更细微的类型假设:如果模板假定$ userID是整数,则程序员不能将此值更改为非 - 模型中的数字在不破坏模板的情况下。 此规则禁止数组索引,例如colorCode [$ topic]和$ name [$ ID]。视图进一步不能调用具有参数的方法,因为除静态或动态外,还有一个假定的参数类型,除非可以保证模型方法只是把它们当作对象。 除了图形设计师不是程序员, 期待他们调用方法并知道要传递什么是不现实的。
  • 来自模型的数据不得包含显示或布局信息。 该模型不能将任何显示信息传递给伪装成数据值的视图。 这包括不传递模板的名称以应用于其他数据值。
  • 顺便提一句,特伦斯创建了自己的模板引擎,称为字符串模板,该模板据说在执行这些规则方面确实做得很好。 我没有亲身体验过它,但很想在我的下一个项目中查看它。

    链接地址: http://www.djcxy.com/p/13359.html

    上一篇: How to avoid using scriptlets in my JSP page?

    下一篇: Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern