ประเมินรายการมีสตริงใน JSTL


89

ฉันต้องการซ่อนองค์ประกอบหากมีค่าบางอย่างอยู่ใน JSP

ค่าจะถูกเก็บไว้ในรายการดังนั้นฉันจึงลอง:

<c:if test="${  mylist.contains( myValue ) }">style='display:none;'</c:if>

แต่มันไม่ได้ผล

ฉันจะประเมินได้อย่างไรว่ารายการมีค่าใน JSTL รายการและค่าเป็นสตริง


17
โปรดทราบว่าไวยากรณ์ที่กำหนดจะทำงานตามความตั้งใจตั้งแต่ EL 2.2 (ซึ่งนำมาเป็นส่วนหนึ่งของ Servlet 3.0 / JSP 2.2 ซึ่งเผยแพร่เมื่อธันวาคม 2009)
BalusC

คำตอบ:


70

น่าเศร้าที่ฉันคิดว่า JSTL ไม่สนับสนุนอะไรเลยนอกจากการวนซ้ำผ่านองค์ประกอบทั้งหมดเพื่อหาสิ่งนี้ ที่ผ่านมาฉันเคยใช้เมธอด forEach ในไลบรารีแท็กหลัก:

<c:set var="contains" value="false" />
<c:forEach var="item" items="${myList}">
  <c:if test="${item eq myValue}">
    <c:set var="contains" value="true" />
  </c:if>
</c:forEach>

หลังจากดำเนินการนี้ $ {contains} จะเท่ากับ "true" หาก myList มี myValue


10
ทำงานได้ดีหากรายการมีขนาดเล็ก เพียงแค่ตระหนักว่ามีค่าใช้จ่ายในการดำเนินการด้วยวิธีนี้
Chii

ใช่จะมีถ้าคุณสูงพอ ฉันใช้มันสำหรับคอลเลกชัน 10-20 สิ่งและไม่พบปัญหาด้านประสิทธิภาพใด ๆ สิ่งที่ฉันคิดว่าแย่กว่าคือจำนวนบรรทัดของ JSTL ถึงกระนั้นฉันคิดว่านี่เป็นวิธีเดียวที่ไม่ต้องตั้งค่า TLD ของคุณเอง (ซึ่งไม่ยากเกินไปและอาจคุ้มค่ามาก)
Kaleb Brasee

98

ไม่มีคุณสมบัติในตัวเพื่อตรวจสอบสิ่งนั้นสิ่งที่คุณต้องทำคือเขียนฟังก์ชัน tld ของคุณเองซึ่งรับรายการและรายการและเรียกใช้วิธีการมี () เช่น

//in your own WEB-INF/custom-functions.tld file add this
<?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
        xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
        version="2.0"
        >
    <tlib-version>1.0</tlib-version>
    <function>
        <name>contains</name>
        <function-class>com.Yourclass</function-class>
        <function-signature>boolean contains(java.util.List,java.lang.Object)
        </function-signature>
    </function>
</taglib>

จากนั้นสร้างคลาสชื่อ Yourclass และเพิ่มวิธีการแบบคงที่ที่เรียกว่ามีด้วยลายเซ็นด้านบน ฉันแน่ใจว่าการใช้วิธีนั้นค่อนข้างอธิบายได้ด้วยตนเอง:

package com; // just to illustrate how to represent the package in the tld
public class Yourclass {
   public static boolean contains(List list, Object o) {
      return list.contains(o);
   }
}

จากนั้นคุณสามารถใช้ใน jsp ของคุณ:

<%@ taglib uri="/WEB-INF/custom-functions.tld" prefix="fn" %>
<c:if test="${  fn:contains( mylist, myValue ) }">style='display:none;'</c:if>

สามารถใช้แท็กจาก JSP ใดก็ได้ในไซต์

แก้ไข: ข้อมูลเพิ่มเติมเกี่ยวกับไฟล์ tld - ข้อมูลเพิ่มเติมที่นี่


4
ฉันแนะนำให้ใช้CollectionแทนListใน taglib - ใช้งานได้เหมือนกัน แต่รองรับประเภทคอลเลกชันเพิ่มเติมเช่นSets
Ralph

28

อีกวิธีหนึ่งในการทำเช่นนี้คือการใช้Map (HashMap)คู่คีย์กับค่าแทนวัตถุของคุณ

Map<Long, Object> map = new HashMap<Long, Object>();
map.put(new Long(1), "one");
map.put(new Long(2), "two");

ใน JSTL

<c:if test="${not empty map[1]}">

สิ่งนี้ควรกลับมาเป็นจริงหากคู่นั้นมีอยู่ในแผนที่


2
นี่เป็นวิธีที่ฉันชอบเช่นกันตั้งค่าแฮชแมปใน viewmodel สำหรับทุกสิ่งที่ฉันต้องการในมุมมอง รวมเข้ากับไวยากรณ์ของ EL ได้เป็นอย่างดีและรวดเร็วเมื่อค้นหา
Boris B.

อีกอย่างหนึ่งถ้ามีคีย์อยู่ แต่ค่าเป็นโมฆะหรือว่างเปล่ามันจะส่งคืนเท็จ
Zai

1
หรือถ้าแผนที่มีบูลีนtest="${isPresentByValue[myValue]}"อยู่
Noumenon

