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

发布于 2024-08-20 13:30:53 字数 1543 浏览 5 评论 0原文

有人告诉我,在 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>
  <% } %>  
  &nbsp;
</div>

<div class="body">
  <decorator:body />
</div>

</body>
</html>

谢谢大家

I've been told that the use of scriptlets (<%= ... %>) in my JSP pages isn't such a great idea.

Can someone with a bit more java/jsp experience please give me some pointers as to how to change this code so its more 'best practice', whatever that may be?

This JSP is actually my sitemesh main decorator page. Basically my web design has a tab strip and a submenu, and i wish to somehow highlight the current tab and show the correct submenu by looking at the current request 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>

Thanks all

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

岁月流歌 2024-08-27 13:30:53

我认为,如果您亲眼看到它实际上可以完全无需 scriptlet 完成,那会更有帮助。

这是在 JSTL< 等帮助下进行的一对一重写/a> (只需删除 jstl-1.2.jar< /code>/WEB-INF/lib 中)核心functions 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>
   
</div>

这是一个更优化的重写,请注意,我使用 c:set 来“缓存”表达式结果以供重用,并且我使用 HTML 标签以避免将上下文路径放入每个链接中(只需使网页中的所有相对 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>
   
</div>

如果您收集所有这些“硬编码”值,例如 eventspeople 以及应用程序范围内 Map 中的链接文本,并在每个 JSTL 显示选项卡。

至于您的实际问题,您可以通过在 web 应用程序的 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 教程第二部分第 5 章。隐式 EL 对象,例如 ${pageContext} 的描述是 这里。要了解有关 JSTL 的更多信息,请查看 Java EE 教程第二部分第 7 章。请注意,JSTL 和 EL 是两个不同的东西。 JSTL 是一个标准标签库,EL 仅支持以编程方式访问后端数据。虽然它通常在像 JSTL 这样的标签库中使用,但它也可以在模板文本中独立使用。

I think it helps more if you see with your own eyes that it can actually be done entirely without scriptlets.

Here's a 1 on 1 rewrite with help of among others JSTL (just drop jstl-1.2.jar in /WEB-INF/lib) core and functions 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>
   
</div>

Here's a more optimized rewrite, note that I used c:set to "cache" expression results for reuse and that I use HTML <base> tag to avoid putting the context path in every link (just make all relative URL's in your webpage relative to it --without the leading slash!):

<%@ 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>

It can actually be optimized more if you collect all those "hardcoded" values like events and people and link texts in a Map in the application scope and use under each the JSTL <c:forEach> to display the tabs.

As to your actual question, you can disable scriptlets (and get runtime errors about using it) by adding the following entry in webapp's web.xml. It may help to spot overseen scriptlets.

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

To learn more about EL, check the Java EE tutorial part II chapter 5. Implicit EL objects, such as ${pageContext} are described here. To learn more about JSTL, check the Java EE tutorial part II chapter 7. Note that JSTL and EL are two separate things. JSTL is a standard taglib and EL just enables to access backend data programmatically. Although it is normally used in taglibs like JSTL, it can also be used standalone in template text.

浪推晚风 2024-08-27 13:30:53

顺便说一句,<%= request.getContextPath() %> 是一种可以接受的 scriptlet 使用方式吗?

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

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

但从根本上(如“将逻辑排除在模板之外”)我看不出

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

和之间有任何区别

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

As an aside, is <%= request.getContextPath() %> an acceptable use of scriptlets that isn't frowned on so much?

This may be an unpopular opinion, but if all you do are simple conditionals and text insertions, I cannot find much fault in the use of scriptlets. (Note the if)

I'd probably use JSTL and the expression language, but mostly because it can be less typing, and IDE support may be better (but a good JSP IDE can also find missing closing brackets and stuff like that).

But fundamentally (as in "keep logic out of templates") I fail to see any difference between

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

and

