我知道类似以下三行

<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>

是一种老式的编码方式,在JSP版本2中存在一种避免JSP文件中出现Java代码的方法。什么是可选的JSP2行,这种技术叫什么?


当前回答

在JSP中使用JSTL标记库。这将非常有效。

其他回答

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>

代码看起来像普通的HTML(或XHTML)加上XML命名空间中的一些特殊属性;它可以用浏览器查看,也可以由设计师安全地调整。

支持宏以及国际化和本地化:

<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实现不太了解。

自2001年taglibs(如JSTL)和EL(表达式语言,那些${}的东西)诞生以来,在JSP中使用scriptlets(那些<%%>的东西)确实非常不受欢迎。

scriptlets的主要缺点是:

可重用性:不能重用scriptlets。可替换性:不能使scriptlets抽象。OO能力:你不能利用继承/组合。可调试性:如果scriptlet中途抛出异常,则只会得到一个空白页面。可测试性:scriptlets不是可单元测试的。可维护性:每个saldo需要更多的时间来维护混合/杂乱/重复的代码逻辑。

Sun Oracle本身也建议在JSP编码约定中避免在(标记)类可能具有相同功能时使用scriptlet。以下是几个相关的例子:

根据JSP1.2规范,强烈建议在web应用程序中使用JSP标准标记库(JSTL),以帮助减少页面中对JSP脚本的需求。通常,使用JSTL的页面更容易阅读和维护。...如果可能,只要标记库提供了等效的功能,就避免使用JSP脚本。这使得页面更易于阅读和维护,有助于将业务逻辑与表示逻辑分开,并将使您的页面更容易演变为JSP 2.0风格的页面(JSP 2.0规范支持但不强调scriptlets的使用)。...本着采用模型-视图-控制器(MVC)设计模式来减少表示层与业务逻辑之间的耦合的精神,JSP脚本不应用于编写业务逻辑。相反,如果需要,可以使用JSP脚本将处理客户端请求返回的数据(也称为“值对象”)转换为适合客户端的格式。即使这样,使用前端控制器servlet或自定义标记也会更好。


如何替换scriptlet完全取决于代码/逻辑的唯一目的。这段代码通常被放在一个完整的Java类中:

