EL เข้าถึงค่าแผนที่โดยใช้คีย์จำนวนเต็ม


85

ฉันมีแผนที่ที่คีย์ด้วย Integer เมื่อใช้ EL ฉันจะเข้าถึงค่าด้วยคีย์ได้อย่างไร

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");

ฉันคิดว่ามันจะใช้งานได้ แต่มันไม่ได้ (โดยที่แผนที่มีอยู่แล้วในคุณสมบัติของคำขอ)

<c:out value="${map[1]}"/>

ติดตามผล:ฉันติดตามปัญหาแล้ว เห็นได้ชัดว่า${name[1]}ทำการค้นหาแผนที่โดยมีหมายเลขเป็นไฟล์Long. ฉันคิดว่านี้เมื่อฉันเปลี่ยนHashMapไปTreeMapและได้รับข้อผิดพลาด:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

หากฉันเปลี่ยนแผนที่เป็น:

Map<Long, String> map = new HashMap<Long, String>();
map.put(1L, "One");

จากนั้น${name[1]}ส่งกลับ "One" นั่นคืออะไร? ทำไม<c:out>ถือว่าตัวเลขเป็นแบบยาว ดูเหมือนจะสวนทางกับฉัน (เนื่องจาก int มักใช้มากกว่า long)

คำถามใหม่ของฉันคือมีสัญลักษณ์ EL เพื่อเข้าถึงแผนที่ด้วยIntegerค่าหรือไม่?

คำตอบ:


117

คำตอบเริ่มต้น (EL 2.1, พฤษภาคม 2009)

ดังที่กล่าวไว้ในเธรดฟอรัม Java นี้ :

โดยทั่วไปแล้ว autoboxing จะวางวัตถุจำนวนเต็มลงในแผนที่ กล่าวคือ:

map.put(new Integer(0), "myValue")

EL (Expressions Languages) ประเมินว่า 0 เป็น Long จึงมองหา Long เป็นกุญแจสำคัญในแผนที่ กล่าวคือประเมิน:

map.get(new Long(0))

เนื่องจาก a Longไม่เคยเท่ากับIntegerวัตถุจึงไม่พบรายการในแผนที่
สรุปได้แค่นี้


อัปเดตตั้งแต่เดือนพฤษภาคม 2552 (EL 2.2)

ธันวาคม 2009 เห็นการนำ EL 2.2 กับ JSP 2.2 / Java EE 6มีความแตกต่างน้อยเมื่อเทียบกับ 2.1
ดูเหมือนว่า (" EL Expression แยกวิเคราะห์จำนวนเต็มยาว ") ที่:

คุณสามารถเรียกใช้เมธอดintValueบนLongวัตถุภายใน EL 2.2 :

<c:out value="${map[(1).intValue()]}"/>

นั่นอาจเป็นวิธีแก้ปัญหาที่ดีที่นี่ (กล่าวถึงด้านล่างในคำตอบของTobias Liefke )


คำตอบเดิม:

EL ใช้เครื่องห่อดังต่อไปนี้:

Terms                  Description               Type
null                   null value.               -
123                    int value.                java.lang.Long
123.00                 real value.               java.lang.Double
"string" ou 'string'   string.                   java.lang.String
true or false          boolean.                  java.lang.Boolean

หน้า JSP แสดงสิ่งนี้:

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

 <%@ page import="java.util.*" %>

 <h2> Server Info</h2>
Server info = <%= application.getServerInfo() %> <br>
Servlet engine version = <%=  application.getMajorVersion() %>.<%= application.getMinorVersion() %><br>
Java version = <%= System.getProperty("java.vm.version") %><br>
<%
  Map map = new LinkedHashMap();
  map.put("2", "String(2)");
  map.put(new Integer(2), "Integer(2)");
  map.put(new Long(2), "Long(2)");
  map.put(42, "AutoBoxedNumber");

  pageContext.setAttribute("myMap", map);  
  Integer lifeInteger = new Integer(42);
  Long lifeLong = new Long(42);  
%>
  <h3>Looking up map in JSTL - integer vs long </h3>

  This page demonstrates how JSTL maps interact with different types used for keys in a map.
  Specifically the issue relates to autoboxing by java using map.put(1, "MyValue") and attempting to display it as ${myMap[1]}
  The map "myMap" consists of four entries with different keys: A String, an Integer, a Long and an entry put there by AutoBoxing Java 5 feature.       

  <table border="1">
    <tr><th>Key</th><th>value</th><th>Key Class</th></tr>
    <c:forEach var="entry" items="${myMap}" varStatus="status">
    <tr>      
      <td>${entry.key}</td>
      <td>${entry.value}</td>
      <td>${entry.key.class}</td>
    </tr>
    </c:forEach>
</table>

    <h4> Accessing the map</h4>    
    Evaluating: ${"${myMap['2']}"} = <c:out value="${myMap['2']}"/><br>
    Evaluating: ${"${myMap[2]}"}   = <c:out value="${myMap[2]}"/><br>    
    Evaluating: ${"${myMap[42]}"}   = <c:out value="${myMap[42]}"/><br>    

    <p>
    As you can see, the EL Expression for the literal number retrieves the value against the java.lang.Long entry in the map.
    Attempting to access the entry created by autoboxing fails because a Long is never equal to an Integer
    <p>

    lifeInteger = <%= lifeInteger %><br/>
    lifeLong = <%= lifeLong %><br/>
    lifeInteger.equals(lifeLong) : <%= lifeInteger.equals(lifeLong) %> <br>

ไม่มีทางที่จะทำให้ EL ขยายจำนวนเป็นจำนวนเต็มได้ใช่หรือไม่?
Steve Kuo

1
@ สตีฟ: แน่นอนว่า EL ดูเหมือนจะไม่รองรับสิ่งนั้น
VonC

ฉันพบคำถามและคำตอบนี้จากการค้นหาของ Google แน่นอนว่าทันทีที่ฉันเปลี่ยนจาก Map <Integer, String> เป็น Map <Long, String> ฉันสามารถดึงจากมันโดยใช้ EL ที่ฉันมีในหน้า JSP ของฉัน ขอบคุณ !!
John Munsch

@ สตีฟ: เป็นไปได้ - ดูคำตอบของฉัน
Tobias Liefke

@SteveKuo มันควรจะเป็นไปได้แน่นอน ตอนนี้ฉันรู้แล้วว่าคำตอบอายุ 6 ขวบนี้เขียนขึ้นเมื่อ EL 2.2 ยังไม่เปิดตัว ฉันได้แก้ไขและอัปเดตคำตอบดังกล่าวแล้ว
VonC

11

คำแนะนำที่เป็นประโยชน์อื่น ๆ นอกเหนือจากความคิดเห็นด้านบนคือเมื่อคุณมีค่าสตริงที่อยู่ในตัวแปรบางตัวเช่นพารามิเตอร์คำขอ ในกรณีนี้การส่งผ่านสิ่งนี้จะส่งผลให้ JSTL คีย์ค่าของ say "1" ว่าเป็นการต่อยและไม่พบการจับคู่ดังกล่าวในแฮชแมปแผนที่

วิธีหนึ่งในการหลีกเลี่ยงปัญหานี้คือการทำสิ่งนี้

<c:set var="longKey" value="${param.selectedIndex + 0}"/>

ตอนนี้จะถือว่าเป็นวัตถุยาวจากนั้นมีโอกาสจับคู่วัตถุเมื่อมีอยู่ในแผนที่แผนที่หรืออะไรก็ตาม

จากนั้นดำเนินการต่อตามปกติด้วยสิ่งที่ต้องการ

${map[longKey]}

10

คุณสามารถใช้ฟังก์ชันทั้งหมดจาก Long ได้หากคุณใส่ตัวเลขลงใน "(" ")" ด้วยวิธีนี้คุณสามารถร่ายยาวเป็น int:

<c:out value="${map[(1).intValue()]}"/>

ฉันไม่เห็นคำตอบของคุณในทันที +1. ฉันได้รวมและบันทึกความเป็นไปได้นั้นไว้ในคำตอบของฉันเพื่อให้มองเห็นได้ชัดเจนขึ้น
VonC

3

จากโพสต์ด้านบนฉันได้ลองใช้สิ่งนี้และได้ผลดีฉันต้องการใช้ค่าของ Map B เป็นคีย์สำหรับ Map A:

<c:if test="${not empty activityCodeMap and not empty activityDescMap}">
<c:forEach var="valueMap" items="${auditMap}">
<tr>
<td class="activity_white"><c:out value="${activityCodeMap[valueMap.value.activityCode]}"/></td>
<td class="activity_white"><c:out value="${activityDescMap[valueMap.value.activityDescCode]}"/></td>
<td class="activity_white">${valueMap.value.dateTime}</td>
</tr>
</c:forEach>
</c:if>

3

หากคุณเพิ่งเกิดขึ้นที่จะมีMapกับIntegerคีย์ที่คุณไม่สามารถเปลี่ยนคุณสามารถเขียนกำหนดเองฟังก์ชั่น ELการแปลงไปLong Integerสิ่งนี้จะช่วยให้คุณทำสิ่งต่างๆเช่น:

<c:out value="${map[myLib:longToInteger(1)]}"/>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.