【问题标题】:How to pass a null variable into a Spring Expression in JSP如何将空变量传递给 JSP 中的 Spring 表达式
【发布时间】:2013-04-23 18:00:47
【问题描述】:

我在 JSP 中使用<spring:eval> 标记:

<spring:eval expression="'today is ' + today" />

today 是 java.util.Date。一切正常,只要今天变量不为空。当today 为空时,我得到 ​​p> org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Field or property 'today' can be found on null org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:243) org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:112) org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:107) org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:70) org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:102) org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:98) org.springframework.web.servlet.tags.EvalTag.doEndTag(EvalTag.java:126) org.apache.jsp.WEB_002dINF.views.admin.inbox_jsp._jspx_meth_s_005feval_005f1(inbox_jsp.java:195) org.apache.jsp.WEB_002dINF.views.admin.inbox_jsp._jspService(inbox_jsp.java:120) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) javax.servlet.http.HttpServlet.service(HttpServlet.java:728) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334) javax.servlet.http.HttpServlet.service(HttpServlet.java:728) org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:954) org.apache.jasper.runtime.PageContextImpl.doInclude(PageContextImpl.java:684) org.apache.jasper.runtime.PageContextImpl.include(PageContextImpl.java:678) org.apache.tiles.request.jsp.JspRequest.doInclude(JspRequest.java:123) org.apache.tiles.request.AbstractViewRequest.dispatch(AbstractViewRequest.java:47) org.apache.tiles.request.render.DispatchRenderer.render(DispatchRenderer.java:45) org.apache.tiles.request.render.ChainedDelegateRenderer.render(ChainedDelegateRenderer.java:68) org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:259) org.apache.tiles.template.InsertAttributeModel.renderAttribute(InsertAttributeModel.java:188) org.apache.tiles.template.InsertAttributeModel.execute(InsertAttributeModel.java:132) org.apache.tiles.jsp.taglib.InsertAttributeTag.doTag(InsertAttributeTag.java:299) org.apache.jsp.WEB_002dINF.views.common.main_002dlayout_jsp._jspx_meth_tiles_005finsertAttribute_005f2(main_002dlayout_jsp.java:243) org.apache.jsp.WEB_002dINF.views.common.main_002dlayout_jsp._jspService(main_002dlayout_jsp.java:103) org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) javax.servlet.http.HttpServlet.service(HttpServlet.java:728) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334) javax.servlet.http.HttpServlet.service(HttpServlet.java:728) org.apache.tiles.request.servlet.ServletRequest.forward(ServletRequest.java:265) org.apache.tiles.request.servlet.ServletRequest.doForward(ServletRequest.java:228) org.apache.tiles.request.AbstractClientRequest.dispatch(AbstractClientRequest.java:57) org.apache.tiles.request.render.DispatchRenderer.render(DispatchRenderer.java:45) org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:259) org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:397) org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:238) org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:221) org.apache.tiles.renderer.DefinitionRenderer.render(DefinitionRenderer.java:59) org.springframework.web.servlet.view.tiles3.TilesView.renderMergedOutputModel(TilesView.java:145) org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:264) org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1208) org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:939) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827) javax.servlet.http.HttpServlet.service(HttpServlet.java:621) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) javax.servlet.http.HttpServlet.service(HttpServlet.java:728) org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:152) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118) org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)

所以我尝试使用 Elvis 运算符检查 null:

<spring:eval expression="'today is ' + (today ?: 'null date!') " />

但这给出了完全相同的表达式。使用调试器进入 Spring PropertyOrFieldReference 代码后,我发现它似乎无法处理空变量。

普通的旧 JSTL 代码通过不打印任何内容来处理 null,这很好:

today is ${today}

如果 today 是 bean 的属性,它在 SPeL 中也可以正常工作:

<spring:eval expression="'today is ' + myBean.today" />

这会按预期产生字符串“today is null”。在这个简单的例子中,当变量为空时,我可以使用 JSTL 围绕我的 <spring:eval> 标记进行分支,但我真正需要能够做的是使用 <spring:eval> 执行一个具有多个变量的静态函数,任何其中可以合法地为空。问题是,SPeL 似乎无法正确解析为 null 的变量。

【问题讨论】:

  • 试试"'today is ' + (today is null?'null date!':today) " /> 甚至'today is' + today?
  • 感谢您的想法 - 第一个无法解析,因为 is 不是关键字。我认为你做的 SQL 太多了... :) 但是,如果我用 == 替换它,它会失败并出现相同的异常(与 Elvis 运算符不起作用的原因相同)。第二个不解析,因为它认为? 是三元运算符的开头。

标签: jsp spring-el


【解决方案1】:

EL 没问题。范围不明确。 Spring连变量都找不到。

将此用于请求范围:

<spring:eval expression="'today is ' + requestScope['today']" />

将此用于会话范围:

<spring:eval expression="'today is ' + sessionScope['today']" />

【讨论】:

  • 这确实解决了这个问题,所以我感谢你。但是,我只需要对可能为空的变量执行此操作似乎很奇怪(而且有点令人不安)。如果 today 变量有一个非空值,那么 Spring 可以很好地解析裸变量名。这是我所期望的。毕竟,在 JSP EL 中,它首先查找页面范围内的标识符,然后查找请求、会话等。如果找不到,则表达式的计算结果为 null。它不需要您指定范围。为什么 Spring 不能做到这一点?
  • 其实问题的症结似乎是一个bug。 org.springframework.web.servlet.tags.EvalTag.JspPropertyAccessor 的 canRead() 方法依赖于 pageContext.findAttribute()。它假定如果 findAttribute() 返回 null,则该属性未设置,因此不可读。因此它无法处理存在属性但具有空值的情况。也许更好的测试是测试 pageContext.getAttributesScope() 的返回值,看看它是否设置在任何范围内(即 - 返回值 > 0)。
猜你喜欢
  • 1970-01-01
  • 2013-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-08
相关资源
最近更新 更多