15

คุณต้องใช้ฟังก์ชันfn:contains()orfn:containsIgnoreCase()

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

...

 <c:if test="${not fn:containsIgnoreCase(mylist, 'apple')}">
        <p>Doesn't contain 'apple'</p>
    </c:if>

หรือ

<c:if test="${not fn:contains(mylist, 'Apple')}">
            <p>Contains 'Apple'</p>
        </c:if>

หมายเหตุ: วิธีนี้จะได้ผลmylist.toString().contains("apple")และหากนี่ไม่ใช่สิ่งที่คุณต้องการให้ใช้แนวทางอื่นที่ดีกว่า


2
นี่ไม่ใช่แนวทางที่ถูกต้อง โดยทั่วไปแล้วจะมีพฤติกรรมเหมือนmylist.toString().contains("apple")ซึ่งไม่ใช่สิ่งที่คุณคาดหวังในตอนแรก
BalusC

โอ้ .. ใช่นี่ไม่ใช่สิ่งที่ฉันคาดหวัง อย่างไรก็ตามฉันจะอัปเดตคำตอบของฉันด้วยการปรับนี้
tk_

2

ต่อไปนี้เป็นวิธีแก้ปัญหามากกว่าคำตอบสำหรับคำถามของคุณ แต่อาจเป็นสิ่งที่คุณกำลังมองหา หากคุณสามารถใส่ค่าของคุณลงในแผนที่แทนที่จะเป็นรายการนั่นจะช่วยแก้ปัญหาของคุณได้ เพียงแค่จับคู่ค่าของคุณกับค่าที่ไม่ใช่ค่าว่างและทำสิ่งนี้<c:if test="${mymap.myValue ne null}">style='display:none;'</c:if>หรือคุณสามารถแมปstyle='display:none;และเพียงแค่ส่งออก${mymap.myValue}


ฉันเดาว่าไวยากรณ์ควรเป็น <c: if test = "$ {mymap [myValue] ne null}"> style = 'display: none;' </ c: if> ไม่เช่นนั้นจะไม่มีการประเมินตัวแปร "myValue"
Andreas


0

หากคุณใช้ EL 3.0+แนวทางที่ดีที่สุดในกรณีนี้คือคำตอบอื่นที่อธิบายไว้ในหัวข้ออื่น:

วิธีCollectionง่ายๆเพียงใช้Colleciton#contains() วิธีใน EL

<h:panelGroup id="p1" rendered="#{bean.panels.contains('p1')}">...</h:panelGroup>
<h:panelGroup id="p2" rendered="#{bean.panels.contains('p2')}">...</h:panelGroup>
<h:panelGroup id="p3" rendered="#{bean.panels.contains('p3')}">...</h:panelGroup>

สำหรับObject[](อาร์เรย์) คุณต้องมี EL 3.0 ขั้นต่ำและใช้การสนับสนุน Lambda ใหม่

<h:panelGroup id="p1" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p1').get()}">...</h:panelGroup>
<h:panelGroup id="p2" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p2').get()}">...</h:panelGroup>
<h:panelGroup id="p3" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p3').get()}">...</h:panelGroup>

หากคุณยังไม่ได้ใช้ EL 3.0 คุณจะต้องสร้างฟังก์ชัน EL ที่กำหนดเอง [... ]


-1

หากคุณใช้ Spring Framework คุณสามารถใช้ Spring TagLib และ SpEL:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
---
<spring:eval var="containsValue" expression="mylist.contains(myValue)" />
<c:if test="${containsValue}">style='display:none;'</c:if>

-1

ฉันพบว่าโซลูชันนี้น่าทึ่งมาก

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%
   ArrayList list = new ArrayList();
   list.add("one");
   list.add("two");
   list.add("three");
%>
<c:set var="list" value="<%=list%>" />
<html>
<body>
        My list is ${list}<br/>
<c:if test='${fn:contains(list, "two")}'>
        My list contains two <br/>
</c:if>
<c:if test='${fn:contains(list, ",")}'>
        My list contains , 
</c:if>
</body>
</html>

ผลลัพธ์ของโค้ดด้านบนคือ

รายการของฉันคือ [หนึ่งสองสาม]

รายการของฉันมีสองรายการ

รายการของฉันประกอบด้วย

ฉันหวังว่ามันจะช่วยใครสักคน


-2
<c:if test="${fn:contains(task.subscribers, customer)}">

วิธีนี้ใช้ได้ดีสำหรับฉัน


18
กำลังทำการตรวจสอบหลังจากแปลงทั้งสององค์ประกอบเป็นสตริง รายการจะถูกแปลงเป็นสตริงและไม่มีการตรวจสอบตามองค์ประกอบ หาก task.subscribers เป็นรายการ ["one", "two", "twentyone"] จะเป็นจริงสำหรับลูกค้า = "หนึ่ง" (การจับคู่สองครั้ง) false สำหรับลูกค้า = "สาม" (ไม่ตรงกัน) จริงสำหรับลูกค้า = "ยี่สิบ" (ซึ่งไม่ใช่สิ่งที่คุณกำลังมองหา)
Ricardo Marimon

2
เมื่อตระหนักถึงคำเตือนของ rmarimon คำตอบนี้ตรงกับกรณีการใช้งานของฉัน
CodeReaper
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.