${fn:contains(pageContext.request.requestURI, '/events/') 
萤火眠眠 2024-08-27 13:30:53

Scriptlet 并不是世界上最糟糕的事情。一个重要的考虑因素是考虑谁将维护代码。如果网页设计人员没有太多 Java 经验,那么使用标签库可能会更好。然而,如果 Java 开发人员进行维护,那么使用 scriptlet 可能会更容易。

如果您最终使用标签库和 JSTL,那么您期望维护者也学习标签库并了解 JSTL。一些开发人员会对此感到满意,因为这是他们想要或已经拥有的技能,但对于一些只需要每隔几个月左右处理一次 JSP 的开发人员来说,使用用漂亮的语言编写的清晰编写的 scriptlet 可以减轻很多痛苦。 ,熟悉Java。

Scriptlets aren't the worst thing in the world. An important consideration is to think about who is going to be maintaining the code. If its web designers who don't have much Java experience, you are probably better off going with tag libraries. However, if Java developers are doing the maintainance, it may be easier on them to go with scriptlets.

If you end up using a tag library and JSTL, you are expecting the maintainer to also learn the tag library and know JSTL. Some developers will be fine with this as it is a skill they want or already have, but for some developers who only have to deal with JSPs every few months or so, it can be lot less painful to work with clearly written scriptlets written in nice, familiar Java.

紫瑟鸿黎 2024-08-27 13:30:53

这不是对你的问题的直接答案(已经有几个很好的答案,所以我不会尝试添加它),但你确实提到:

谁能懂一点java/jsp
经验请给我一些
有关如何更改此代码的指针
所以无论如何,它更像是“最佳实践”
这可能是?

在我看来,关于 JSP 的最佳实践是,它应该严格用作模板引擎,仅此而已(即,其中没有业务逻辑)。正如许多人指出的那样,使用 JSTL 绝对可以帮助您实现这一目标,但即使使用 JSTL,在 JSP 中也可以轻松完成很多工作。

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

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

  1. 视图无法通过直接更改模型来修改模型
    数据对象或通过调用方法
    导致副作用的模型。

    也就是说,模板可以访问数据
    来自模型和调用方法,但是
    这样的引用一定是副作用
    自由的。该规则部分出现
    因为数据引用必须是
    顺序不敏感。请参阅第 7.1 节。
  2. 视图无法对依赖数据执行计算
    值,因为计算可能
    未来会发生变化,他们应该
    被整齐地封装在模型中
    任何情况。例如,视图不能
    将图书销售价格计算为
    “价格*.90 美元”。独立于
    模型,视图无法制作
    关于数据含义的假设。
  3. 该视图无法比较相关数据值,但可以测试
    数据的属性,例如
    存在/不存在或长度
    多值数据值。测试如
    $bloodPressure<120 必须移至
    医生喜欢保留的模型
    降低最大收缩压
    在我们身上。视图中的表达式必须是
    替换为测试是否存在
    模拟布尔值的值,例如
    $bloodPressureOk!=null 模板输出
    可以以模型数据为条件,并且
    计算,条件只是
    必须在模型中计算。甚至
    产生负值的简单测试
    应在模型中计算红色;
    正确的抽象级别通常是
    与更高级别的事物结盟,例如
    “x 部门正在赔钱。”
  4. 视图无法做出数据类型假设。某些类型假设是
    当视图假设数据时显而易见
    例如,值是日期,但更多
    出现了微妙的类型假设:如果
    模板假设 $userID 是
    整数,程序员不能
    将此值更改为非数字
    在模型中不破坏
    模板。该规则禁止数组
    索引,例如 colorCode[$topic] 和
    $name[$ID] 视图还不能
    调用带有参数的方法,因为
    (静态或动态)有
    一种假定的参数类型,除非
    可以保证模型方法
    只是将它们视为对象。
    此外,图形设计师不是
    程序员;期待他们调用
    方法并知道要传递什么
    不现实。
  5. 模型中的数据不得包含显示或布局信息。
    该模型无法通过任何显示
    视图的信息伪装成
    数据值。这包括不通过
    要应用的模板的名称
    其他数据值。


顺便说一句,Terence 创建了自己的模板引擎,名为 String Template,据说它在执行这些规则方面做得非常好。我对此没有个人经验,但很想在我的下一个项目中检查一下。

This isn't a direct answer to your question (and there are already several good ones, so I won't try to add to it), but you did mention:

Can someone with a bit more java/jsp
experience please give me some
pointers as to how to change this code
so its more 'best practice', whatever
that may be
?

In my opinion, best practice, with regards to JSP, is that it should be used strictly as a templating engine, and no more (i.e., no business logic in there). Using JSTL, as many pointed out, definitely helps you get there, but even with JSTL, it's easy to do to much in a JSP.

