ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

@Koray Tugay,只要在使用之前在某处声明了计数器变量,那么它肯定是有效的......
@SheldonR。这是有效的:<%= counter++ %> 或这个:<%!整数计数器 = 0; int x = 计数器++; %> 但不是:<%!整数计数器 = 0;计数器++; %>
@KorayTugay,我的意思是如果变量 counter 在较早的脚本块中声明,它应该在以后的块中有效。但最终,这些天的 J2EE 程序员应该使用 EL 变量而不是 scriptlet,无论如何......

B
BalusC

自从 taglibs(如 JSTL)和 EL({ 4},那些 ${} 事情)早在 2001 年。

Scriptlet 的主要缺点是:

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

Sun Oracle 本身也在 JSP coding conventions 中建议避免使用 scriptlet,只要(标记)类可以实现相同的功能。以下是一些相关的引用:

从 JSP 1.2 规范开始,强烈建议在您的 Web 应用程序中使用 JSP 标准标记库 (JSTL),以帮助减少页面中对 JSP scriptlet 的需求。使用 JSTL 的页面通常更易于阅读和维护。 ...只要标签库提供等效功能,就尽可能避免使用 JSP scriptlet。这使页面更易于阅读和维护,有助于将业务逻辑与表示逻辑分开,并使您的页面更容易演变为 JSP 2.0 样式的页面(JSP 2.0 规范支持但不强调使用 scriptlet)。 ... 本着采用模型-视图-控制器 (MVC) 设计模式来减少表示层与业务逻辑之间的耦合的精神,不应使用 JSP 脚本来编写业务逻辑。相反,如果需要,可以使用 JSP 脚本将处理客户端请求返回的数据(也称为“值对象”)转换为适当的客户端就绪格式。即便如此,最好使用前端控制器 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("登录"); // 未登录,重定向到登录页面。 } else { chain.doFilter(request, response); // 登录,继续请求。当映射到覆盖感兴趣的 JSP 页面的适当 上时,您无需复制粘贴整个 JSP 页面的同一段代码。

