提问



我是Java EE的新手,我知道类似以下三行


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


是一种旧式的编码方式,在JSP版本2中,存在一种避免JSP文件中的Java代码的方法。有人可以告诉我替代的JSP 2行,以及这种技术的名称是什么?

最佳参考


自从 taglibs (如JSTL)和EL(表达语言)诞生以来,在JSP中使用 scriptlet (那些<% %>事物)确实非常气馁。 ${}事情)早在2001年。


scriptlet 的主要缺点是:



  1. 可重用性:您无法重复使用scriptlet。

  2. 可替换性:你不能使scriptlet抽象化。

  3. OO-ability:你不能使用继承/组合。

  4. 可调试性:如果scriptlet中途抛出异常,您只能获得一个空白页。

  5. 可测试性: scriptlet不可进行单元测试。

  6. 可维护性:每个saldo需要更多时间来维护混杂/混乱/重复的代码逻辑。



Sun Oracle本身也建议在JSP编码约定中避免在(标记)类可能的情况下使用 scriptlet 。以下是几个相关的引用:[71]



  从JSP 1.2规范,强烈建议在Web应用程序中使用JSP标准标记库(JSTL)来帮助减少页面中对JSP scriptlet的需求。通常,使用JSTL的页面更易于阅读和维护。

  
  ...

  
  在标签库提供等效功能的情况下,尽可能避免JSP scriptlet 。这使页面更易于阅读和维护,有助于将业务逻辑与表示逻辑分离,并使您的页面更容易演变为JSP 2.0样式的页面(JSP 2.0规范支持但不强调使用scriptlet)。

  
  ...

  
  本着采用模型 - 视图 - 控制器(MVC)设计模式来减少表示层与业务逻辑之间的耦合的精神,不应使用 JSP scriptlet 来编写业务逻辑。相反,如果需要,可以使用JSP scriptlet将从处理客户端请求返回的数据(也称为值对象)转换为适当的客户端就绪格式。即使这样,最好使用前端控制器servlet或自定义标签。






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



  • 如果您想在每个请求上调用相同的 Java代码,则无论请求的页面如何,都要少或多,例如检查用户是否已登录,然后在doFilter()方法中实现过滤器并相应地编写代码。 E.g.:[73]


    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.
        }
    }
    


    当映射到覆盖感兴趣的JSP页面的适当<url-pattern>时,您不需要在所有JSP页面上复制相同的代码段。




  • 如果要调用某些Java代码以预处理请求,例如从数据库预加载一些列表以显示在某个表中,如果有必要,根据一些查询参数,然后在doGet()方法中实现一个servlet并相应地编写代码。 E.g.:[75]


    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显示之前。每当数据库访问引发异常时,您仍然可以更改响应。在上面的示例中,将显示默认错误500页面,您可以通过web.xml中的<error-page>进行自定义。




  • 如果要调用某些Java代码以后处理请求,例如处理表单提交,然后实现一个servlet并在doPost()方法中相应地编写代码。 E.g.:[77]


    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.
        }
    }
    


    这样处理不同的结果页面目标更容易:在出现错误的情况下重新显示带有验证错误的表单(在此特定示例中,您可以使用EL中的${message}重新显示它),或者只是转到所需的目标页面成功的案例。




  • 如果要调用某些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);
        }
    }
    


    或者只是采用像JSF,Spring MVC,Wicket等MVC框架,这样你最终只需要一个JSP/Facelets页面和一个Javabean类,而不需要自定义的servlet。 [[




  • 如果要在JSP页面中调用某些Java代码来控制流,那么您需要获取(现有的)流控制标记库,如JSTL核心。例如。在表格中显示List<Product>:[84]


    <%@ 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,代码比具有各种打开和关闭括号的一堆scriptlet更易读(因此更易于维护)(这个闭合括号属于哪个? )。一个简单的帮助是通过将以下部分添加到web.xml来配置Web应用程序,以便在仍然使用 scriptlet 时抛出异常:


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


    在Facelets中,JSP的后继者是Java EE提供的MVC框架JSF的一部分,它已经可以使用 scriptlets 。这样你就会以正确的方式自动被迫做事。




  • 如果你想在JSP页面中调用一些Java代码来访问和显示后端数据,那么你需要使用EL(表达式语言),那些${}的东西。例如。重新显示提交的输入值:


    <input type="text" name="foo" value="${param.foo}" />
    


    ${param.foo}显示request.getParameter("foo")的结果。




  • 如果要直接在JSP页面中调用一些实用程序 Java代码(通常是public static方法),则需要将它们定义为EL函数。 JSTL中有一个标准函数taglib,但你也可以自己轻松创建函数。这里有一个例子,JSTL fn:escapeXml如何用来防止XSS攻击。[87] [88] [89] [90]


    <%@ 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/无关,在您开发的每个 Web应用程序中都需要考虑此问题。 scriptlets 的问题在于它无法提供内置预防,至少不使用标准Java API。 JSP的继承者Facelets已经隐式HTML转义,所以你不必担心Facelets中的XSS漏洞。



另见:




  • JSP,Servlet和JSF有什么区别?

  • Servlet,ServletContext,HttpSession和HttpServletRequest/Response如何工作?

  • JSP,Servlet和JDBC的基本MVC示例

  • Java Web应用程序中的设计模式

  • JSP/Servlet的隐藏功能


其它参考1


作为安全措施:禁止Scriptlet for Good [95]


正如另一个问题所讨论的那样,您可以并且始终应该在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>

其它参考2


JSTL为条件,循环,集合,获取等提供标签。例如:[97]


<c:if test="${someAttribute == 'something'}">
   ...
</c:if>


JSTL使用请求属性 - 它们通常由Servlet在请求中设置,其中转发到JSP。

其它参考3


我不确定我是否认为这是正确的。


你应该阅读一些关于MVC的内容。 Spring MVC& Struts 2是两种最常见的解决方案。 [98] [99]

其它参考4


您可以将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>

其它参考5


还有基于组件的框架,例如 Wicket ,可以为您生成大量HTML。最终在HTML中的标签非常基本,几乎没有混合的逻辑。结果几乎是空的HTML页面,具有典型的HTML元素。缺点是 Wicket API中有很多组件需要学习,有些事情在这些限制条件下很难实现。

其它参考6


在MVC架构模式中,JSP表示View层。在JSP中嵌入Java代码被认为是一种不好的做法。
您可以将JSTL,freeMarker,velocity用JSP作为模板引擎。
这些标记的数据提供者取决于您正在处理的框架Struts 2webwork作为MVC模式的实现使用OGNL非常有趣的技术将Beans属性暴露给JSP。[100] [101] [102] [103]]]

