• JSP隐含变量和Spring中Model在EL表达式中的读取顺序


    偶然中存在着必然,必然中存在着偶然

    偶然出现的bug,必然存是由代码的不合理甚至错误的

    代码逻辑越长,越复杂,就越容易出现bug

    之前项目里几次偶然出现了一个bug,简单的描述就是第一次新增了之后进行一个B操作,之后在新增一次,页面中的一个隐含变量会"记住"这个新增之后的id,因为这个需要连续两次新增且在第一次新增之后进行B操作之后才会出现,所以很长时间里面都是偶然出现.

    定位问题的过程就是进行很多次的操作,然后逐个排除.尝试自己的猜测,再次进行代码级的排除.定位这种问题一定要有一定的测试量.就像有一个入口和一个出口的迷宫,答案就是有偶发性bug的路径.

    最后发现问题是当时model中的id为null,而在B操作中session中也存了id.

    下面一起来看一下,El读取变量的顺序

    后台代码

    package com.my.innerParam.test;

    import javax.servlet.ServletConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import javax.servlet.jsp.JspWriter;
    import javax.servlet.jsp.PageContext;

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;

    /**
     * 测试几个内置变量中在EL读取的顺序
     * @author rocky
     *
     */
    @Controller
    public class InnerParam
    {
        @RequestMapping("/innerParamTest")
        public String innerParamTest(HttpServletRequest request,HttpServletResponse response,Model model)
        {
            HttpSession session = request.getSession();
            session.setAttribute("session", "session223");
            
            ServletContext application = request.getServletContext();
           // application.setInitParameter("appicationParam", "appicationParam");
            //Initialization parameters can not be set after the context has been initialized
            application.setAttribute("appicationAttr", "applicationAttr");
            request.setAttribute("request", "request");
           
            
            model.addAttribute("model", "model123");
            return "/testParam/testParam1";
        }
        
        //当变量名字相同时判断EL表达式用哪一个
        @RequestMapping("/innerParamTest2")
        public String innerParamTest2(HttpServletRequest request,HttpServletResponse response,Model model)
        {
            HttpSession session = request.getSession();
            session.setAttribute("test", "session223");
            
            ServletContext application = request.getServletContext();
           // application.setInitParameter("appicationParam", "appicationParam");
            //Initialization parameters can not be set after the context has been initialized
            application.setAttribute("test", "applicationAttr");
     
            request.setAttribute("test", "request");
            model.addAttribute("test", "model123");
            return "/testParam/testParam2";
        }
        
        //当model是null的时候
        @RequestMapping("/innerParamTest3")
        public String innerParamTest3(HttpServletRequest request,HttpServletResponse response,Model model)
        {
            HttpSession session = request.getSession();
            session.setAttribute("test", "session223");
            
            ServletContext application = request.getServletContext();
           // application.setInitParameter("appicationParam", "appicationParam");
            //Initialization parameters can not be set after the context has been initialized
            application.setAttribute("test", "applicationAttr");
     
            request.setAttribute("test", "request");
            model.addAttribute("test", null);
            return "/testParam/testParam3";
        }
    }

    第一种情况,显示

    代码

    <h3>session : ${session}</h3>
    <h3>appicationAttr : '${appicationAttr}'</h3>
    <h3>appicationParam : '${appicationParam}'</h3>
    <h3>request : '${request}'</h3>
    <h3>model : '${model}'</h3> 运行结果

    session : session223

    
    

    appicationAttr : 'applicationAttr'

    
    

    appicationParam : ''

    
    

    request : 'request'

    
    

    model : 'model123'

    
    

    第二,变量名字相同时

    <h3>session : ${test}</h3>
    <h3>appicationAttr : '${test}'</h3>
    <h3>appicationParam : '${test}'</h3>
    <h3>request : '${test}'</h3>
    <h3>model : '${test}'</h3> 运行结果

    session : model123

    
    

    appicationAttr : 'model123'

    
    

    appicationParam : 'model123'

    
    

    request : 'model123'

    
    

    model : 'model123'

    
    

    第三,当model为null时

    <h3>session : ${test}</h3>
    <h3>appicationAttr : '${test}'</h3>
    <h3>appicationParam : '${test}'</h3>
    <h3>request : '${test}'</h3>
    <h3>model : '${test}'</h3>
    运行结果

    session : session223

    
    

    appicationAttr : 'session223'

    
    

    appicationParam : 'session223'

    
    

    request : 'session223'

    
    

    model : 'session223'

    
    

    第四,当session也为null时

    <h3>session : ${test}</h3>
    <h3>appicationAttr : '${test}'</h3>
    <h3>appicationParam : '${test}'</h3>
    <h3>request : '${test}'</h3>
    <h3>model : '${test}'</h3>
    
    运行结果
    session : applicationAttr
    
    appicationAttr : 'applicationAttr'
    
    appicationParam : 'applicationAttr'
    
    request : 'applicationAttr'
    
    model : 'applicationAttr'

    结论:1.model > session >application>requset的,其他的就不测试了,这几个是最长用的.

    2.慎重使用session变量,这个范围太大了,如果因为一个模块把变量存在session中实现起来更容易,就这样做了,那么这就很容易为后面埋下bug.

    如果把变量放到session里,就说明它的作用域是session,它的有效范围是当前会话。
    
    所谓当前会话,就是指从用户打开浏览器开始,到用户关闭浏览器这中间的过程。这个过程可能包含多个
    
    请求响应。也就是说,只要用户不关浏览器,服务器就有办法知道这些请求是一个人发起的,整个过程被
    
    称为一个会话(session),而放到会话中的变量,就可以在当前会话的所有请求里使用。
    
    如果把变量放到application里,就说明它的作用域是application,它的有效范围是整个应用。
    
    整个应用是指从应用启动,到应用结束。我们没有说“从服务器启动,到服务器关闭”,是因为一个服务
    
    器可能部署多个应用,当然你关闭了服务器,就会把上面所有的应用都关闭了。
    
    application作用域里的变量,它们的存活时间是最长的,如果不进行手工删除,它们就一直可以使用。
    
    与上述三个不同的是,application里的变量可以被所有用户共用。如果用户甲的操作修改了application
    
    中的变量,用户乙访问时得到的是修改后的值。这在其他scope中都是不会发生的,page, request,

    参考blog:JSP九大内置对象及四个作用域

    3.熟悉jsp基础,已经常用的变量.

  • 相关阅读:
    面试90%都会翻车的高并发分布式事务,我劝你好好啃透!
    JVM最多支持多少个线程?你知道吗?
    利用注解 + 反射消除重复代码(Java项目)
    ASP.NET HTTP模拟提交通用类 GET POST
    UPW学习资料整理 .NET C# 转
    前端引擎初步设计稿 -通过配置生成动态页面 ,LandaSugar平台 .NET-C#-MVC
    分享一个ASP.NET 文件压缩解压类 C#
    验证码的种类与实现 C#封装类
    ASP.NET MVC 使用 IOC框架 AutoFac 自动释放数据库资源
    ASP.NET MVC权限验证 封装类
  • 原文地址:https://www.cnblogs.com/rocky-AGE-24/p/5816193.html
Copyright © 2020-2023  润新知