从 JSP 1.2 规范开始,强烈建议在 Web 应用程序中使用 JSP 标准标记库 (JSTL),以帮助减少对 JSP scriptlet 的需求在您的页面中。一般来说,使用 JSTL 的页面更易于阅读和维护。
...
在可能的情况,避免 JSP 小脚本每当标签库提供同等功能时。这使得页面更易于阅读和维护,有助于将业务逻辑与表示逻辑分开,并使您的页面更容易发展为 JSP 2.0 样式的页面(JSP 2.0 规范支持但不再强调 scriptlet 的使用)。
...
本着采用模型-视图-控制器(MVC)设计模式来减少表示层与业务逻辑之间的耦合的精神,不应使用 JSP scriptlet用于编写业务逻辑。相反,如果需要,可以使用 JSP scriptlet 将处理客户端请求返回的数据(也称为“值对象”)转换为适当的客户端就绪格式。即使如此,最好使用前端控制器 servlet 或自定义标签来完成。
-
如果你想调用sameJava 代码上every请求,或多或少,无论请求的页面如何,例如检查用户是否登录,然后实施filter https://stackoverflow.com/tags/servlet-filters/info并相应地编写代码doFilter() https://jakarta.ee/specifications/platform/9/apidocs/jakarta/servlet/filter#doFilter-jakarta.servlet.ServletRequest-jakarta.servlet.ServletResponse-jakarta.servlet.FilterChain-方法。例如。:
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代码处理 GET 请求,例如从数据库预加载一些列表以显示在某些表中,如果需要的话基于一些查询参数,然后实现servlet https://stackoverflow.com/tags/servlets/info并相应地编写代码doGet() https://jakarta.ee/specifications/platform/9/apidocs/jakarta/servlet/http/httpservlet#doGet-jakarta.servlet.http.HttpServletRequest-jakarta.servlet.http.HttpServletResponse-方法。例如。:
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);
}
}
这种方式处理异常更加容易。 DB 不是在 JSP 渲染过程中访问的,而是在 JSP 显示之前访问的。每当数据库访问引发异常时,您仍然可以更改响应。在上面的示例中,将显示默认的错误 500 页面,您可以通过自定义<error-page>
in web.xml
.
-
如果你想调用一些Java代码处理 POST 请求,例如从提交的 HTML 表单中收集数据并用它做一些业务(转换、验证、保存在数据库中等),然后实现一个servlet https://stackoverflow.com/tags/servlets/info并相应地编写代码doPost() https://jakarta.ee/specifications/platform/9/apidocs/jakarta/servlet/http/httpservlet#doPost-jakarta.servlet.http.HttpServletRequest-jakarta.servlet.http.HttpServletResponse-方法。例如。:
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}
in EL https://stackoverflow.com/tags/el/info),或者在成功的情况下直接进入所需的目标页面。
-
如果你想调用一些Java代码control执行计划和/或请求和响应的目的地,然后实施servlet https://stackoverflow.com/tags/servlets/info根据MVC的前端控制器模式 https://stackoverflow.com/questions/3541077/design-patterns-web-based-applications/3542297#3542297. E.g.:
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 https://stackoverflow.com/tags/jsf/info, 春季MVC https://stackoverflow.com/tags/spring-mvc/info, Wicket https://stackoverflow.com/tags/wicket/info等,这样您最终只需一个 JSP/Facelets 页面和一个 JavaBean 类,而不需要自定义 servlet。
-
如果你想调用一些Java代码控制流量在 JSP 页面内,那么您需要获取一个(现有的)流程控制标签库,例如JSTL核心 https://jakarta.ee/specifications/tags/1.2/tagdocs/c/tld-summary.html。例如。显示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>
使用与所有 HTML 完美契合的 XML 样式标签,代码比一堆带有各种左大括号和右大括号的 scriptlet 更具可读性(因此也更易于维护)(“这个右大括号到底属于哪里?”)。一个简单的帮助是将您的 Web 应用程序配置为在任何时候抛出异常小脚本通过添加以下片段仍然可以使用web.xml
:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
In Facelets https://stackoverflow.com/tags/facelets/info,JSP的后继者,它是Java EE提供的MVC框架的一部分JSF https://stackoverflow.com/tags/jsf/info,已经是not可以使用小脚本。这样你就会自动被迫以“正确的方式”做事。
-
如果你想调用一些Java代码访问和显示JSP页面内部的“后端”数据,那么你需要使用EL(表达式语言),那些${}
事物。例如。重新显示提交的输入值:
<input type="text" name="foo" value="${param.foo}" />
The ${param.foo}
显示结果request.getParameter("foo")
.
-
如果你想调用一些utilityJava代码直接在JSP页面中(通常是public static
方法),那么您需要将它们定义为 EL 函数。有一个标准函数标签库 https://jakarta.ee/specifications/tags/1.2/tagdocs/fn/tld-summary.html在 JSTL 中,但是您也可以轻松地自己创建函数 https://stackoverflow.com/questions/6395621/how-to-call-a-static-method-in-jsp-el。下面是 JSTL 的示例fn:escapeXml
有利于防止XSS攻击 https://en.wikipedia.org/wiki/Cross-site_scripting.
<%@ 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/任何其他内容没有任何具体关系,这个问题需要在every您开发的网络应用程序。的问题小脚本最大的问题是它没有提供内置的预防措施,至少没有使用标准的 Java API。 JSP 的后继者 Facelets 已经具有隐式 HTML 转义功能,因此您无需担心 Facelets 中的 XSS 漏洞。