简体   繁体   English

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

[英]Is this an acceptable case to use a JSP scriptlet?

I know that using JSP scriptlets is generally frowned upon, which is why I'm wondering if there is a more elegant way of achieving what I'm trying to do. 我知道使用JSP scriptlet通常是不受欢迎的,这就是为什么我想知道是否有一种更优雅的方式来实现我想要做的事情。 Pretty much I am creating a view, and depending on certain situations in the domain model, I am rendering different HTML. 我正在创建一个视图,并且根据域模型中的某些情况,我正在呈现不同的HTML。

For example, consider the scenario where a user could be in a role. 例如,考虑用户可能处于角色中的场景。 And a method like this is defined on the User model class: 这样的方法在User模型类中定义:

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

And then we have a JSP, like below: 然后我们有一个JSP,如下所示:

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

// Some HTML here...

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

As far as I know this can't be done using JSTL/EL. 据我所知,使用JSTL / EL无法做到这一点。 Does using scriptlets here sound like a good idea? 在这里使用scriptlet听起来是个好主意吗? Or is there another approach I should be taking? 或者我应该采取另一种方法吗?

Thanks for any suggestions. 谢谢你的任何建议。

I'd either upgrade to Servlet 3.0 / JSP 2.2 where invoking methods with arguments is allowed in EL 我要么升级到Servlet 3.0 / JSP 2.2,要么在EL中调用带参数的方法

<c:if test="${user.isInRole('admin')}">

or create a custom EL function 或创建自定义EL功能

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

As per your question history, you seem to be already using JEE6. 根据您的问题历史,您似乎已经在使用JEE6。 So the first approach should work for you (if your web.xml is declared conform Servlet 3.0 spec). 所以第一种方法应该适合你(如果你的web.xml声明符合Servlet 3.0规范)。

You may also create a custom tag to accomplish this. 您还可以创建自定义标记来完成此操作。 Here is a bare bones example: 这是一个简单的例子:

create a new tld file: WEB-INF/user.tld 创建一个新的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>

create the custom tag class: tags/UserRoleTag.java 创建自定义标记类:tags / 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;
  }
}

create your jsp: warfolder/home.jsp 创建你的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>

Taking this approach keeps your model and tag loosely coupled, and it can be reused in other projects, most likely. 采用这种方法可以使您的模型和标签保持松散耦合,并且最有可能在其他项目中重复使用。

The rule of thumb that I use is that scriptlets (or JSP tags or EL for that matter) must only use the model that has already been set up by the controller as opposed to triggering actions that interact with back end systems and get stuff. 我使用的经验法则是scriptlets(或JSP标签或EL)必须只使用已经由控制器设置的模型,而不是触发与后端系统交互并获取内容的操作。

The difference is often subtle but is quite significant in my opinion. 差异往往是微妙的,但在我看来是非常重要的。 In your example, let us say that the determination if the user is in an admin role requires you to access some database or make a web service call. 在您的示例中,我们假设确定用户是否处于管理员角色需要您访问某个数据库或进行Web服务调用。 Then you would be violating MVC by triggering that action from a view. 然后,您将通过从视图中触发该操作来违反MVC。 Whether you invoke the action from a scriptlet or a JSP tag or EL is immaterial. 无论是从scriptlet调用操作还是从JSP标记调用EL都是无关紧要的。 You have done stuff that is best done by the controller. 你做过最好由控制器完成的事情。

So how would I solve this problem? 那么我该如何解决这个问题呢? I would put the logic of determining if the user is in an admin role into the controller. 我会把确定用户是否处于管理员角色的逻辑放入控制器。 Then I would make this information available in the model so that the view can use the model to determine if the user is in an admin role. 然后,我将在模型中提供此信息,以便视图可以使用该模型来确定用户是否处于管理员角色。 A simple ${user.isAdmin} would then answer the question from the view. 然后,简单的$ {user.isAdmin}将从视图中回答问题。 The view would not be "accused" of triggering any actions. 该观点不会被“指责”触发任何行动。

So, am I being a purist by being a stickler to this kind of injunction? 那么,作为这种禁令的坚持者,我是纯粹主义者吗? I find that in many cases where an optimization of an application is required, it is easier for me to scan the controllers and optimize on what they are doing. 我发现在需要优化应用程序的许多情况下,我更容易扫描控制器并优化他们正在做的事情。 If the view also triggers back end work, then it would be very hard to do this kind of optimization since the back end interaction would then be scattered across multiple controllers and views. 如果视图还触发后端工作,那么进行这种优化将非常困难,因为后端交互将分散在多个控制器和视图中。

This also violates the single responsibility principle. 这也违反了单一责任原则。 Hope this answers your question. 希望这能回答你的问题。

By the way, great question. 顺便说一句,很棒的问题。 I am glad that you are thinking about this to this level of detail. 我很高兴您正在考虑这个细节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM