JSTL通过数值key访问map的陷阱

<%@ taglib uri=" http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri=" http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
< %@page contentType="text/html;charset=gb2312"%>
< %@page import="java.util.*"%>
<%!
private static class User{
        private int id;
        private String name;
        private String hello;
        public int getId() {return id;}
        public void setId(int id) {this.id = id;}
        public String getName() {return name;}
        public void setName(String name) {this.name = name;}
     public void setHello(String hello){
      this.hello = hello;
     }
     public String getHello(){
      return "hello";
     }
        @Override
        public String toString() {return "User [id=" + id + ", name=" + name + "]";}
        public User(int id, String name) {this.id = id;this.name = name;}
        public User() {}
    }
%>
<%
Map<Long,User> userMap = new HashMap<Long,User>();
userMap.put(1L,new User(1,"xujsh"));
userMap.put(2L,new User(2,"dm"));
pageContext.setAttribute("userMap",userMap);
pageContext.setAttribute("key",1L);//这种赋值方式能明确的知道key的类型
%>
<c:forEach items="${userMap}" var="entry">
 <c:out value="${entry.key}" />
 <c:out value="${entry.value}" />
</c:forEach><br/>
user:<c:out value="${userMap[key]}" /><br/>
现在稍微做一下改动:<br/>
<%
Map<Long,User> userMap2 = new HashMap<Long,User>();
userMap2.put(1L,new User(1,"xujsh"));
userMap2.put(2L,new User(2,"dm"));
pageContext.setAttribute("userMap2",userMap2);
//pageContext.setAttribute("key",1L);//不是用这种方式设置值
%>
<c:forEach items="${userMap2}" var="entry">
 <c:out value="${entry.key}" />
 <c:out value="${entry.value}" />
</c:forEach><br/>
<c:set var="key" value="1" /><!--用这种方式设置,这个值无论是“1L”还是“1”,都取不出值来,貌似是当成字符串了!-->
<!--
查看jsp对应的servlet,我们可以看出来,确实是当成字符串了!
_jspx_th_c_005fset_005f0.setVar("key");
_jspx_th_c_005fset_005f0.setValue(new String("1"));
-->

user:<c:out value="${userMap2[key]}" /><br/>
user:<c:out value="${userMap2[1]}" /><br/> <!--直接使用数字1是可以取出来的-->
<pre>
对于这个问题,参考:
http://stackoverflow.com/questions/924451/jstl-access-a-map-value-by-key
Basically autoboxing puts an Integer object into the Map. ie:
map.put(new Integer(0), "myValue")
也就是说,如果map的key是数字类型,自动装箱会把数字转化成Integer。
EL (Expressions Languages) evaluates 0 as a Long and thus goes looking for a Long as the key in the map. ie it evaluates:
map.get(new Long(0))
当从map里面取的时候,它会把数字key的类型当做是Long。
【结论】我们在往map里面放数据的时候,需要明确的指定key是Long类型,才能正确取出数据来。
Just another helpful hint in addition to the above comment would be when you have a string value contained in some variable such as a request parameter.
In this case, passing this in will also result in JSTL keying the value of say "1" as a sting and as such no match being found in a Map hashmap.
One way to get around this is to do something like this.
<c:set var="longKey" value="${param.selectedIndex + 0}"/><!--如此丑陋的解决方式!-->
This will now be treated as a Long object and then has a chance to match an object when it is contained withing the map Map or whatever.
Then, continue as usual with something like:${map[longKey]}
同样,对于我们的问题:很显然,<c:set var="key" value="1" />是把1当成了字符串,因此<c:out value="${userMap2[key]}" />就取不到数据了!我们要做的就是强制把key的类型转化成数字类型:<c:out value="${userMap2[key+0]}" />。
虽然很ugly,终归算是解决问题了!
</pre>
--------------速查备忘----------------<br/>
---------------String---------------<br/>
<%
pageContext.setAttribute("op","add"); 
%>
<c:if test="${op == 'add'}">
 op = "add"
</c:if>
<c:if test="${op != 'add'}">
 op != "add"
</c:if> <br/>
<%
pageContext.setAttribute("email",""); 
%>
<c:if test="${empty email}">
 email = empty
</c:if>
<c:if test="${!empty email}">
 email != empty
</c:if><br/>
-------------null---------------<br/>
<%
pageContext.setAttribute("host",null); 
%>
<c:if test="${host == null}">
 host == null
</c:if>
<c:if test="${host != null }">
 host != null
</c:if> <br/>
<c:if test="${empty host}">
 host = empty
</c:if>
<c:if test="${! empty host}">
 host != empty
</c:if> <br/>
【注意】null可以用empty,也可以用null来判断<br/>
-------------boolean---------------<br/>
<%
pageContext.setAttribute("verified",true); 
%>
<c:if test="${verified}">
 verified == true
</c:if>
<c:if test="${! verified }">
 verified == false
</c:if> <br/>
<c:set var="hasError" value="true" />
<c:if test="${hasError}">
 hasError = true
</c:if>
<c:if test="${!hasError}">
 hasError = fasle
</c:if><br/>
-------------int---------------<br/>
<%
pageContext.setAttribute("type",Integer.valueOf(1)); 
%>
<c:if test="${type == 1}">
 type == 1
</c:if>
<c:if test="${type != 1 }">
 type != 1
</c:if> <br/>
<c:if test="${type > 0 and type < 2}">
 type > 0 and type < 2
</c:if><br/>
-------------if/else---------------<br/>
<%
pageContext.setAttribute("user",null); 
%>
<c:choose>
 <c:when test="${empty user or user.id == 1}">
  empty user or user.id == 1
 </c:when>
 <c:otherwise>
  not empty user and user.id != 1
 </c:otherwise>
</c:choose><br/>
-------------list----------------<br/>
<%
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("yes");
pageContext.setAttribute("list",list); 
%>
<c:if test="${fn:length(list) > 0}"><!--为什么不能直接用size来访问?悲哀!-->
 list.size > 0
</c:if>
<c:if test="${fn:length(list) <= 0}">
 list.size <= 0
</c:if> 
<br/>
<c:forEach var="out_item" items="${list}" varStatus="out_status" step="2" begin="0">
 ${out_item}
 <c:forEach var="in_item" items="${list}" varStatus="in_status" begin="${out_status.index+1}" end="${out_status.index+1}" >
 ${in_item}
    </c:forEach>
    <br/>
</c:forEach>
【注意】通过两个循环,每次输出多个元素<br/>
really ugly!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值