Java 如何避免在我的 JSP 页面中使用 scriptlet?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2188706/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to avoid using scriptlets in my JSP page?
提问by Chris
I've been told that the use of scriptlets (<%= ... %>) in my JSP pages isn't such a great idea.
有人告诉我,在我的 JSP 页面中使用 scriptlet (<%= ... %>) 并不是一个好主意。
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?
有更多 java/jsp 经验的人可以给我一些关于如何更改此代码的指示,使其成为更多的“最佳实践”,无论是什么?
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.
这个 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>
Thanks all
谢谢大家
采纳答案by BalusC
I think it helps more if you see with your own eyes that it can actually be done entirely withoutscriptlets.
我认为如果你亲眼看到它实际上可以完全没有脚本来完成,它会更有帮助。
Here's a 1 on 1 rewrite with help of among others JSTL(just drop jstl-1.2.jar
in /WEB-INF/lib
) coreand functionstaglib:
这里有一个1对1重写与在其他的帮助JSTL(刚落jstl-1.2.jar
于/WEB-INF/lib
)核心和功能的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!):
这是一个更优化的重写,请注意,我曾经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>
</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.
如果您在应用程序范围内收集所有那些“硬编码”值(如events
和people
和链接文本)Map
并在每个 JSTL 下使用<c:forEach>
以显示选项卡,则实际上可以对其进行更多优化。
As to your actualquestion, you can disablescriptlets (and get runtime errors about using it) by adding the following entry in webapp's web.xml
. It may help to spot overseen scriptlets.
至于你的实际问题,你可以禁用脚本小程序(并获得有关使用它的运行时错误),通过添加web应用程序的以下条目web.xml
。它可能有助于发现受监督的 scriptlet。
<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 tagliband 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.
要了解有关 EL 的更多信息,请查看Java EE 教程第二部分第 5 章。隐式 EL 对象,例如这里${pageContext}
描述的。要了解有关 JSTL 的更多信息,请查看Java EE 教程第二部分第 7 章。请注意,JSTL 和 EL 是两个独立的东西。JSTL 是一个标准的 taglib,EL 只允许以编程方式访问后端数据。虽然它通常用于像 JSTL 这样的标签库中,但它也可以在模板文本中独立使用。
回答by Ondra ?i?ka
You'll need to use some web framework. Or at least some convenient taglib. Or a templating enginge like FreeMarker.
你需要使用一些网络框架。或者至少是一些方便的 taglib。或者像FreeMarker这样的模板引擎。
Ad frameworks:
广告框架:
If you like JSP way of coding, then I'd suggest Struts 2.
如果您喜欢 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>
Then there's component-oriented JSF.
然后是面向组件的JSF。
If you like OOP and coding everything in Java, try Apache Wicket(my favorite) or Google Web Toolkit.
如果您喜欢 OOP 并使用 Java 编写所有代码,请尝试Apache Wicket(我最喜欢的)或Google Web Toolkit。
回答by Vincent Ramdhanie
You may want to start by using tag libraries. You can use the standard tag library JSTLto 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.
您可能希望从使用标记库开始。您可以使用标准标记库JSTL来完成大多数需要脚本的常见事情。还有许多其他更丰富的标签库,如在 struts2 框架中或从 apache 中使用。
e.g.
例如
<c:if test="${your condition}">
Your Content
</c:if>
would replace your if statements.
将替换您的 if 语句。
回答by Jacob Mattison
The preferred alternative to scriptlets is the JSTL expression language; here's a good overview. You'll need to add the taglib like so:
scriptlet 的首选替代品是 JSTL 表达式语言;这是一个很好的概述。您需要像这样添加标签库:
<%@ 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
.
例如,JSTL 提供了一堆隐式对象,它们为您提供所需的东西;你想要的是pageContext.request
。
So you can replace <%request.getRequestURI%>
with ${pageContext.request.requestURI}
.
所以你可以<%request.getRequestURI%>
用${pageContext.request.requestURI}
.
You can do conditionals using <c:if>
tags.
您可以使用<c:if>
标签来执行条件。
回答by Thilo
As an aside, is
<%= request.getContextPath() %>
an acceptable use of scriptlets that isn't frowned on so much?
顺便说一句,是
<%= request.getContextPath() %>
小脚本的可接受使用未就这么多皱起了眉头?
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)
这可能是一个不受欢迎的意见,但如果你所做的只是简单的条件和文本插入,我在使用 scriptlet 时找不到太多错误。(注意如果)
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).
我可能会使用 JSTL 和表达式语言,但主要是因为它可以减少输入,并且 IDE 支持可能更好(但是一个好的 JSP IDE 也可以找到缺少的右括号之类的东西)。
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/')
回答by Hyman Leow
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?
有更多 java/jsp 经验的人可以给我一些关于如何更改此代码的指示,以便它更“最佳实践”,无论是什么?
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.
在我看来,关于 JSP 的最佳实践是,它应该严格用作模板引擎,而不是更多(即,其中没有业务逻辑)。正如许多人指出的那样,使用 JSTL 肯定可以帮助您实现目标,但即使使用 JSTL,在 JSP 中也很容易做很多事情。
I personally like to follow the rules laid out in Enforcing Strict Model-View Separation in Templating Enginesby 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.
在 JSP 中进行开发时,我个人喜欢遵循Terence Parr在模板引擎中执行严格的模型视图分离中规定的规则 。论文中提到了模板引擎的目的(分离模型和视图),以及一个好的模板引擎的特点。它仔细研究了 JSP 并指出它不是一个好的模板引擎。毫不奇怪,JSP 基本上太强大了,允许开发人员做太多事情。我强烈建议您阅读这篇论文,它将帮助您将自己限制在 JSP 的“好”部分。
If you read only one section in that paper, read chapter 7, which includes the following rules:
如果您只阅读了该论文的一个部分,请阅读第 7 章,其中包含以下规则:
- 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.
- the view cannot perform computations upon dependent data valuesbecause 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.
- 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.”
- 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.
- 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.
- 视图无法通过直接更改模型数据对象或通过调用模型上导致副作用的方法来修改模型。也就是说,模板可以从模型访问数据并调用方法,但此类引用必须没有副作用。出现此规则的部分原因是数据引用必须是顺序不敏感的。参见第 7.1 节。
- 视图无法根据相关数据值执行计算,因为计算可能会在未来发生变化,无论如何都应该将它们巧妙地封装在模型中。例如,该视图无法将图书销售价格计算为“$price*.90”。为了独立于模型,视图不能对数据的含义做出假设。
- 该视图无法比较相关数据值,但可以测试数据的属性,例如多值数据值的存在/不存在或长度。像 $bloodPressure<120 这样的测试必须移到模型中,因为医生喜欢不断降低我们的最大收缩压。视图中的表达式必须替换为模拟布尔值是否存在的测试,例如 $bloodPressureOk!=null 模板输出可以以模型数据和计算为条件,条件只需要在模型中计算. 即使是将负值变为红色的简单测试也应在模型中计算;正确的抽象级别通常是更高级别的内容,例如“部门 x 正在赔钱”。
- 视图不能做出数据类型假设。例如,当视图假定数据值是日期时,某些类型假定是显而易见的,但会出现更微妙的类型假定:如果模板假定 $userID 是整数,则程序员不能将此值更改为非- 模型中的数字而不破坏模板。此规则禁止数组索引,例如 colorCode[$topic] 和 $name[$ID] 视图进一步不能调用带参数的方法,因为(静态或动态)存在假定的参数类型,除非可以保证模型方法只是将它们视为对象。此外图形设计师不是程序员;期望他们调用方法并知道要传递什么是不现实的。
- 模型中的数据不得包含显示或布局信息。模型不能将任何显示信息传递给伪装成数据值的视图。这包括不传递模板名称以应用于其他数据值。
Incidentally, Terence has created his own templating engine called String Templatewhich 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.
顺便说一句,Terence 创建了他自己的模板引擎,称为String Template,据说它在执行这些规则方面做得非常好。我没有个人经验,但很想在我的下一个项目中查看它。
回答by Spike Williams
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.
Scriptlet 并不是世界上最糟糕的东西。一个重要的考虑是考虑谁将维护代码。如果它的 Web 设计人员没有太多 Java 经验,那么使用标签库可能会更好。但是,如果 Java 开发人员进行维护,他们可能更容易使用 scriptlet。
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.
如果您最终使用了标记库和 JSTL,那么您希望维护者也学习标记库并了解 JSTL。一些开发人员会接受这个,因为这是他们想要或已经拥有的技能,但对于一些只需要每隔几个月左右处理一次 JSP 的开发人员来说,使用用 nice 编写的清晰的脚本可以少很多痛苦。 ,熟悉的Java。