I personally like to follow the rules laid out in Enforcing Strict Model-View Separation in Templating Engines by the Terence Parr when developing in JSP. The paper mentions the purpose of templating engines (separating model and view), and characteristics of a good templating engine. It takes a good look at JSP and points out ways it's not a good templating engine. Not surprisingly, JSP is basically too powerful and allows developers to do too much. I strongly recommend reading this paper, and it'll help you restrict yourself to the "good" parts of JSP.

If you read only one section in that paper, read chapter 7, which includes the following rules:

  1. the view cannot modify the model either by directly altering model
    data objects or by invoking methods on
    the model that cause side-effects.

    That is, a template can access data
    from the model and invoke methods, but
    such references must be side-effect
    free. This rule arises partially
    because data references must be
    order-insensitive. See Section 7.1.
  2. the view cannot perform computations upon dependent data
    values
    because the computations may
    change in the future and they should
    be neatly encapsulated in the model in
    any case. For example, the view cannot
    compute book sale prices as
    “$price*.90”. To be independent of the
    model, the view cannot make
    assumptions about the meaning of data.
  3. the view cannot compare dependent data values, but can test the
    properties of data such as
    presence/absence or length of a
    multi-valued data value. Tests like
    $bloodPressure<120 must be moved to
    the model as doctors like to keep
    reduc- ing the max systolic pressure
    on us. Expressions in the view must be
    replaced with a test for presence of a
    value simulat- ing a boolean such as
    $bloodPressureOk!=null Template output
    can be conditional on model data and
    com- putations, the conditional just
    has to be computed in the model. Even
    simple tests that make negative values
    red should be computed in the model;
    the right level of abstraction is usu-
    ally something higher level such as
    “department x is losing money.”
  4. the view cannot make data type assumptions. Some type assumptions are
    obvious when the view assumes a data
    value is a date, for example, but more
    subtle type assumptions ap- pear: If a
    template assumes $userID is an
    integer, the pro- grammer cannot
    change this value to be a non-numeric
    in the model without breaking the
    template. This rule forbids array
    indexing such as colorCode[$topic] and
    $name[$ID] The view further cannot
    call methods with arguments be- cause
    (statically or dynamically) there is
    an assumed argu- ment type, unless one
    could guarantee the model method
    merely treated them as objects.
    Besides graphics designers are not
    programmers; expecting them to invoke
    methods and know what to pass is
    unrealistic.
  5. data from the model must not contain display or layout information.
    The model cannot pass any display
    informa- tion to the view disguised as
    data values. This includes not passing
    the name of a template to apply to
    other data values.

Incidentally, Terence has created his own templating engine called String Template which supposedly does a really good job of enforcing these rules. I have no personal experience with it, but would love to check it out on my next project.

月亮邮递员 2024-08-27 13:30:53

您可能想从使用标签库开始。您可以使用标准标记库 JSTL 来执行您需要执行的大多数常见操作需要 scriptlet。还有许多其他更丰富的标签库可以在 struts2 框架或 apache 中使用。

例如

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

将替换您的 if 语句。

You may want to start by using tag libraries. You can use the standard tag library JSTL to do most of the common things that you need scriplets for. There are many other richer tag libraries that are used like in the struts2 framework or from apache.

e.g.

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

would replace your if statements.

黑凤梨 2024-08-27 13:30:53

scriptlet 的首选替代方案是 JSTL 表达式语言; 这里有一个很好的概述。您需要像这样添加 taglib:

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

例如,JSTL 提供了一堆隐式对象,可以为您提供所需的内容;你想要的是pageContext.request

因此,您可以将 <%request.getRequestURI%> 替换为 ${pageContext.request.requestURI}

您可以使用 标签执行条件语句。

The preferred alternative to scriptlets is the JSTL expression language; here's a good overview. You'll need to add the taglib like so:

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

As an example, JSTL provides a bunch of implicit objects that give you the stuff you need; the one you want is pageContext.request.

So you can replace <%request.getRequestURI%> with ${pageContext.request.requestURI}.

You can do conditionals using <c:if> tags.

孤独岁月 2024-08-27 13:30:53

您需要使用一些网络框架。或者至少有一些方便的标签库。或者像 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 网络工具包

You'll need to use some web framework. Or at least some convenient taglib. Or a templating enginge like FreeMarker.

Ad frameworks:

If you like JSP way of coding, then I'd suggest 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>

Then there's component-oriented JSF.

If you like OOP and coding everything in Java, try Apache Wicket (my favorite) or Google Web Toolkit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文