详解JSP页面jsp:setProperty标签使用表达式赋值报500错误的原因

错误示例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<jsp:useBean id="currentDate" class="java.util.Date" scope="application"/>
<%
    String value=request.getParameter("timeValues");
    System.out.println(value);
%>
<jsp:setProperty name="currentDate" property="time" value="<%=value%>"/>
<jsp:getProperty name="currentDate" property="time"/>
</body>
</html>

这个JSP页面进行访问时会报500错误,注意访问链接上带上timeValues参数进行测试,我这儿就不放测试结果了。至于有些说将value="<%=value>"的双引号改成单引号,这种做法在这个示例里面没用,也许在其他某些情况下有用,等下我会说明原因。

现在我将<jsp:setProperty name="currentDate" property="time" value="<%=value%>"/>这行代码改为如下所示<jsp:setProperty name="currentDate" property="time" value="123456789"/>直接对value进行赋值,按照上面的链接进行访问测试,结果访问成功,没报500错误。产生这种差异的原因最后在看JSP转换成的源代码时才发现。因为这2种方式产生的源代码调用了不一样的接口!!!

1.第一种情况:<jsp:setProperty name="currentDate" property="time" value="<%=value%>"/>产生的源代码片段如下:

String value=request.getParameter("timeValues");
    System.out.println(value);

      out.write('\r');
      out.write('\n');
      org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty
(_jspx_page_context.findAttribute("currentDate"), "time",value);
      out.write('\r');
      out.write('\n');
      out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((java.util.Date)_jspx_page_context.findAttribute("currentDate")).getTime())));

从代码片段可以看到,调用了一个handleSetProperty的方法进行赋值,这个接口的完整方法如下:

    public static void handleSetProperty(Object bean, String prop, Object value) throws JasperException {
        try {
            Method method = getWriteMethod(bean.getClass(), prop);
            method.invoke(bean, value);
        } catch (Exception var5) {
            Throwable thr = ExceptionUtils.unwrapInvocationTargetException(var5);
            ExceptionUtils.handleThrowable(thr);
            throw new JasperException(var5);
        }
    }

现在详解这3个参数的作用。1.bean:这个参数是上例中的currentDate对象,这个对象在这个例子中是java.util.Date类型的;2.prop:这个参数是属性名称,在这儿是time;3.value:本例中request.getParameter("timeValues")的结果,也就是我们要设置的属性值。

到这儿疑问就来了,从代码看起来没问题啊,获得Class对象的一个写属性方法,然后对bean对象进行写操作,问题其实就出在这个写操作上,我接下来追踪一下代码,在执行invoke时的变量数据如下:(访问时timeValues=123456798)

从数据看来是没问题的,写方法也找到了,bean对象也没问题,value也和设置的值相同="123456789",结果这步一执行就异常,让我们看报的是什么异常。

什么!!!type不匹配,原来是因为time是long类型的,这个value是string类型的,肯定执行要异常啊。问题的原因算是找到了,要解决这个问题的方法那就是千万种了,可以在JSP页面表示式里面转类型Long.parseLong()。有人也许会问,即便转了类型也有双引号标识这是个字符串啊,如果你仔细看了代码,你就会发现上例handleSetProperty方法里最后那个value参数传的是一个变量,可没规定一定是一个字符串。就像上例传的是value变量一样,就结果而言,表达式里面传的是什么类型的参数,源代码里面那个参数就是什么类型的!!!

2.第二种情况:<jsp:setProperty name="currentDate" property="time" value="123456"/>产生的源代码片段如下:

 String value=request.getParameter("timeValues");
    System.out.println(value);

      out.write('\r');
      out.write('\n');
      org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("currentDate"), "time", "123456", null, null, false);
      out.write('\r');
      out.write('\n');
      out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((java.util.Date)_jspx_page_context.findAttribute("currentDate")).getTime())));

从代码中,可以很清楚的看到,很坑爹的这个调用的接口变了,变了,变了!!!这个接口的完整代码如下:

   public static void introspecthelper(Object bean, String prop, String value, ServletRequest request, String param, boolean ignoreMethodNF) throws JasperException {
        Method method = null;
        Class<?> type = null;
        Class propertyEditorClass = null;

        try {
            BeanInfo info = Introspector.getBeanInfo(bean.getClass());
            if (info != null) {
                PropertyDescriptor[] pd = info.getPropertyDescriptors();
                //这个循环用于找到time属性,并获得time属性的写方法以及time属性的类型
                for(int i = 0; i < pd.length; ++i) {
                    if (pd[i].getName().equals(prop)) {
                        method = pd[i].getWriteMethod();
                        type = pd[i].getPropertyType();
                        propertyEditorClass = pd[i].getPropertyEditorClass();
                        break;
                    }
                }
            }

            if (method != null && type != null) {
                if (type.isArray()) {
                    if (request == null) {
                        throw new JasperException(Localizer.getMessage("jsp.error.beans.setproperty.noindexset"));
                    }

                    Class<?> t = type.getComponentType();
                    String[] values = request.getParameterValues(param);
                    if (values == null) {
                        return;
                    }

                    if (t.equals(String.class)) {
                        method.invoke(bean, values);
                    } else {
                        createTypedArray(prop, bean, method, values, t, propertyEditorClass);
                    }
                } else {
                    if (value == null || param != null && value.equals("")) {
                        return;
                    }
                    //convert方法用于类型转换,到此value都是字符串,转换之后类型变为
                    //上面得到的类型,即type 
                    Object oval = convert(prop, value, type, propertyEditorClass);
                    if (oval != null) {
                        method.invoke(bean, oval);
                    }
                }
            }
        } catch (Exception var12) {
            Throwable thr = ExceptionUtils.unwrapInvocationTargetException(var12);
            ExceptionUtils.handleThrowable(thr);
            throw new JasperException(var12);
        }

        if (!ignoreMethodNF && method == null) {
            if (type == null) {
                throw new JasperException(Localizer.getMessage("jsp.error.beans.noproperty", new Object[]{prop, bean.getClass().getName()}));
            } else {
                throw new JasperException(Localizer.getMessage("jsp.error.beans.nomethod.setproperty", new Object[]{prop, type.getName(), bean.getClass().getName()}));
            }
        }
    }

代码过长,不详细讲解了,不过代码不难,很容易看懂,注释的2点即为为什么这种方法不报错的原因,终究还是因为这种方法在最后进行了一个类型的判断与转换。

总结:说到底这种错误只是因为在使用表达式时的类型不匹配造成的,在某些情况下,比如属性为字符串,就能避免这种错误,给人造成一种"这种方法没错,肯定是哪儿操作不对的错觉",因此发现这种错误的原因才是根本的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值