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

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

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

这是一种古老的编码方式,在 JSP 版本 2 中,存在一种避免在 JSP 文件中使用 Java 代码的方法。有人可以告诉我替代的 JSP 2 行吗,这种技术叫什么?

答案

自从 2001 年标签库 (如JSTL )和EL表达式语言 ,即${}东西)诞生以来,在JSP中确实不建议使用scriptlet (那些<% %>东西)。

scriptlet的主要缺点是:

  1. 可重用性:您无法重用 scriptlet。
  2. 可替换性:您不能使 scriptlet 抽象。
  3. 面向对象的能力:您不能利用继承 / 组合。
  4. 可调试性:如果 scriptlet 在中途抛出异常,您得到的只是空白页。
  5. 可测试性:脚本无法进行单元测试。
  6. 可维护性:每一次维护,需要花费更多时间来维护混合 / 混乱 / 重复的代码逻辑。

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

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

...

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

...

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


如何完全替换scriptlet取决于代码 / 逻辑的唯一目的。这段代码比以往更多地被放置在完全值得的 Java 类中:

保障措施:永久禁用脚本

在讨论另一个问题时 ,您可以并且始终应该在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>

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

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

JSTL 与请求属性一起使用 - 它们通常是由 Servlet 在请求中设置的,该 Servlet 会转发到 JSP。

我不确定我是否正确。

您应该阅读有关 MVC 的内容。 Spring MVCStruts 2是两个最常见的解决方案。

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

还有一些基于组件的框架,例如Wicket ,可以为您生成许多 HTML。最终出现在 HTML 中的标签是非常基础的,几乎没有逻辑混入其中。结果是带有典型 HTML 元素的几乎像空的 HTML 页面。不利的一面是, Wicket API 中有很多组件需要学习,在这些限制下,有些事情可能很难实现。

在 MVC 体系结构模式中,JSP 代表视图层。在 JSP 中嵌入 Java 代码被认为是不好的做法。您可以使用JSTLFreeMarker 的速度与 JSP 作为 “模板引擎”。这些标签的数据提供者取决于您正在处理的框架 。作为 MVC 模式的实现, Struts 2webwork使用OGNL “将 Beans 属性公开给 JSP 的非常有趣的技术”。

经验表明,JSP 有一些缺点,其中之一就是很难避免将标记与实际代码混合在一起。

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

学习使用 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 / 中创建 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>

将以下代码编译到 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>

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