题
我是Java EE的新手,我知道以下三行类似
<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>
是一种旧学校编码的方式,在JSP版本2中,存在一种避免JSP文件中Java代码的方法。有人可以告诉我替代JSP 2行,该技术称为什么?
解决方案
指某东西的用途 脚本 (那些 <% %>
事物) JSP 自从出生以来,确实令人不安 taglibs (像 JSTL) 和 El (表达语言, , 那些 ${}
事物)早在2001年。
主要缺点 脚本 是:
- 可重复使用: 您无法重复使用脚本。
- 替代性: 您不能使脚本集抽象。
- oo-o-ability: 您不能使用继承/构图。
- 辩论性: 如果Scriptlet在中途抛出异常,那么您所得到的只是空白页。
- 可验证性: Scriptlet不是单位检验。
- 可维护性: 每萨尔多需要更多时间来维护混合/混乱/重复的代码逻辑。
太阳 甲骨文本身也建议 JSP编码约定 避免使用 脚本 每当(标签)类都可以使用相同的功能。以下是几个相关性的引用:
从JSP 1.2规范中,强烈建议您在Web应用程序中使用JSP标准标签库(JSTL)来帮助 减少对JSP脚本的需求 在您的页面中。通常,使用JSTL的页面通常更易于阅读和维护。
...
在可能的情况, 避免JSP脚本 每当标签库提供等效功能时。这使得页面更易于阅读和维护,有助于将业务逻辑与演示逻辑分开,并使您的页面易于演变为JSP 2.0风格的页面(JSP 2.0规范支持支持,但强调了脚本的使用)。
...
本着采用模型视图控制器(MVC)设计模式的精神,以减少业务逻辑中的演示层之间的耦合, JSP脚本不应使用 用于编写业务逻辑。相反,如有必要,使用JSP脚本将数据(也称为“值对象”)从处理客户的请求转换为适当的客户端就绪格式。即使那样,使用前控制器servlet或自定义标签也可以更好地完成。
如何更换 脚本 完全取决于代码/逻辑的唯一目的。此代码不仅仅是将其放置在一个全面的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. } }
映射在适当的
<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); } }
这样处理例外的方式更容易。在JSP渲染中未访问DB,但在显示JSP之前就远处访问了DB。每当DB访问引发异常时,您仍然可以更改响应。在上面的示例中,将显示默认错误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. } }
这样处理不同结果页面目的地的方式更容易:在发生错误的情况下,用验证错误重新播放表单(在此特定示例中,您可以使用它重新播放它
${message}
在 El),或仅在成功的情况下进入所需的目标页面。如果您想调用一些Java代码 控制 执行计划和/或请求的目的地和响应的目的地,然后实现 servlet 根据 MVC的前控制器图案. 。例如:
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); } }
或只是采用像MVC框架一样 JSF, 春季MVC, 便门, ,等等,以便您最终仅获得JSP/FACELETS页面和Javabean类而无需进行自定义servlet。
如果您想调用一些Java代码 控制流程 在JSP页面中,您需要抓住(现有的)流控制taglib 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>
使用XML风格的标签,非常适合所有HTML,代码比具有各种开放式和闭合括号的脚本脚本更好(因此可以维护更好)(并且可以维护更好)(“这个闭合支架属于哪里?”)。一个简单的辅助是配置您的Web应用程序,以便在 脚本 仍然通过将以下作品添加到
web.xml
:<jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <scripting-invalid>true</scripting-invalid> </jsp-property-group> </jsp-config>
在 面板, ,JSP的继任者,这是Java EE提供的MVC框架的一部分 JSF, ,已经 不是 可以使用 脚本. 。这样,您会自动被迫“正确的方式”做事。
如果您想调用一些Java代码 访问和显示 JSP页面中的“后端”数据,然后您需要使用EL(表达式语言),这些数据
${}
事物。例如,重新播放提交的输入值:<input type="text" name="foo" value="${param.foo}" />
这
${param.foo}
显示结果request.getParameter("foo")
.如果您想调用一些 效用 直接在JSP页面中的Java代码(通常
public static
方法),然后您需要将它们定义为EL函数。有一个标准 功能taglib 在JSTL中,但是 您也可以自己轻松创建功能. 。这是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)}" />
请注意,XSS敏感性与Java/jsp/jstl/el/whyth毫无意义,需要考虑此问题 每一个 您开发的Web应用程序。问题 脚本 是它没有提供内置预防措施,至少不使用标准Java API。 JSP的后继FACELET已经隐含了HTML逃脱,因此您不必担心Facelets中的XSS孔。
也可以看看:
其他提示
作为保障:禁用脚本
作为 另一个问题 正在讨论,您可以并且总是应该禁用您的脚本。 web.xml
Web应用程序描述符。
我总是会这样做,以防止任何开发人员添加脚本集,尤其是在您迟早会失去概述的较大公司中。这 web.xml
设置看起来像这样:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
JSTL 提供有条件,循环,集合,获取等标签。例如:
<c:if test="${someAttribute == 'something'}">
...
</c:if>
JSTL与请求属性一起使用 - 它们通常是由Servlet设置在请求中的 前锋 到JSP。
您可以将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>
还有基于组件的框架,例如 便门 这为您生成了很多HTML。最终进入HTML的标签非常基本,几乎没有逻辑混合在一起。结果几乎是像具有典型HTML元素的类似空的HTML页面。不利的一面是, 便门 在这些约束下,学习的API很难实现。
在MVC架构模式中,JSP表示视图层。将Java代码嵌入JSP被认为是一种不良习惯。您可以使用 JSTL, freemarker, 速度 以JSP为“模板引擎”。这些标签的数据提供商 取决于框架 您正在处理的。 Struts 2
和 webwork
作为MVC模式使用的实现 OGNL “将豆类属性暴露于JSP的非常有趣的技术”。
经验表明,JSP有一些缺点,其中一个很难避免将标记与实际代码混合。
如果可以的话,请考虑使用专门的技术来完成工作。在Java EE 6中,有JSF 2.0,它提供了许多不错的功能,包括粘合Java Bean和JSF页面,通过The JSF页面 #{bean.method(argument)}
方法。
如果您只想避免JSP中的Java编码的缺点,即使使用Scriplets也可以这样做。只需遵循一些纪律即可在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>
学习使用JSTL自定义和编写自己的标签
请注意El是 邪恶的 (运行时例外,重构)
检票口也可能是邪恶的(性能,小型应用程序辛劳或简单的视图层)
示例来自 Java2s,
必须将其添加到Web应用程序的Web.xml
<taglib>
<taglib-uri>/java2s</taglib-uri>
<taglib-location>/WEB-INF/java2s.tld</taglib-location>
</taglib>
创建文件: /web-inf /in /web-inf /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>
将以下代码编译到Web-Inf class 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;
}
}
启动服务器并在浏览器中加载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>
检票口也是将Java与HTML完全分开的替代方案,因此设计师和程序员可以在几乎没有理解的情况下共同努力并在不同的代码上合作。
看门。
您提出了一个很好的问题,尽管您得到了很好的答案,但我建议您摆脱JSP。它是过时的技术,最终将死亡。使用现代方法,例如模板引擎。您将在业务和演示层之间进行非常明确的分离,当然没有模板中的Java代码,因此您可以直接从Web演示编辑软件中生成模板,在大多数情况下,利用Wysiwyg。
当然,请远离过滤器以及前后处理,否则您可能会处理支持/调试困难,因为您始终不知道变量在哪里获取该值。
为了避免JSP文件中的Java代码,Java现在提供了标签库,例如JSTL也提出了JSF,您可以在其中以标签的形式编写所有编程结构
无论您尝试避免多少,当您与其他开发人员合作时,其中一些仍然会喜欢Scriptlet,然后将邪恶代码插入项目中。因此,如果您真的想减少脚本码,则在第一个标志上设置项目非常重要。有几种技术可以克服这一点(包括其他提到的几个框架)。但是,如果您喜欢纯JSP方式,请使用JSTL标签文件。关于这一点的好处是,您还可以为项目设置主页,因此其他页面可以继承主页
在您的Web-Inf/标签下使用以下内容创建一个名为base.tag的主页面
<%@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页面上,我创建了一个名为“标题”的片段,因此在“子”页面中,我可以将更多代码插入主页的这个位置。另外,标签 <jsp:doBody/>
将被儿童页面的内容替换
在您的WebContent文件夹中创建子页面(child.jsp):
<%@ 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/>
在您的主页上。您的孩子页面也可以包括任何标签lib,您可以像其他提到的其他标签一样使用它。但是,如果您在此处使用任何scriptlet代码(<%= request.getParameter("name") %>
...)并尝试运行此页面,您将获得一个 JasperException because Scripting elements ( <%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) are disallowed here
. 。因此,其他人无法将邪恶代码包括在JSP文件中
从您的控制器拨打此页面:
您可以从控制器轻松地调用child.jsp文件。这也适用于Struts框架
采用 JSTL Tag libraries
在JSP中,这将是完美的。
只需使用JSTL标签和EL表达式即可。
如果有人真的反对以比一种语言更多的语言编程, ,我建议GWT,从理论上讲,您可以避免所有JS和HTML元素,因为Google Toolkit将所有客户端和共享代码转换为JS,您对它们不会有问题,因此您在没有任何其他语言的情况下都有网络服务。即使您也可以从某个地方使用一些默认的CSS,因为它由扩展名(SmartGWT或Vaadin)提供。您不需要学习数十个注释。
当然,如果需要的话,您可以将自己砍成代码的深处并注入JS并丰富您的HTML页面,但是如果需要,您确实可以避免使用它,结果将是在任何其他框架中写的,结果将是好的。我说值得一试,基本的GWT有充分的文献记录。
当然,许多其他程序员在此描述或推荐了其他一些解决方案。 GWT适合那些真的不想处理网络部分或最小化它的人。
来自Python世界的一个整洁的想法是 模板属性语言; TAL是由Zope(因此又名“ Zope Page模板”,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>
该代码看起来像普通的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>
如果可以使用内容的翻译,则使用它们。
我不太了解 Java实施, , 尽管。
在JSP中使用Scriptlet并不是一个好习惯。
相反,您可以使用:
- JSTL标签
- El表达
- 自定义标签 - 您可以定义自己的标签要使用。
请参阅:
当然,更换 <%! counter++; %>
通过事件生产者 - 消费者体系结构,该体系结构已通知业务层有关增加计数器的需求,它做出了相应的反应,并通知了演示者,以便他们更新视图。涉及许多数据库交易,因为将来我们将需要了解计数器的新价值和旧价值,后者已将其递增以及目的是什么。显然涉及序列化,因为这些层完全被解耦。您将能够通过RMI,IIOP,肥皂来增加计数器。但是,仅需要HTML,您不实施它,因为这是一个平凡的情况。您的新目标是在新的闪亮E7,64GB RAM服务器上达到250次增量。
我已经有20多年的编程,大多数项目都在六重奏之前失败:可重复使用性替换性OO可辩论性可可可可维护性。其他仅关心功能的人经营的项目非常成功。同样,在项目中太早实现的硬对象结构使代码无法适应规格的急剧变化(又称敏捷)。
因此,我认为是拖延项目早期或不具体要求的“层”或冗余数据结构的活动。
从技术上讲,JSP都在运行时转换为servlet. 。 JSP最初是为了遵循MVC模式的将业务逻辑和设计逻辑解耦的目的而创建的。因此,从技术上讲,JSP是运行时的所有Java代码。但是为了回答这个问题,标签库通常用于将逻辑(删除Java代码)应用于JSP页面。
如果我们在Java Web应用程序中使用以下内容,则可以从JSP的前景中消除Java代码。
将MVC架构用于Web应用程序
使用JSP标签
一种。标准标签
b。自定义标签
表达语言
如何避免JSP文件中的Java代码?
您可以使用标签标签 JSTL 除了表达语言(El)。但是EL与JSP不能很好地工作。因此,最好完全放下JSP并使用 面板.
面板 是专为设计的第一个非JSP页面声明语言 JSF(Java服务器面) 与JSP相比,这为JSF开发人员提供了更简单,更强大的编程模型。它解决了Web应用程序开发的JSP中发生不同的问题。
使用Scriptlet是一种非常古老的方式,不建议使用。如果您想直接在JSP页面中输出某些内容,则只需使用 表达语言(EL) 随着 JSTL .
还有其他选项,例如使用模板引擎,例如速度,自由状标志物,胸腺胸膜等,但是在大多数时候将Plain JSP与EL和JSTL一起使用我的目的,对于初学者来说,这也是最简单的。
另外,请注意,在视图层中进行业务逻辑不是最好的做法,而是在服务层中执行业务逻辑,并通过控制器将输出结果传递给视图。
我的朋友不再使用它,我的建议是将服务器从服务器中解脱出视图(CSS,HTML,JavaScript等)。
就我而言,我可以使用Angular来处理视图,并使用REST服务从服务器带来任何数据。
相信我,这将改变您的设计方式
使用主链,像JavaScript类似于UI设计的角链,并使用REST API获取数据。这将完全从UI中删除Java依赖性。
JSP 2.0具有称为的功能 “标签文件”, ,您可以编写没有外部的标签 java
代码和 tld
. 。您需要创建一个 .tag
归档并将其放入 WEB-INF\tags
您甚至可以创建一个目录结构来打包标签。
例如:
/WEB-INF/tags/html/label.tag
<%@tag description="Rensders a label with required css class" pageEncoding="UTF-8"%>
<%@attribute name="name" required="true" description="The label"%>
<label class="control-label control-default" id="${name}Label">${name}</label>
使用它
<%@ taglib prefix="h" tagdir="/WEB-INF/tags/html"%>
<h:label name="customer name" />
另外,您可以轻松阅读标签主体
/WEB-INF/tags/html/bold.tag
<%@tag description="Bold tag" pageEncoding="UTF-8"%>
<b>
<jsp:doBody/>
</b>
用它
<%@ taglib prefix="h" tagdir="/WEB-INF/tags/bold"%>
<h:bold>Make me bold</h:bold>
样本非常简单,但是您可以在这里执行许多复杂的任务。请考虑您可以使用其他标签(例如: JSTL
具有控制标签 if/forEcah/chosen
文字操纵喜欢 format/contains/uppercase
甚至SQL标签 select/update
),通过所有类似参数 Hashmap
, , 使用权 session
, request
, ,...在您的标签文件中。
标签文件 非常简单地开发,因为您不需要在更改服务器时重新启动服务器,例如JSP文件。这使它们易于开发。
即使您使用具有很多好标签的Struts 2之类的框架,您可能会发现拥有自己的标签可以大大减少代码。您可以将标签参数传递给支撑杆,然后将其自定义标签。
您不仅可以使用标签来避免使用Java,还可以最大程度地减少HTML代码。我自己尝试查看HTML代码并在我的页面中启动代码重复时,就会很快构建标签。
(即使您最终在JSP代码中使用Java,我希望不要,您可以将该代码封装在标签中)
正如许多答案所说,使用JSTL或创建自己的自定义标签。 这里 是关于创建自定义标签的很好的解释
- 在您的servlet类中制作您的价值观和参数
- 使用JSTL/TAGLIB在JSP中获取这些值和参数
这种方法的好处是您的代码也像html一样!
通过将JSTL标签与EL表达式一起使用,您可以避免。将以下内容放入您的JSP页面:
<%@ 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" %>