chm*_*ers 1649 java jsp scriptlet
我是Java EE的新手,我知道类似以下三行
<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>
Run Code Online (Sandbox Code Playgroud)
是一种旧式的编码方式,在JSP版本2中,存在一种避免JSP文件中的Java代码的方法.有人可以告诉我替代的JSP 2行,以及这种技术的名称是什么?
Bal*_*usC 1947
使用小脚本(那些<% %>
在东西)JSP确实是高度自诞生气馁标签库(如JSTL)和EL(表达式语言,那些${}
东西),早在2001年.
scriptlet的主要缺点是:
Sun Oracle本身也建议在JSP编码约定中避免在(标记)类可能的情况下使用scriptlet.以下是几个相关的引用:
从JSP 1.2规范,强烈建议JSP标准标签库(JSTL)在Web应用程序中使用,以帮助减少对JSP小脚本需要在你的页面.通常,使用JSTL的页面更易于阅读和维护.
...
尽可能在标记库提供等效功能时避免使用JSP scriptlet.这使页面更容易阅读和维护,有助于业务逻辑从表示逻辑分离,将使您的网页更容易演变成JSP 2.0风格的页面(JSP 2.0规范支持,但去强调使用脚本小程序).
...
本着采用模型 - 视图 - 控制器(MVC)设计模式以减少表示层与业务逻辑之间的耦合的精神,JSP scriptlet不应用于编写业务逻辑.相反,如果需要,可以使用JSP scriptlet将从处理客户端请求返回的数据(也称为"值对象")转换为适当的客户端就绪格式.即使这样,使用前端控制器servlet或自定义标签也可以做得更好.
如何完全替换scriptlet取决于代码/逻辑的唯一目的.这些代码通常被置于一个完整的Java类中:
如果要在每个请求上调用相同的 Java代码,不管请求的页面是否少于或多,例如检查用户是否已登录,则实现过滤器并在方法中相应地编写代码.例如:doFilter()
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
} else {
chain.doFilter(request, response); // Logged in, just continue request.
}
}
Run Code Online (Sandbox Code Playgroud)
当映射到适当的<url-pattern>
覆盖JSP页面时,那么你不需要在整个JSP页面中复制相同的代码片段.
如果要调用某些Java代码来预处理请求,例如,从数据库预加载某些列表以显示在某个表中,必要时根据某些查询参数,然后实现servlet并在doGet()
方法中相应地编写代码.例如:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<Product> products = productService.list(); // Obtain all products.
request.setAttribute("products", products); // Store products in request scope.
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
} catch (SQLException e) {
throw new ServletException("Retrieving products failed!", e);
}
}
Run Code Online (Sandbox Code Playgroud)
这种处理异常的方式更容易.在JSP渲染过程中不会访问DB,但是在JSP显示之前.每当数据库访问引发异常时,您仍然可以更改响应.在上面的示例中,将显示默认错误500页面,您可以通过输入<error-page>
进行自定义web.xml
.
如果要调用某些Java代码来处理请求,例如处理表单提交,则实现servlet并在doPost()
方法中相应地编写代码.例如:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
response.sendRedirect("home"); // Redirect to home page.
} else {
request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
}
}
Run Code Online (Sandbox Code Playgroud)
这样处理不同的结果页面目标更容易:在出现错误的情况下重新显示带有验证错误的表单(在此特定示例中,您可以${message}
在EL中重新显示它),或者只是在成功的情况下转到所需的目标页面.
如果要调用某些Java代码来控制请求和响应的执行计划和/或目标,则根据MVC的前端控制器模式实现servlet.例如:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
} else {
response.sendRedirect(view);
}
} catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
Run Code Online (Sandbox Code Playgroud)
或者只是采用一个MVC框架,如JSF,Spring MVC,Wicket等,这样你最终只需要一个JSP/Facelets页面和一个JavaBean类,而不需要自定义的servlet.
如果要调用某些Java代码来控制 JSP页面内的流,那么您需要获取(现有的)流控制标记库,如JSTL核心.例如List<Product>
,在表格中显示:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.name}</td>
<td>${product.description}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</table>
Run Code Online (Sandbox Code Playgroud)
使用XML样式的标签非常适合所有HTML,代码比具有各种打开和关闭括号的一堆scriptlet更好的可读性(因此更易于维护)("这个闭合括号属于哪个?").一个简单的帮助是配置您的Web应用程序,以便在仍然使用scriptlet时抛出异常,方法是将以下部分添加到web.xml
:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
Run Code Online (Sandbox Code Playgroud)
在Facelets的,JSP的继任者,这是Java EE提供的MVC框架的一部分JSF,它已经不能够使用小脚本.这样你就会被迫以"正确的方式"做事.
如果要调用某些Java代码来访问和显示 JSP页面中的"后端"数据,那么您需要使用EL(表达式语言)这些${}
东西.例如,重新显示提交的输入值:
<input type="text" name="foo" value="${param.foo}" />
Run Code Online (Sandbox Code Playgroud)
该${param.foo}
显示器的结果request.getParameter("foo")
.
如果要直接在JSP页面中调用某些实用程序 Java代码(通常是public static
方法),则需要将它们定义为EL函数.JSTL中有一个标准函数taglib,但您也可以自己轻松创建函数.以下是JSTL如何fn:escapeXml
有效防止XSS 攻击的示例.
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
Run Code Online (Sandbox Code Playgroud)
请注意,XSS灵敏度绝不与Java/JSP/JSTL/EL /无关,在您开发的每个 Web应用程序中都需要考虑此问题.scriptlet的问题在于它无法提供内置预防,至少不使用标准Java API.JSP的后继者Facelets已经隐式HTML转义,因此您不必担心Facelets中的XSS漏洞.
Ste*_*ers 223
作为安全措施:禁用Scriptlets for Good
正如另一个问题所讨论的那样,您可以并且始终应该在web.xml
Web应用程序描述符中禁用scriptlet .
我总是这样做是为了防止任何开发人员添加scriptlet,特别是在大型公司中,您迟早会丢失概述.该web.xml
设置是这样的:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
Run Code Online (Sandbox Code Playgroud)
Boz*_*zho 107
JSTL为条件,循环,集合,获取等提供标签.例如:
<c:if test="${someAttribute == 'something'}">
...
</c:if>
Run Code Online (Sandbox Code Playgroud)
JSTL使用请求属性 - 它们通常由Servlet设置在请求中,Servlet 转发到JSP.
tzi*_*zim 60
我不确定我是否正确.
你应该阅读一些关于MVC的内容.Spring MVC和Struts 2是两种最常见的解决方案.
Lam*_*bda 54
您可以将JSTL标记与EL表达式一起使用,以避免混合使用Java和HTML代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
<head>
</head>
<body>
<c:out value="${x + 1}" />
<c:out value="${param.name}" />
// and so on
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
小智 34
还有基于组件的框架,如Wicket,可以为您生成大量的HTML.最终在HTML中的标签非常基本,并且几乎没有混合的逻辑.结果几乎是空的HTML页面,具有典型的HTML元素.缺点是Wicket API 中有很多组件需要学习,有些事情在这些限制条件下很难实现.
小智 32
在MVC架构模式中,JSP表示View层.在JSP中嵌入Java代码被认为是一种不好的做法.您可以将JSTL,freeMarker,velocity用JSP作为"模板引擎".这些标记的数据提供者取决于您正在处理的框架.Struts 2
并且webwork
作为MVC Pattern的实现使用OGNL "非常有趣的技术将Beans Properties暴露给JSP".
Tho*_*sen 27
经验表明,JSP有一些缺点,其中一个难以避免将标记与实际代码混合在一起.
如果可以的话,请考虑使用专门的技术来完成您的工作.在Java EE 6有JSF 2.0,它提供了很多不错的功能,包括通过JSF页面粘合的Java bean在一起#{bean.method(argument)}
的方法.
tom*_*asb 26
学习使用JSTL自定义和编写自己的标签
请注意,EL是EviL(运行时异常,重构)
Wicket也可能是邪恶的(性能,对于小应用程序或简单视图层来说很难)
来自java2s的示例,
必须将其添加到Web应用程序的web.xml中
<taglib>
<taglib-uri>/java2s</taglib-uri>
<taglib-location>/WEB-INF/java2s.tld</taglib-location>
</taglib>
Run Code Online (Sandbox Code Playgroud)
在/ WEB-INF /中创建File:java2s.tld
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- a tab library descriptor -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>Java2s Simple Tags</short-name>
<!-- this tag manipulates its body content by converting it to upper case
-->
<tag>
<name>bodyContentTag</name>
<tag-class>com.java2s.BodyContentTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>howMany</name>
</attribute>
</tag>
</taglib>
Run Code Online (Sandbox Code Playgroud)
将以下代码编译为WEB-INF\classes\com\java2s
package com.java2s;
import java.io.IOException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
public class BodyContentTag extends BodyTagSupport{
private int iterations, howMany;
public void setHowMany(int i){
this.howMany = i;
}
public void setBodyContent(BodyContent bc){
super.setBodyContent(bc);
System.out.println("BodyContent = '" + bc.getString() + "'");
}
public int doAfterBody(){
try{
BodyContent bodyContent = super.getBodyContent();
String bodyString = bodyContent.getString();
JspWriter out = bodyContent.getEnclosingWriter();
if ( iterations % 2 == 0 )
out.print(bodyString.toLowerCase());
else
out.print(bodyString.toUpperCase());
iterations++;
bodyContent.clear(); // empty buffer for next evaluation
}
catch (IOException e) {
System.out.println("Error in BodyContentTag.doAfterBody()" + e.getMessage());
e.printStackTrace();
} // end of catch
int retValue = SKIP_BODY;
if ( iterations < howMany )
retValue = EVAL_BODY_AGAIN;
return retValue;
}
}
Run Code Online (Sandbox Code Playgroud)
启动服务器并在浏览器中加载bodyContent.jsp
<%@ taglib uri="/java2s" prefix="java2s" %>
<html>
<head>
<title>A custom tag: body content</title>
</head>
<body>
This page uses a custom tag manipulates its body content.Here is its output:
<ol>
<java2s:bodyContentTag howMany="3">
<li>java2s.com</li>
</java2s:bodyContentTag>
</ol>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
dip*_*ipu 26
如果您只是想避免JSP中Java编码的缺点,即使使用scriplet也可以这样做.只需遵循一些规则,在JSP中使用最少的Java,而在JSP页面中几乎没有计算和逻辑.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%//instantiate a JSP controller
MyController clr = new MyController(request, response);
//process action if any
clr.process(request);
//process page forwaring if necessary
//do all variable assignment here
String showMe = clr.getShowMe();%>
<html>
<head>
</head>
<body>
<form name="frm1">
<p><%= showMe %>
<p><% for(String str : clr.listOfStrings()) { %>
<p><%= str %><% } %>
// and so on
</form>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
Dmi*_*y R 23
你提出了一个很好的问题,虽然你得到了很好的答案,但我建议你摆脱JSP.它是过时的技术,最终会死亡.使用现代方法,如模板引擎.您将非常清楚地分离业务层和表示层,当然模板中没有Java代码,因此您可以直接从Web演示文稿编辑软件生成模板,在大多数情况下可以利用WYSIWYG.
当然,远离过滤器以及前后处理,否则您可能会遇到支持/调试困难,因为您始终不知道变量获取值的位置.
Tha*_*ran 21
无论你试图避免多少,当你与其他开发人员合作时,他们中的一些人仍然会喜欢scriptlet,然后将邪恶的代码插入到项目中.因此,如果您真的想减少scriptlet代码,那么在第一个符号设置项目非常重要.有几种技术可以克服这个问题(包括其他提到的几个框架).但是,如果您更喜欢纯JSP方式,那么请使用JSTL标记文件.关于这一点的好处是您还可以为项目设置母版页,因此其他页面可以继承母版页
在WEB-INF/tags下创建一个名为base.tag的母版页,其中包含以下内容
Run Code Online (Sandbox Code Playgroud)<%@tag description="Overall Page template" pageEncoding="UTF-8"%> <%@attribute name="title" fragment="true" %> <html> <head> <title> <jsp:invoke fragment="title"></jsp:invoke> </title> </head> <body> <div id="page-header"> .... </div> <div id="page-body"> <jsp:doBody/> </div> <div id="page-footer"> ..... </div> </body> </html>
在这个mater页面上,我创建了一个名为"title"的片段,这样在子页面中,我可以在母版页的这个位置插入更多代码.此外,标记<jsp:doBody/>
将被子页面的内容替换
在WebContent文件夹中创建子页面(child.jsp):
Run Code Online (Sandbox Code Playgroud)<%@ taglib prefix="t" tagdir="/WEB-INF/tags" %> <t:base> <jsp:attribute name="title"> <bean:message key="hello.world" /> </jsp:attribute> <jsp:body> [Put your content of the child here] </jsp:body> </t:base>
<t:base>
用于指定要使用的母版页(此时为base.tag).<jsp:body>
此处标记内的所有内容都将替换<jsp:doBody/>
您母版页上的内容.您的子页面还可以包含任何标记库,您可以像通常提到的那样使用它.但是,如果您在此处使用任何scriptlet代码(<%= request.getParameter("name") %>
...)并尝试运行此页面,您将获得一个JasperException because Scripting elements ( <%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) are disallowed here
.因此,其他人无法将恶意代码包含在jsp文件中
从您的控制器调用此页面:
您可以从控制器轻松调用child.jsp文件.这也适用于struts框架
CsB*_*ary 17
如果有人真的反对使用多种语言编程,我建议GWT,理论上你可以避免所有的JS和HTML元素,因为Google Toolkit将所有客户端和共享代码转换为JS,你不会有问题,所以你有一个没有任何其他语言编码的网络服务.即使你可以使用某些默认的CSS,因为它是由扩展(smartGWT或Vaadin)提供的.您不需要学习几十个注释.
当然,如果你愿意,你可以深入了解代码的深度并注入JS并丰富你的HTML页面,但实际上如果你愿意,你可以避免使用它,结果会很好,因为它是在任何其他框架中编写的.我说值得一试,基本的GWT已经有了很好的记录.
当然,许多其他程序员在此描述或推荐了其他几种解决方案.GWT适用于那些真正不想处理Web部件或将其最小化的人.
Tob*_*ias 16
来自Python世界的一个巧妙的想法是模板属性语言 ; TAL由Zope引入(因此也称为"Zope页面模板",ZPT)并且是标准的,并且还实现了PHP,XSLT和Java(我使用了Python/Zope和PHP版本).在这类模板语言中,上面的一个示例可能如下所示:
<table>
<tr tal:repeat="product products">
<td tal:content="product/name">Example product</td>
<td tal:content="product/description">A nice description</td>
<td tal:content="product/price">1.23</td>
</tr>
</table>
Run Code Online (Sandbox Code Playgroud)
代码看起来像普通的HTML(或XHTML)以及XML命名空间中的一些特殊属性; 它可以通过浏览器查看,并由设计师安全地进行调整.支持宏和i18n:
<h1 i18n:translate="">Our special offers</h1>
<table>
<tr tal:repeat="product products">
<td tal:content="product/name"
i18n:translate="">Example product</td>
<td tal:content="product/description"
i18n:translate="">A nice description</td>
<td tal:content="product/price">1.23</td>
</tr>
</table>
Run Code Online (Sandbox Code Playgroud)
如果内容的翻译可用,则使用它们.
不过,我对Java实现不太了解.
小智 14
当然,替换<%! counter++; %>
为事件生产者 - 消费者体系结构,其中业务层被通知有关递增计数器的需要,它会相应地做出反应,并通知演示者以便他们更新视图.涉及到许多数据库事务,因为将来我们需要知道计数器的新旧值,它已经增加了它并且考虑了什么目的.显然涉及序列化,因为这些层完全是分离的.您将能够通过RMI,IIOP,SOAP递增计数器.但是只需要HTML,这是你没有实现的,因为它是如此平凡的情况.您的新目标是在新的闪亮E7,64GB RAM服务器上每秒达到250个增量.
我有超过20年的编程经验,大多数项目在六重奏之前都失败了:可重用性可替换性OO能力可调试性可测性甚至还需要可维护性.由仅关心功能的人经营的其他项目非常成功.此外,在项目中过早实施的僵硬对象结构使得代码无法适应规范中的剧烈变化(也称为敏捷).
因此,我认为拖延是在项目早期或非特别需要时定义"层"或冗余数据结构的活动.
mel*_*ngs 11
从技术上讲,JSP在运行时都会转换为Servlet.JSP最初是为了按照MVC模式解耦业务逻辑和设计逻辑而创建的.所以JSP在运行时在技术上都是java代码.但回答这个问题,Tag Libraries通常用于将逻辑(删除Java代码)应用于JSP页面.
如果我们在java Web应用程序中使用以下内容,则可以从JSP的前台中删除java代码.
将MVC架构用于Web应用程序
使用JSP标记
一个.标准标签
湾 自定义标签
表达语言
使用 Scriptlet 是一种非常古老的方法,不推荐。如果您想在 JSP 页面中直接输出某些内容,只需使用表达式语言 (EL) 和JSTL即可。
还有其他选择,例如使用模板引擎,如 Velocity、Freemarker、Thymeleaf 等。但是使用带有 EL 和 JSTL 的普通 JSP 在大多数情况下都能满足我的目的,而且对于初学者来说它似乎也是最简单的。
另外,请注意,在视图层中执行业务逻辑并不是最佳实践。您应该在服务层执行业务逻辑,并通过控制器将输出结果传递到视图。
归档时间: |
|
查看次数: |
277088 次 |
最近记录: |