其它参考7


经验表明,JSP有一些缺点,其中一个难以避免将标记与实际代码混合。


如果可以,那么请考虑使用专门的技术来完成您的工作。在Java EE 6中有JSF 2.0,它提供了很多很好的功能,包括通过#{bean.method(argument)}方法将Java bean与JSF页面粘合在一起。

其它参考8


Wicket也是一种完全将java与html分开的替代方案,因此设计人员和程序员可以在不同的代码集上协同工作,彼此之间几乎没有相互理解。


看看Wicket。

其它参考9


如果您只是想避免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>

其它参考10


了解如何使用JSTL自定义和编写自己的代码


请注意,EL是 EviL (运行时异常,重构)

Wicket也可能是邪恶的(性能,对于小应用程序或简单的视图层来说很难)


来自 java2s 的示例,


这必须添加到Web应用程序的web.xml中


<taglib>
    <taglib-uri>/java2s</taglib-uri>
    <taglib-location>/WEB-INF/java2s.tld</taglib-location>
</taglib>


在/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 \\ 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;
    }
}


启动服务器并在浏览器中加载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>

其它参考11


你提出了一个很好的问题,虽然你得到了很好的答案,但我建议你摆脱JSP。它是过时的技术,最终将死亡。使用现代方法,如模板引擎。您将清楚地分离业务层和表示层,当然模板中没有Java代码,因此您可以直接从Web演示文稿编辑软件生成模板,在大多数情况下可以利用WYSIWYG。


当然要远离过滤器以及前后处理,否则你可能会遇到支持/调试困难,因为你总是不知道变量获取值的位置。

其它参考12


为了避免JSP文件中的java代码,java现在提供了像JSTL这样的标记库,java也提出了JSF,你可以用标签的形式编写所有的编程结构

其它参考13


无论你多么努力避免,当你与其他开发人员合作时,他们中的一些人仍然会喜欢scriptlet,然后将邪恶的代码插入到项目中。因此,如果您真的想减少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页面上,我创建了一个名为title的片段,这样在子页面中,我可以在母版页的这个位置插入更多代码。此外,标签<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/>。您的子页面还可以包含任何标记库,您可以像通常提到的那样使用它。但是,如果您在此处使用任何scriptlet代码(<%= request.getParameter("name") %> ...)并尝试运行此页面,您将获得JasperException because Scripting elements ( &lt;%!, &lt;jsp:declaration, &lt;%=, &lt;jsp:expression, &lt;%, &lt;jsp:scriptlet ) are disallowed here。因此,其他人无法将邪恶代码包含在jsp文件中


从您的控制器调用此页面


您可以从控制器轻松调用child.jsp文件。这对struts框架也很好用

其它参考14


在JSP中使用 JSTL Tag libraries ,这将是完美的。

其它参考15


只需使用JSTL标记和EL表​​达式。

其它参考16


如果有人真的反对使用多种语言编程,我建议GWT,理论上你可以避免使用所有JS和HTML元素,因为Google Toolkit会将所有客户端和共享代码转换为JS,你赢了他们有问题,所以你有一个没有任何其他语言编码的web服务。甚至你可以使用某些地方的默认CSS,因为它是由扩展(smartGWT或Vaadin)给出的。你不需要学习几十个注释。


