获取servlet上下文时出现空指针异常

3
我知道这个问题被问了无数次,也有500万种答案——其中一些非常有信息量。但是没有一个能解决这个问题。 我的目标与其他人类似——我希望在Web应用程序运行环境中访问文件——图像、SVG文件、模板等。如果只是硬编码目录路径,我可以让它正常工作。然而,我想让我的servlet可移植,并使用相对引用来访问这些资源——即使仅仅因为我在Windows上开发,在Linux上部署。 基本问题是getServletContext()为空,我无法确定原因。 下面是错误消息、产生它的代码,以及环境详细信息。在开发和生产中都会产生相同的错误。如果需要,我很乐意提供任何额外的细节。 请解释一下我需要做什么才能让它工作?我将永远感激不尽。谢谢!
     SEVERE: Servlet.service() for servlet [jsp] in context with path [/HelloWorld] threw exception [An exception occurred processing JSP page /hello.jsp at line 19

     16: <title>Hello World</title>
     17: </head>
     18: <body>
     19:  <%=wtGreet.getGreeting()%> 
     20: </body>
     21: </html>


    Stacktrace:] with root cause
    java.lang.NullPointerException
at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:125)
at HelloWorld.Greeting.getGreeting(Greeting.java:23)
at org.apache.jsp.hello_jsp._jspService(hello_jsp.java:91)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

“HelloWorld”应用程序可以运行,但会产生一个不期望的错误,跟真正的情况完全一样。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF 8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<jsp:useBean id="wtGreet" scope="page"
class="HelloWorld.Greeting">
<jsp:setProperty name="wtGreet" property="who" value="World"/>
<jsp:setProperty name="wtGreet" property="greet" value="Hello"/>
</jsp:useBean> 
<jsp:setProperty name="wtGreet" property="*"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Hello World</title>
</head>
<body>
 <%=wtGreet.getGreeting()%>
</body>
</html>

JSP调用的Servlet
package HelloWorld;

import javax.servlet.http.HttpServlet;

public class Greeting extends HttpServlet {

    private static final long serialVersionUID = 1298516959968350334L;
    private String who;
    private String greet;

    public void setWho(String who) {
        this.who = who;
    }

    public void setGreet(String greet) {
        this.greet = greet;
    }

    public String getGreeting() {
        System.out.println("getServletContext() == null :" + getServletContext().getContextPath());
        return "<p>" + this.greet + " " + this.who + "</P>";
    }
}

开发环境: Windows Eclipse JEE Apache Tomcat 7 JRE 7
生产环境: Linux Apache Tomcat 7 JRE 8
2个回答

4
基于您的堆栈跟踪中的最后一个元素
at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:125)

javax.servlet.GenericServlet 类的第 125 行调用了 getServletContext() 方法,导致异常发生。

如果 getServletContext() 返回了 null,那么最后一条堆栈跟踪元素将是:

at HelloWorld.Greeting.getGreeting(Greeting.java:23)

根据javax.servlet.GenericServlet代码,方法getServletConfig()返回null,即您的servlet未配置。

这可能是因为您在jsp中将servlet误用为bean。

<jsp:useBean id="wtGreet" scope="page" class="HelloWorld.Greeting">

Servlet没有正确初始化,因此不能这样使用。您可能希望使用一个简单的JavaBean,并使其具有一个getGreeting()方法。

要在您的jsp中获取ServletContext,可以使用内置对象application,在此处查看jsp中其他可用的内置对象。


你正确地理解了我误解的核心。这帮助我构建我的研究以得出答案。基本解决方案集中在模型1与模型2的概念上。我在某个地方实现了一个意外的模型,但并没有真正符合任何模型(我的前提是MVC-将视图与模型分离)。我的理解是,模型2是普遍的最佳实践,因此我的目标是实现这种模式。如果您能分享任何观点,我将不胜感激。谢谢。 - Threadid
任何对此感兴趣的人都可以参考以下相关资料:这里 - Threadid

0

尽管最终的解决方案是实现模型2模式(完成后将包括在内),但对于所提出的问题,有一个很好的工作答案。感谢A4L指明了方向。

从理解jsp引擎将jsp编译成servlet并将其加载到servlet引擎中的角度出发,可以使用jsp隐式对象来访问已实例化的javax.servlet对象。

HelloWorld示例更改如下: 1)删除import javax.servlet.http.HttpServlet;和extends HttpServlet,因为这没有任何作用。 2)添加一个类型为ServletContext的属性,并使用jsp页面的setter填充该属性。

通过jsp隐式对象,任何可用于servlet的对象都可以对bean可用。

jsp

{<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<jsp:useBean id="wtGreet" scope="page"
class="HelloWorld.Greeting">
<jsp:setProperty name="wtGreet" property="who" value="World"/>
<jsp:setProperty name="wtGreet" property="greet" value="Hello"/>
</jsp:useBean> 
<jsp:setProperty name="wtGreet" property="*"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello World</title>
</head>
<body>
<%wtGreet.setSc(application.getContext("/HelloWorld"));%>
<%=wtGreet.getGreeting()%>
</body>
</html>}

Bean

package HelloWorld;
import javax.servlet.ServletContext;
public class Greeting {
private String who;
private String greet;
private ServletContext sc;
public void setSc(ServletContext sc) {
    this.sc = sc;
}
public void setWho(String who) {
    this.who = who;
}
public void setGreet(String greet) {
    this.greet = greet;
}
public String getGreeting() {
    return "<p>" + this.greet + " " + this.who + " from \"Context Path\" " + sc.getContextPath() + "</P>";
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接