帮调一个奇怪的jsp显示数据的bug

struts2项目中,同事这样描述了一个bug:

在后台action中执行了一段逻辑A,再调用函数B,该函数为Action中的对象C赋值。在Action中打印C的各字段值正常,jsp页面中,使用el表达式显示C各字段的值,其中字段1有值,字段2无值。

另外一段Action函数中,无逻辑A,后续调用函数B等部分完全一致,返回同一个jsp页面,在前端可以正确显示所有字段的值。

经过大量调试无果后,我介入。过程如下:

  • 将页面上的字段值作各种替换,如输出字段1的部分改为输出字段2,或相反。此步骤是为了排除那种由于视线盲点死活都无法发现的拼写错误。无果。
  • 去掉逻辑A,运行,可以正常显示。恢复逻辑A,又变成异常情况。

至此基本确定错误范围是逻辑A,但逻辑A只是简单的新建变量、赋值等操作,看上去并不像会导致莫名其妙异常的那种代码。

又仔细看了看前端代码,发现其使用方式是用一个struts的iterator标签嵌套了一堆el表达式,el表达式使用的是struts iterator标签中定义的循环变量。再查后发现,该循环变量与逻辑A中的操作的某个变量重名了。所以页面上显示的是逻辑A中操作变量的值。

窗户纸捅破了,其实也没什么太高的技术含量。但调试代码中暴露的问题确实也挺让人头疼。

分而治之的思路如果掌握了,知道先把无关代码都注释了再调能减少很多猜测分支,调bug的思路会大大清晰。

所谓的相同逻辑在两段函数中运行的结果一个正确一个不正确,实际上这两种情况下jsp页面中根本就是访问了两组变量,但debug一下午,测试数据都是完全相同的那一种情况,姓名全叫张三……

不知道给变量规律化起名字的意义,起码循环变量都加个temp前缀,单数复数一个加s一个不加。变量名的起名规则就是,在定义变量的代码处向上数10行,找一个眼熟的名字,这……

一篇充满怨念的记录,项目规模上去之后,事事掌控的模式已经不可行了,分工之后,满眼都是这种无聊的问题。团队建设,看来还任重道远。

===

最近总是精神焦虑,无法集中精力想问题,效率有了很大的降低。生活中的杂事很多,还是要努力克服。黎明不远,加油!

JSP页面中,根据ID获取对象的语法糖封装

需求:

经常需要在jsp页面中,根据id获取某Model的实例,用于显示其某个属性。如:人事管理系统中,大部分的页面都需要根据id获取人员信息,显示姓名、性别等不同的属性。如果都在后台取得之后,用servlet api或者mvc框架的api放到request中,过于繁琐,会造成大量的冗余代码。

解决方案:

在application中放置假map,key为id(或者其他需要频繁查询的key字段),value为根据key查询出的对象。这样,就可以在jsp页面中用el表达式访问map的语法,获取到该对象,并进一步获取其属性。

具体实现方法为:项目启动时,在application域中放置一个实现Map接口的匿名类(可采用Listener方式),只需要重写其get函数。如:

public void contextInitialized(ServletContextEvent contextEvent)
        {
                contextEvent.getServletContext().setAttribute(“modelPoolById”, new HashMap<Long, Model>()
                {
                        /**
                         *
                         */
                        private static final long serialVersionUID = 1L;

                        @Override
                        public Org get(Object key)
                        {
                               //通过Dao层访问该方法并返回
                        }

                });

……

 

在jsp页面中,可以直接使用el表达式访问:${modelPoolById[id].xxx}

如果项目需要,可以在保证访问接口不变的情况下,增加缓存等其他复杂逻辑。

比写JSP标签的方式更轻量,只封装了查询逻辑,并没有限制要显示那些字段,而是提供了一个完整的对象。并且,嵌套给其它标签使用方面也更方便。