当然,如果你愿意,你可以深入了解代码的深度并注入JS并丰富你的HTML页面,但实际上如果你愿意,你可以避免使用它,结果会很好,因为它是在任何其他框架中编写的。我说值得一试,基本的GWT已经有了很好的记录。


当然,许多其他程序员在此描述或推荐了其他几种解决方案。 GWT适用于那些真正不想处理Web部件或将其最小化的人。

其它参考17


来自Python世界的一个巧妙的想法是模板属性语言; TAL由Zope引入(因此a.k.a。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命名空间中的一些特殊属性;它可以通过浏览器查看,并由设计师安全地进行调整。
支持宏和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的实现。[104]

其它参考18


在JSP中使用scriptlet不是一个好习惯。


相反,您可以使用:



  1. JSTL标签

  2. EL表达式

  3. 自定义标签 - 您可以定义自己的标签以供使用。



请参阅:



  1. http://docs.oracle.com/javaee/1.4/tutorial/doc/JSTL3.html

  2. EL


其它参考19


从技术上讲,JSP在运行时都会转换为Servlet 。 JSP最初是为了按照MVC模式解耦业务逻辑和设计逻辑而创建的。所以JSP在运行时在技术上都是java代码。但回答这个问题,Tag Libraries通常用于将逻辑(删除Java代码)应用于JSP页面。[105] [106]

其它参考20


当然,将<%! counter++; %>替换为事件生产者 - 消费者体系结构,其中业务层被通知需要递增计数器,它会相应地做出反应,并通知演示者以便他们更新视图。涉及许多数据库事务,因为将来我们需要知道计数器的新旧值,谁已经增加了它并且考虑了什么目的。显然涉及序列化,因为这些层完全是分离的。您将能够通过RMI,IIOP,SOAP递增计数器。但是只需要HTML,你不会实现,因为它是如此平凡的情况。你的新目标是在新的闪亮的E7,64GB RAM服务器上每秒达到250个增量。


我有超过20年的编程经验,大多数项目在六重奏之前都失败了:可重用性可替换性OO能力可调试性可测性甚至还需要可维护性。由仅关注功能的人经营的其他项目非常成功。此外,在项目中过早实施的僵硬对象结构使得代码无法适应规范中的剧烈变化(也称为敏捷)。


所以我认为拖延是在项目早期或没有特别要求时定义层或冗余数据结构的Activity。 &NBSP;

其它参考21


如果我们在java Web应用程序中使用以下内容,则可以从JSP的前台删除Java代码。



  1. 将MVC架构用于Web应用程序

  2. 使用JSP标记


    一个。标准标签


    湾自定义标签

  3. 表达语言


其它参考22


如何避免JSP文件中的Java代码?


除了表达式语言( EL )之外,您还可以使用 JSTL 等标签库标签。但EL与JSP不兼容。因此,最好完全删除JSP并使用 Facelets


Facelets 是第一个为 JSF(Java Server Faces)设计的非JSP页面声明语言,与JSP相比,它为JSF开发人员提供了更简单,更强大的编程模型。它解决了JSP中用于Web应用程序开发的不同问题。


[107]

其它参考23


JSP 2.0有一个名为Tag Files的功能,你可以编写没有外部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,也可以在标签文件中访问sessionrequest,....


标记文件非常容易开发,因为您在更改服务器时不需要重新启动服务器,例如jsp文件。这使它们易于开发。


即使你使用像struts 2这样的框架,它有很多好的标签,你可能会发现拥有自己的标签可以减少你的代码。您可以将标记参数传递给struts,这样就可以自定义框架标记。


您不仅可以使用标记来避免使用Java,还可以最小化HTML代码。一旦看到代码重复在我的页面中开始,我自己就会尝试查看HTML代码并构建标签。


(即使您最终在jsp代码中使用java,我希望不会,您可以将该代码封装在标记中)

其它参考24


使用Scriptlet是一种非常古老的方式,不推荐使用。如果您想在JSP页面中直接输出内容,只需使用表达式语言(EL)以及 JSTL


还有其他选项,例如使用模板引擎,如Velocity,Freemarker,Thymeleaf等。但是使用带有EL和JSTL的普通JSP大部分时间都是我的目的,对于初学者来说它似乎也是最简单的。


另外,请注意,在视图层中执行业务逻辑不是最佳做法,您应该在服务层中执行业务逻辑,
并通过Controller将输出结果传递给您的视图。

其它参考25


我的朋友不再使用它,我的建议是从服务器中分离视图(css,html,javascript等)。


在我的情况下,我使用Angular处理视图,并使用rest从服务器获取所需的任何数据服务。


相信我,这将改变你的设计方式

其它参考26


使用骨干,角度类似javascript框架进行UI设计
并使用rest api获取数据。这将完全从UI中删除java依赖项。

其它参考27


正如许多答案所说,使用JSTL或创建自己的自定义标签。以下是创建自定义标签的好解释[108]

其它参考28


通过将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" %>