如果你想调用一些Java代码来处理一个GET请求,例如从数据库中预加载一些列表以显示在一些表中,如果有必要基于一些查询参数,那么实现一个servlet并在doGet()方法中相应地编写代码。例如:protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { List products = productService.list(); // 获取所有产品。 request.setAttribute("产品", 产品); // 将产品存储在请求范围内。 request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // 转发到 JSP 页面以在 HTML 表格中显示它们。 } catch (SQLException e) { throw new ServletException("检索产品失败!", e); } } 这种方式处理异常更容易。在 JSP 呈现过程中不访问 DB,但在显示 JSP 之前很长时间。每当数据库访问引发异常时,您仍然可以更改响应。在上面的示例中,将显示默认的错误 500 页面,您可以通过 web.xml 中的 自定义该页面。

如果您想调用一些 Java 代码来处理 POST 请求,例如从提交的 HTML 表单中收集数据并用它做一些业务(转换、验证、保存在数据库中等),那么实现一个 servlet 并相应地编写代码在 doPost() 方法中。例如:protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username");字符串密码 = request.getParameter("密码");用户用户 = userService.find(用户名,密码); if (user != null) { request.getSession().setAttribute("user", user); // 登录用户。 response.sendRedirect("home"); // 重定向到主页。 } else { request.setAttribute("message", "未知用户名/密码。请重试。"); // 在请求范围内存储错误消息。 request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // 转发到 JSP 页面以重新显示有错误的登录表单。这种方式处理不同的结果页面目的地更容易:在出现错误时重新显示带有验证错误的表单(在这个特定的示例中,您可以在 EL 中使用 ${message} 重新显示它),或者只是进入所需的目标页面在成功的情况下。

如果您想调用一些 Java 代码来控制执行计划和/或请求和响应的目的地,那么根据 MVC 的前端控制器模式实现一个 servlet。例如:protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Action action = ActionFactory.getAction(request);字符串视图 = action.execute(请求,响应); 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、Spring MVC、Wicket 等,这样你最终会得到只需一个 JSP/Facelets 页面和一个 JavaBean 类,而无需自定义 servlet。

如果您想调用一些 Java 代码来控制 JSP 页面内的流程,那么您需要获取一个(现有的)流程控制标记库,如 JSTL 核心。例如在表格中显示 List:<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> ...

${product.name} ${product.description} ${product.价格}
使用与所有 HTML 完美匹配的 XML 样式标签,代码比一堆带有各种开括号和闭括号(“这个闭括号到底属于哪里?”)。一个简单的帮助是通过将以下部分添加到 web.xml 来配置您的 Web 应用程序以在仍然使用 scriptlet 时抛出异常: *.jsp< /url-pattern> true 在 Facelets 中,JSP 的继承者,它是 Java EE 提供的 MVC 框架 JSF 的一部分,已经不可能使用scriptlet了。这样,您就会自动被迫以“正确的方式”做事。

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

如果您想在 JSP 页面中直接调用一些实用 Java 代码(通常是公共静态方法),那么您需要将它们定义为 EL 函数。 JSTL 中有一个标准的函数标签库,但您也可以轻松地自己创建函数。这是 JSTL fn:escapeXml 如何用于防止 XSS 攻击的示例。 <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" 前缀="fn" %> ... 请注意,XSS 敏感性与 Java/JSP/JSTL/EL/whatever 无关,在您开发的每个 Web 应用程序中都需要考虑到这个问题。 scriptlet 的问题在于它没有提供内置预防措施,至少不使用标准 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 是可以的,但这应该是证明规则的例外。
@svachon:Scriptlet 对于快速原型设计/测试很有用。据我所知,scriptlet 只有一种“合法”的生产用途,即 </head><body> 之间的 <% response.getWriter().flush(); %> 以提高网络浏览器中的网页解析性能。但是当服务器端的输出缓冲区大小较低(1~2KB)时,这种使用又完全可以忽略不计。 See also this article
@BalusC 有几次我被不遵循getter/setter 模式的java 类所困扰。恕我直言,这是一个脚本完成这项工作的情况。
@svachon:我会用自己的javabean类包装这些类并使用它们。
C
Community

作为保障:永久禁用 Scriptlet

正如 another question 所讨论的,您可以并且始终应该禁用 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>

@MrSpoon 为您找到了答案。根据 this answer + comment,这将关闭 scriptlet <% %>、scriptlet 表达式 <%! %> 和 scriptlet 声明 <%= %>。这意味着指令 <%@ %> 和评论 <%-- --%> 保持启用和可用,因此您仍然可以进行评论和包含。
B
Bozho

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

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

JSTL 与请求属性一起工作——它们通常由 Servlet 在请求中设置,然后转发给 JSP。


B
Behrang

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

P
Peter Mortensen

还有一些基于组件的框架,例如 Wicket,可以为您生成大量 HTML。

最终出现在 HTML 中的标签非常基本,几乎没有混入其中的逻辑。结果几乎是空的 HTML 页面,带有典型的 HTML 元素。缺点是 Wicket API 中有很多组件需要学习,在这些限制下,有些事情可能很难实现。


e
eis

在 MVC 架构模式中,JSP 代表视图层。在 JSP 中嵌入 Java 代码被认为是一种不好的做法。

您可以将 JSTLfreeMarkervelocity 与 JSP 一起用作“模板引擎”。

这些标签的数据提供者取决于您正在处理的框架Struts 2 和 WebWork 作为 MVC 模式的实现,使用 OGNL“将 Beans 属性公开给 JSP 的非常有趣的技术”。


T
Thorbjørn Ravn Andersen

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

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


旧答案,但我忍不住要说 JSF 是 Java 领域最可怕的发明之一。尝试创建一个(类似 HTTP GET 的)链接,您就会明白为什么。
@Alex,但还是更好。随意推荐一些更好的东西。
@ThorbjørnRavnAndersen 脚本
@user253751 是的,scriptlets 是提到的“将标记与实际代码混合”的缺点。
@ThorbjørnRavnAndersen 标记是实际代码
P
Peter Mortensen

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

P
Peter Mortensen

学习使用 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>

尽管组件的可重用性很好,但它针对的是某些领域
P
Peter Mortensen

Wicket 也是一种将 Java 与 HTML 完全分开的替代方案,因此设计人员和程序员可以一起工作并处理不同的代码集,而彼此几乎不了解。

看看检票口。


g
glen3b

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

并且一定要远离过滤器以及前后处理,否则您可能会遇到支持/调试困难,因为您总是不知道变量从哪里获得值。


JSP 本身就是一个模板引擎
您可以将业务层和表示层与大多数其他模板引擎混合使用,因为它们中的大多数都是图灵完备的。我认为 stringtemplate.org 是非图灵完备的例外之一。
P
Peter Mortensen

为了避免 JSP 文件中出现 Java 代码,Java 现在提供了标记库,例如 JSTL。

此外,Java 还提出了 JSF,您可以在其中以标记的形式编写所有编程结构。


T
Thai Tran

不管你如何避免,当你与其他开发人员合作时,他们中的一些人仍然会更喜欢 scriptlet,然后将恶意代码插入到项目中。因此,如果你真的想减少 scriptlet 代码,一开始就设置项目非常重要。有几种技术可以克服这个问题(包括其他提到的几个框架)。但是,如果您更喜欢纯 JSP 方式,那么请使用 JSTL 标记文件。这样做的好处是您还可以为您的项目设置母版页,因此其他页面可以继承母版页

在您的 WEB-INF/tags 下创建一个名为 base.tag 的母版页,其中包含以下内容

<%@tag description="Overall Page template" pageEncoding="UTF-8"%> <%@attribute name="title" fragment="true" %> <jsp:invoke fragment ="title"></jsp:invoke>

在这个母版页上,我创建了一个名为“title”的片段,以便在子页中,我可以在母版页的这个地方插入更多的代码。此外,标签 <jsp:doBody/> 将替换为子页面的内容

在您的 WebContent 文件夹中创建子页面 (child.jsp):

<%@ taglib prefix="t" tagdir="/WEB-INF/tags" %> < /jsp:attribute> [把你孩子的内容放在这里]

<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 框架


“无论你多么努力避免,当你与其他开发人员合作时,他们中的一些人仍然会更喜欢 scriptlet,然后将恶意代码插入到项目中。”请参阅“作为保障措施:永久禁用 Scriptlets”答案。
或者你可以解释为什么 scriptlet 是邪恶的,如果你不能解释它,也许它们实际上并不是邪恶的。
P
Peter Mortensen

在 JSP 中使用 JSTL 标记库。这将完美地工作。


t
tanglei

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


P
Peter Mortensen

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

当然,如果你愿意,你可以深入到代码的深处,注入 JavaScript 并丰富你的 HTML 页面,但如果你愿意,你真的可以避免它,结果会很好,因为它是在任何其他框架中编写的.我说值得一试,基本的 GWT 有据可查。

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


并没有真正回答OP的问题。
@EvanDonovan 好吧,实际上它确实给出了答案。您无需将 Java 代码与其他语言混为一谈。我承认它使用 Java 进行编码,但它会在没有 Java 调用的情况下转换为 JS。但问题的范围是如何避免经典 JSP 的混乱。而 GWT 技术解决了这个问题。我添加了这个答案,因为没有人提到它,但因为它是 JSP 的替代品,所以很重要。我不想回答这个问题的全部范围,而是想为正在寻找替代品的人添加有价值的信息。
P
Peter Mortensen

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 命名空间中的一些特殊属性;它可以用浏览器查看,并由设计师安全地进行调整。

支持宏和 internationalisation and localisation

<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 implementation 了解不多。


自 2009 年 12 月以来,JSP 被支持这些东西的 Facelets 所取代。 Facelets 也是基于 XML 的。另请参阅 Facelets chapter in Java EE 6 tutorialui:xxx tags in Facelts VDL
我不太了解 Facelets,但 IIRC 都是关于编写实现自定义 XML 元素的类。 TAL/ZPT 方式是拥有包含真正 (X)HTML 的模板,这些模板具有填充或替换原始元素的特殊属性;因此,您可以查看工作模板并查看具有漂亮虚拟内容的原型。我不确定 Facelets 是否允许使用自定义属性调整原始 HTML 元素(没有额外的命名空间)。
我刚刚又看了看这个 Facelets 的东西。它包含各种验证工具等,因此遵循与 TAL 完全不同的理念。 TAL 方法是,“尽可能干净地将逻辑排除在模板之外;让所有复杂的事情都由提供它的控制器来完成。”您永远不会将 Facelets 模板提供给设计师让他/她对其进行调整;这是不可能的。关于生成的内容 - 就像一直使用 tal:replace="structure (expression)" 属性一样。
R
RustyTheBoyRobot

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

相反,您可以使用:

JSTL 标记 EL 表达式 自定义标记 - 您可以定义自己的标记来使用。

请参阅:

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


A
Alex Weitz

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

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

因此,我认为在项目早期或没有特别需要时定义“层”或冗余数据结构的活动是拖延。


P
Peter Mortensen

从技术上讲,JSP 在运行时都被转换为 Servlet。

JSP 最初是为了解耦业务逻辑和设计逻辑而创建的,遵循 MVC 模式。因此,从技术上讲,JSP 是运行时期间的所有 Java 代码。

但要回答这个问题,标记库通常用于将逻辑(删除 Java 代码)应用于 JSP 页面。


P
Peter Mortensen

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

为 Web 应用程序使用 MVC 架构 使用 JSP 标签

一个。标准标签

湾。自定义标签

表达语言


P
Peter Mortensen

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

除了表达式语言 (EL) 之外,您还可以使用标签库标签,例如 JSTL。但是 EL 不适用于 JSP。因此,完全放弃 JSP 并使用 Facelets 可能会更好。

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

https://i.stack.imgur.com/osqxG.png

Source


我绝对支持这个回应。带有或不带有 Facelets 的 JSF。我认为用 JSP 进行开发已经在 10 多年前基本停止了。我上次写 JSP 是在 2000 年!
P
Peter Mortensen

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

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

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


P
Peter Mortensen

使用 Backbone.js 或类似 AngularJS 的 JavaScript 框架进行 UI 设计并使用 REST API 获取数据。这将从 UI 中完全删除 Java 依赖项。


P
Peter Mortensen

我的朋友,这些都不再使用了。我的建议是将视图(CSS、HTML、JavaScript 等)与服务器分离。

就我而言,我的系统使用 Angular 来处理视图,所需的任何数据都使用 REST 服务从服务器获取。

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


它将改变我们的设计方式,但并不总是以一种好的方式产生好的结果。
它将改变我们的设计方式,但并不总是以一种好的方式产生好的结果。我们将面临 1. 较长的初始加载 2. 谷歌索引缓慢,其他搜索引擎没有索引 3. 低端移动设备上的性能问题。 SPA 框架应该用于 SPA。使用 SPA 框架创建内容网站,尤其是 Angular 或 React 等重型框架是一种麻烦。
P
Peter Mortensen

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,访问 { 6}, request, ...也在你的标签文件中。

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

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

您不仅可以使用标签来避免使用 Java,还可以最大限度地减少 HTML 代码。一旦我在我的页面中看到代码重复,我自己就会尝试大量查看 HTML 代码并构建标签。

(即使您最终在 JSP 代码中使用了 Java,我希望不会,您也可以将该代码封装在标签中。)


M
Mehdi

在 servlet 类中创建值和参数 使用 JSTL/Taglib 在 JSP 中获取这些值和参数

这种方法的好处是您的代码也是类似 HTML 的代码!


P
Peter Mortensen

正如许多答案所说,使用 JSTL 或创建自己的自定义标签。 Here 很好地解释了创建自定义标签。


P
Philippe Damerval

这里的很多答案都是“使用框架”路线。这是零错误的。但是我认为它并不能真正回答您的问题,因为框架可能使用也可能不使用 JSP,它们的设计也没有以任何方式将在 JSP 中使用 java 作为主要目标。您的问题“我如何避免在 JSP 中使用 Java”的唯一好的答案是:您不能。这就是 JSP 的用途——使用 Java 以动态数据/逻辑呈现 HTML。后续问题可能是,我应该在我的 JSP 中使用多少 java。在我们回答这个问题之前,您还应该思考,“我需要使用 JSP 来使用 Java 构建 Web 内容吗?”最后一个的答案是,不。对于使用 Java 开发面向 Web 的应用程序,有许多 JSP 替代方案。例如,Struts 不会强迫您使用 JSP - 不要误会我的意思,您可以使用它们,许多实现都可以,但您并非绝对必须这样做。 Struts 甚至不强制您使用任何 HTML。 JSP 也不会,但老实说,不产生 HTML 的 JSP 有点奇怪。众所周知,Servlet 允许您通过 HTTP 动态地提供您喜欢的任何类型的内容。它们是几乎所有 java web 背后的主要技术——JSP 只是 servlet 的 HTML 模板,真的。因此,您应该在 JSP 中放入多少 java 的答案是“尽可能少”。我的 JSP 中当然有 java,但它完全由标记库定义、会话和客户端变量以及封装服务器端对象的 bean 组成。我的 HTML 中的 <%%> 标记几乎完全是属性调用或变量表达式。罕见的例外情况包括与单个页面相关且不太可能被重用的超特定计算;源自页面特定问题的错误修正仅适用于一页;最后一分钟的连接和算术源于不寻常的要求,范围仅限于一页;和其他类似情况。在 150 万行、3000 个 JSP 和 5000 个类的代码集中,可能有 100 个此类独特片段的实例。在类或标记库定义中进行这些更改是完全可能的,但由于每种情况的特殊性,它会非常复杂,编写和调试需要更长的时间,因此需要更多的时间才能到达我的用户。这是一个判断电话。但是不要搞错,你不能用“no java”写出任何意义的JSP,你也不想写。这种能力是有原因的。


y
yurin

Java 本身是一种非常好的语言,但在企业环境中的大量使用使其标准解决方案极其(荒谬地)困难。示例:JSTL、JSF、Wicket 等。

这是一种在 Java 中创建后端的超轻量级方法:

根本不使用 JSP(或任何其他模板引擎);

使用纯 HTML 模板;

使用 JSOUP 将 HTML 模板解析为 Document 对象;

使用其非常直观的类似 jQuery 的方法修改 Document 对象;

返回 Document.toString() 作为对请求的响应。

我将它用于我的一个副项目(托管 Digitalocean 5 美元的水滴、Nginx、Tomcat),它非常快:根据 Googlebot 的平均响应时间约为 160 毫秒。