这是使用JSP scriptlet的可接受的案例吗?

时间:2011-02-15 02:27:11

标签: java model-view-controller jsp servlets java-ee

我知道使用JSP scriptlet通常是不受欢迎的,这就是为什么我想知道是否有一种更优雅的方式来实现我想要做的事情。我正在创建一个视图,并且根据域模型中的某些情况,我呈现的是不同的HTML。

例如,考虑用户可能处于角色中的情况。这样的方法在User模型类中定义:

public boolean isInRole(String roleName) {
    // Logic here to determine if the user is in a role
}

然后我们有一个JSP,如下所示:

<%
    User user = (User)request.getAttribute("user");
%>

// Some HTML here...

<% if (user.isInRole("admin") { %>
    // Generate some admin menu here
<% } %>

据我所知,使用JSTL / EL无法做到这一点。在这里使用scriptlet听起来是个好主意吗?或者我应该采取另一种方法吗?

感谢您的任何建议。

3 个答案:

答案 0 :(得分:8)

我要么升级到Servlet 3.0 / JSP 2.2,在EL

中允许调用带参数的方法
<c:if test="${user.isInRole('admin')}">

或创建自定义EL功能

<c:if test="${util:isUserInRole(user, 'admin')}">

根据您的问题历史,您似乎已经在使用JEE6。所以第一种方法应该适合你(如果你的web.xml被声明符合Servlet 3.0规范)。

答案 1 :(得分:5)

您也可以创建自定义标记来完成此操作。这是一个简单的例子:

创建一个新的tld文件: WEB-INF / user.tld

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag 
Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name></short-name>
    <tag>
       <name>user</name>
       <tag-class>tags.UserRoleTag</tag-class>
       <body-content>JSP</body-content>
       <attribute>
          <name>roles</name>
          <required>true</required>
          <rtexprvalue>true</rtexprvalue>
       </attribute>
    </tag>
</taglib>

创建自定义标记类: 标签/ UserRoleTag.java

package tags;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

@SuppressWarnings("serial")
public class UserRoleTag extends TagSupport {
  private String roles;

  public int doStartTag() throws JspException {
    String userRole = (String)pageContext.getAttribute("currentUserRole");

    return roles.contains(userRole) ? EVAL_BODY_AGAIN : SKIP_BODY;
  }

  public String getRoles() {
    return roles;
  }

  public void setRoles(String roles) {
    this.roles = roles;
  }
}

创建你的jsp:warfolder / home.jsp

<%@ taglib uri="/WEB-INF/user.tld" prefix="u" %>

<% pageContext.setAttribute("currentUserRole", "admin"); // this value would come from the controller... %>

<u:user roles="admin registered">
    welcome admin!
</u:user>

<u:user roles="guest">
    welcome guest!
</u:user>

采用这种方法可以保持模型和标签的松散耦合,并且很可能在其他项目中重复使用。

答案 2 :(得分:2)

我使用的经验法则是scriptlet(或JSP标签或EL)必须仅使用已由控制器设置的模型,而不是触发与后端系统交互的操作并获取东西。

差异往往是微妙的,但在我看来非常重要。在您的示例中,我们假设确定用户是否处于管理员角色需要您访问某个数据库或进行Web服务调用。然后,您将通过从视图中触发该操作来违反MVC。无论是从scriptlet调用操作还是从JSP标记调用EL都是无关紧要的。你做过最好由控制器完成的事情。

那么我该如何解决这个问题呢?我会把确定用户是否处于管理员角色的逻辑放入控制器。然后,我将在模型中提供此信息,以便视图可以使用该模型来确定用户是否处于管理员角色。 然后,简单的$ {user.isAdmin}将从视图中回答问题。该观点不会被“指责”触发任何行动。

那么,作为这种禁令的坚持者,我是纯粹主义者吗?我发现在需要优化应用程序的许多情况下,我更容易扫描控制器并优化他们正在做的事情。如果视图还触发后端工作,那么进行这种优化将非常困难,因为后端交互将分散在多个控制器和视图中。

这也违反了单一责任原则。希望这能回答你的问题。

顺便说一句,很棒的问题。我很高兴您正在考虑这个细节。