如果您希望在每个请求中调用相同的Java代码,无论请求的页面是多少,例如,检查用户是否登录,那么实现一个过滤器并在doFilter()方法中相应地编写代码。例如。:public void doFilter(ServletRequest请求、ServletResponse响应、FilterChain链)抛出ServletException、IOException{if(((HttpServletRequest)请求).getSession().getAttribute(“user”)==null){((HttpServletResponse)响应).sendRedirect(“登录”);//未登录,重定向到登录页面。}其他{chain.doFilter(请求,响应);//已登录,请继续请求。}}当映射到覆盖感兴趣的JSP页面的适当的<url模式>时,就不需要复制粘贴整个JSP页面的同一段代码。如果您想调用一些Java代码来处理GET请求,例如,从数据库中预加载一些列表以显示在某个表中,如果需要,可以基于一些查询参数,然后实现一个servlet并在doGet()方法中相应地编写代码。例如。:protected void doGet(HttpServletRequest请求,HttpServletResponse响应)throws ServletException,IOException{尝试{List<Product>products=productService.List();//获取所有产品。request.setAttribute(“products”,products);//将产品存储在请求范围内。request.getRequestDispatcher(“/WEB-INF/products.jsp”).forward(请求,响应);//转发到JSP页面以在HTML表中显示它们。}catch(SQLException e){抛出新的ServletException(“检索产品失败!”,e);}}这种处理异常的方法更容易。数据库不是在JSP呈现过程中访问的,而是在显示JSP之前访问的。您仍然可以在DB访问引发异常时更改响应。在上面的示例中,将显示默认的错误500页面,您可以通过web.xml中的<errorpage>自定义该页面。如果您想调用一些Java代码来处理POST请求,例如从提交的HTML表单中收集数据并使用它进行一些业务处理(转换、验证、保存在DB中等),那么就实现一个servlet并在doPost()方法中相应地编写代码。例如。:protected void doPost(HttpServletRequest请求,HttpServletResponse响应)throws ServletException,IOException{字符串username=request.getParameter(“username”);字符串密码=request.getParameter(“password”);用户User=userService.find(用户名、密码);if(用户!=空){request.getSession().setAttribute(“user”,用户);//登录用户。response.sendRedirect(“home”);//重定向至主页。}其他{request.setAttribute(“message”,“未知用户名/密码。请重试。”);//将错误消息存储在请求范围中。request.getRequestDispatcher(“/WEB-INF/login.jsp”).forward(请求,响应);//转发到JSP页面以重新显示出现错误的登录表单。}}这种处理不同结果页目的地的方法更容易:在出现错误时重新显示带有验证错误的表单(在这个特定的示例中,您可以使用EL中的${message}重新显示它),或者在成功时只需转到所需的目标页。如果您想调用一些Java代码来控制执行计划和/或请求和响应的目标,那么根据MVC的Front Controller Pattern实现servlet。例如。:受保护的void服务(HttpServletRequest请求、HttpServletResponse响应)引发ServletException、IOException{尝试{Action Action=ActionFactory.getAction(请求);字符串视图=action.execute(请求,响应);if(view.equals(request.getPathInfo().substring(1)){request.getRequestDispatcher(“/WEB-INF/”+view+“.jsp”).forward(请求,响应);}其他{response.sendRedirect(视图);}}catch(异常e){抛出新ServletException(“执行操作失败。”,e);}}或者只是采用一个MVC框架,如JSF、Spring MVC、Wicket等,这样您最终只需要一个JSP/Facelets页面和一个JavaBean类,而不需要定制servlet。如果您想调用一些Java代码来控制JSP页面内的流,那么需要获取一个(现有的)流控制标记库,如JSTL核心。例如,在表格中显示列表<产品>:<%@taglib uri=“http://java.sun.com/jsp/jstl/core“prefix=”c“%>”...<表><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,因此代码的可读性(因此可维护性更好)比带有各种大括号和大括号(“这个大括号到底属于哪里?”)的一堆scriptlet要好。一个简单的帮助是,通过向web.xml添加以下部分,配置web应用程序,以便在仍然使用scriptlet时抛出异常:<jsp配置><jsp属性组><url模式>*.jsp</url模式><脚本无效>true</脚本无效></jsp属性组></jsp配置>在Facelets(JSP的继承者)中,它是JavaEE提供的MVC框架JSF的一部分,已经不可能使用scriptlets。这样你就自动被迫以“正确的方式”做事。如果您想调用一些Java代码来访问和显示JSP页面中的“后端”数据,那么您需要使用EL(表达式语言),这些${}的东西。例如,重新显示提交的输入值:<input-type=“text”name=“foo”value=“${param.foo}”/>${param.foo}显示request.getParameter(“foo”)的结果。如果您想直接在JSP页面中调用一些实用程序Java代码

另请参见:

JSP、Servlet和JSF之间有什么区别?Servlet、ServletContext、HttpSession和HttpServletRequest/Response是如何工作的?使用JSP、Servlet和JDBC的基本MVC示例Java web应用程序中的设计模式JSP/Servlet的隐藏特性

在JSP中使用JSTL标记库。这将非常有效。

使用Scriptlets是一种非常古老的方法,不建议使用。如果您想在JSP页面中直接输出一些内容,只需将表达式语言(EL)与JSTL一起使用即可。

还有其他选项,例如使用Velocity、Freemark、Thymelaf等模板引擎。但在大多数情况下,将普通JSP与EL和JSTL一起使用符合我的目的,对于初学者来说,这似乎也是最简单的。

此外,请注意,在视图层中执行业务逻辑不是最佳实践。您应该在服务层中执行业务逻辑,并通过控制器将输出结果传递给视图。

作为保障:永远禁用Scriptlets

正如另一个问题所讨论的,您可以并且应该始终禁用web.xml web应用程序描述符中的scriptlets。

我会一直这样做,以防止任何开发人员添加脚本,特别是在大公司中,您迟早会失去概述。web.xml设置如下所示:

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