
近几日,遇到一个困惑了我很久的异常,是浏览器页面向Tomcat服务器发起HTTP请求时,服务器发还回来的一处异常
java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "javax.servlet.ServletContext.getAttribute(String)" is null
首先来说一下我是在做什么的过程中遇到这个问题
HttpSession这个接口,然后通过重写内部的sessionCreated()和sessionDestroyed()方法去判定当前页面的用户接入与离开
不过呢,当然在重新启动Smart Tomcat的时候,就出现了下面的情况,请看【问题描述】~
HTTP状态500 - 内部服务器错误,这是HTTP的一个状态码,服务器发还回这个状态的话表示是【我们在后端的代码出问题了,异常实在代码中抛出的】
getAttrubute(String)获取到的内容是空的NullPointerException空指针异常的问题,这个问题其实还挺大的,如果有看过我 指针入门到进阶教程就可以知道对于空指针来说其实是很危险的,其造成的后果堪比【野指针】知道问题在哪了,接下去就让我们到IDEA中的查找一下后端的代码吧【文末会给出】

Spring Boot那么多的注解,还是好理解的null的话也就是表示根本没有去进行一个统计,即这个【online】压根就没有更新,那监听器这里为什么没有监听到呢?我一开始也非常纳闷这一块╮(╯▽╰)╭
于是这个时候我只能通过调试去进行观察了
online的地方打一个断点,然后在Chrome浏览器页面前端进行用户登录点击
online还是为【null】,所以就代表当前这个用户是第一次接入的,此时会将这个online的值设为1

obj已经不为null了,所以不会进入第一个分支,而是会进入第二个if分支
attributes中的去找到这个online观察,就可以看到它的值为2,这也就是意味着当前这个网页的访问者有2位了
online值为2,表明此时已经有2个人在线了,那么当这个用户再接入的时候,online的值就会变为3
online确实变为3了,也就表示此时有3个人正在访问这个页面

但此时当我将Tomcat去进行一个重启后,再进行访问的话,就会造成下面这样的错误

🤔因为服务器这边重启了,所以之前保存的用户信息都不见了,但是呢这个时候客户端却不知道,还是以它之前的那个状态在进行访问,因为服务器之前在第一次访问的时候已经给了每个连接进来的用户创建了一个会话,并且生成了一个SessionId,分别代表了它们各自的身份,而每个SessionId又是存放在浏览器Cookie中的,因为前后端这里的逻辑就对接不上了,服务器完全不认识这个人,所以便返回给它一个【内部服务器错误】👈
所以经过我上面的一番思考,便想到了可能和浏览器这边的Cookie有点关系,于是我就去翻找了每个浏览器的Cookie
SessionId,就保存在当前的这份【Cookie】中,于是当服务器重启后再度去进行访问的时候,那Tomcat这只猫🐱便说:“你谁呀,我不认识你呀”
那么问题其实就是出在这个Cookie上,那一定有同学会问:这该怎么解决呢?
count去接受强转后的在线人数,而是先通过一个【Object】父类去接收一下这个HttpSession对象,因为这个对象也是一个键值对的形式,是我们程序员自己构造的,因此其返回值类型就要是一个总的父类,可以接受任何种类的内容Object obj = req.getServletContext().getAttribute("online");
if (obj == null){
System.out.println("当前用户此前登录过");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("当前用户此前登录过,请清除浏览器缓存后再行登录
");
}
int count = (int)obj;
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("在线人数为:" + count);

但是,浏览器缓存要怎么清理呢?
温馨提示:每个浏览器都是不一样的,读者可自己试着摸索

然后展示一下整体代码,可供测试
前端登录页面
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<form action="onlineUsers", method="post">
<label>用户名label>
<input type="text" name="userName">
<input type="submit" value="登录">
form>
body>
html>
监听器实现类
import javax.servlet.ServletContext;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class UsersCount implements HttpSessionListener{
@Override
public void sessionCreated(HttpSessionEvent event) {
System.out.println("会话创建");
// 1.获取ServletContext对象,在整个容器中只有一份
ServletContext servletContext = event.getSession().getServletContext();
System.out.println(event.getSession().getId());
// 2.在线人数
Object obj = servletContext.getAttribute("online");
// 3.判断当前用户是否是第一个在线的
if(obj == null){
servletContext.setAttribute("online", 1);
}else{
int i = (int)obj; // 若其不是第一个上线的,就 + 1
servletContext.setAttribute("online", i + 1);
}
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
System.out.println("会话销毁");
event.getSession().invalidate();
// 1.获取ServletContext对象,在整个容器中只有一份
ServletContext servletContext = event.getSession().getServletContext();
// 2.在线人数
Object obj = servletContext.getAttribute("online");
if(obj == null){
servletContext.setAttribute("online", 0);
}else{
int i = (int)obj; // 若其不是第一个上线的,就 + 1
servletContext.setAttribute("online", i - 1);
}
}
}
登录验证的Servlet类
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/onlineUsers")
public class loginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userName = req.getParameter("userName");
if(!userName.equals("zhangsan")){
resp.sendRedirect("login.html");
}
HttpSession httpSession = req.getSession(true);
httpSession.setAttribute("userName", userName);
resp.sendRedirect("show");
}
}
展示结果处理是Servlet类
@WebServlet("/show")
public class showServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession httpSession = req.getSession(false);
if(httpSession == null){
System.out.println("未登录,请重新登录");
resp.sendRedirect("login.html");
return;
}
Object obj = req.getServletContext().getAttribute("online");
if (obj == null){
System.out.println("当前用户此前登录过");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("当前用户此前登录过,请清除浏览器缓存后再行登录
");
}
int count = (int)obj;
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("在线人数为:" + count);
}
}
以上就是本文所排查的问题,你学会了吗?我们来回顾一下
2023年5月25日晚8点记
