无法从Scriptlet中的方法向屏幕返回值

时间:2012-03-25 02:39:33

标签: java jsp scriptlet

我需要在屏幕上显示一些在script-let中定义的方法中读取的值。下面的代码没有编译:

<%!
    void displayRecursively(KnowledgeElement ke, ExtendsRelationshipService ers){
        List<ExtendsRelationship> erList = null;
        %><%=ke.getName()%><br /><%!
        try {
            erList = ers.findIncomingExtendsKERelationships(ke);
        } catch (Exception e) {}
        if (erList!=null){
            for (ExtendsRelationship er : erList){
                KnowledgeElement startKe = er.getStartKE();
                displayRecursively(startKe,ers);
            }
        }
    } 
%>  

<%
    KnowledgeElement ke = null;
    ke = (KnowledgeElement)request.getAttribute("knowledgeElement");
    ExtendsRelationshipService ers = (ExtendsRelationshipService)request.getAttribute("ers");
    displayRecursively(ke,ers);             
%>

编译错误是:

PWC6199: Generated servlet error:
cannot find symbol
  symbol:   variable ke
  location: class org.apache.jsp.WEB_002dINF.ke_jsp

使用..%&gt;&lt;%= ke.getName()%&gt;&lt;%..也不会编译。 有人可以建议如何解决这个问题吗?

3 个答案:

答案 0 :(得分:2)

Servlet容器按照这种方法将JSP代码编译成servlet类:

  • 使用“&lt;%!...%&gt;”时scriptlet符号你定义的代码将成为servlet类本身的一部分,它允许你定义函数。
  • 使用“&lt;%...%&gt;”时scriptlet符号你定义的代码将成为servlet本身的“service”方法的一部分。

所以,你正在做的是将在“service”方法之外声明的代码与对将要在“service”方法中复制的变量的引用混合。

要解决您的问题,我会在您的函数中添加另一个参数,并替换“交叉引用”(或者应该调用它)。它看起来像这样:

<%!
    void displayRecursively(JspWriter out, KnowledgeElement ke, ExtendsRelationshipService ers){
        List<ExtendsRelationship> erList = null;
        out.print(ke.getName());
        out.println("<br />");
        try {
            erList = ers.findIncomingExtendsKERelationships(ke);
        } catch (Exception e) {}
        if (erList!=null){
            for (ExtendsRelationship er : erList){
                KnowledgeElement startKe = er.getStartKE();
                displayRecursively(out, startKe,ers);
            }
        }
    } 
  %>

在您的其他scriptlet中调用该函数时,您必须在对PrintWriter的引用中过去(这是对于“service”方法内部的scriptlet的隐式变量):

displayRecursively(out, ke, era);

请注意,您需要在JSP中对“JspWriter”类进行页面导入才能进行编译。

答案 1 :(得分:1)

作为JSP样式指南noted nearly a decade前:

  

尽可能在标记库提供等效功能时避免使用JSP scriptlet。这使得页面更易于阅读和维护,有助于将业务逻辑与表示逻辑分离,并使您的页面更容易演变为JSP 2.0样式的页面......

使用模板进行递归很棘手,但可以完成。

这是一个表示层对象,它可以使您的对象适应EL可以使用的东西,可以处理异常等:

public class RelationshipPresentation {
  private final ExtendsRelationshipService service;
  private final ExtendsRelationship relationship;

  public RelationshipPresentation(ExtendsRelationshipService service, 
                                  ExtendsRelationship relationship) {
    this.service = service;
    this.relationship = relationship;
  }

  public String getName() { return relationship.getName(); }

  public List<RelationshipPresentation> getRelated() {
    List<RelationshipPresentation> list =
                                   new ArrayList<RelationshipPresentation>();
    try {
      for (ExtendsRelationship er :
           service.findIncomingExtendsKERelationships(relationship)) {
        list.add(new RelationshipPresentation(service, er));
      }
    } catch (Exception e) { /*Catching Exception?!*/ }
      return list;
  }
}

将这种类型单独测试到标记也很容易。

在调度到JSP之前将其置于范围内:

RelationshipPresentation relationshipPresentation =
                         new RelationshipPresentation(ers, knowledgeElement);
request.setAttribute("relationshipPresentation", relationshipPresentation);
getServletContext().getRequestDispatcher("/ercontainer.jsp")
                   .forward(request, response);

这是一个JSP片段(er.jsp),它显示了无序列表中的名称:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:out value="${relationshipPresentation.name}" />
<ul>
    <c:forEach var="relationshipPresentation"
               items="${relationshipPresentation.related}">
        <c:set var="relationshipPresentation"
               value="${relationshipPresentation}" scope="request"/>
        <li><jsp:include page="er.jsp"/></li>
    </c:forEach>
</ul>

这可以通过JSP操作<jsp:include page="er.jsp" />包含在您的主页中。

答案 2 :(得分:0)

&LT;!%..%GT;被称为声明性标签。您可以使用声明的变量和在service(&lt;%..%&gt;)中的声明性标记下定义的方法,但不能使用声明性标记中的方法参数。