您的位置:首页 > 移动开发

JSP在请求监听器中调用application的自定义属性时,消除空指针报错(java.lang.NullPointerException)的方法

2016-09-16 17:55 1326 查看
【问题背景】

  JSP开发中,利用Listener监听器对象,可以记录某网站访客的到访时间、访客IP地址等信息。

  注意这里的一个访客对应一个session对象,而不是具体的某人。

  本例中,统计了两类信息:一是访客相关信息;二是浏览历史信息。

   1、前者字段包括:到访ID(主键,整型,自动递增)、到访时间、离开时间(session过期时刻)、IP地址、来源网址等信息,存入数据库visitorDB的visitor表中。通过一个【历史访客】按钮,将表中内容以“历史访客表”的形式显示到一个JSP页面。

   2、后者字段包括:浏览记录ID(主键,整型,自动递增)、到访ID(即visitor表的主键),访问页面时刻,和浏览页面URL。所有记录存入history表中,通过一个【浏览轨迹】按钮,将表中内容以“访问记录表”的形式显示到另一个JSP页面。

  由于出现了到访ID这个外键,在读写history表时,需要调用当前session对应的访客v的主键值。实现方法大致两种:

   (1)在HashMap<String, Visitor>中,调用当前sessionID的键值对,用map.get(sessionID)获取该Visitor对象。这里的 key=sessionID=arg0.getSession().getId();

   (2)将当前访客Visitor visitorCurrent单独保存到session的自定义属性"USER"中,再到requestInitialized()方法中调用该属性值:

    保存:

     HttpSession session = arg0.getSession();

     session.setAttribute("USER",visitorCurrent);

    提取:

     Visitor vCurrent =(Visitor) request.getSession().getAttribute("USER");

  本例使用方法(2)。

【问题描述】

  按照方法(2)保存当前访客对象visitorCurrent,本应保存到session中,结果根据自动提示错误保存到了application中,写成了:Visitor vCurrent = (Visitor) request.getServletContext().getAttribute("USER");

  于是将错就错,将保存语句也一并改成:

   ServletContext application = arg0.getSession().getServletContext();

   application.setAttribute("USER",visitorCurrent);

  启动服务器验证代码,结果在调用访客ID时报空指针错误:java.lang.NullPointerException,问题所在代码为:

   h.setVisitId( vCurrent.getId() );

【原因分析】

  没弄清各监听方法的执行顺序。启动服务器时,Listener先调用“监听服务器启动”的方法contextInitialized(),然后调用“监听页面请求启动”的方法requestInitialized(),处理请求过程中,会根据需要创建session对象,由此触发“监听session创建”的方法sessionCreated()。

  这样,报空指针估计和异步执行有关,调用vCurrent的id值的时候,vCurrent还没从定义在session中的属性“USER”中,获取到Visitor对象,因此出现空指针。要消除该异常,

   ①要么调用前判定有没有提前保存,有才赋值,没有则追加;

   ②要么在服务器启动时就预先保存一个空的Visitor对象visitorEmpty;

  优先选用①,因为②中的空Visitor意味着此时的访客ID=0,与实际情况不符;而①可以指定当前sessionID对应的Visitor,因此更合理。

【解决方案】

  在h.setVisitId( vCurrent.getId() );之前加一句if判定语句,如果“USER”属性值为空,则追加sessionID对应的Visitor对象:

ServletContext app = arg0.getServletContext();
if( app.getAttribute( "USER" ) == null ) {
  @SuppressWarnings( "unchecked" )
  HashMap<String, Visitor> map = ( HashMap<String, Visitor> ) app.getAttribute( "ONLINE" );
  Visitor vCurrent = map.get( request.getSession().getId() );
  arg0.getServletContext().setAttribute("USER", vCurrent);
}
Visitor vNeeded = (Visitor) app.getAttribute("USER");
h.setVisitId( vNeeded.getId() );

  验证代码,空指针错误消除,显示的访客ID也没有出现0值错误,问题解决。

【注意事项】

  本例将错就错,把外键所在的对象vCurrent保存到application属性中,虽然通过验证,但逻辑上仍有重大问题。因为application的属性只有“USER”一个,当多个用户同时调用该属性值时,只能得到一个最晚请求调用的当前访客,之前的访客对象将被后来者覆盖。因此保存到当前session的属性中,才能避免相互覆盖,不同的访客才能看到各自对应的浏览记录。

  本例旨在说明至少以下两个问题:

   1、requestInitialized()方法可能先于sessionCreated()执行,若跨方法调用值报告空指针异常(java.lang.NullPointerException);

   2、明确出现空指针异常的原因,并知道如何修改代码消除该异常;但最终还要考虑实际处理逻辑。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