邮件/会话资源工厂在 Struts 应用程序中不起作用

Posted

技术标签:

【中文标题】邮件/会话资源工厂在 Struts 应用程序中不起作用【英文标题】:mail/Session Resource Factory does not work in Struts application 【发布时间】:2010-10-04 10:40:31 【问题描述】:

我想使用 Tomcat 6.0 提供的标准资源工厂,它为我创建 javax.mail.Sessions 实例。如JNDI Resource HOW-TO tutorial 中所述。

我的 META-INF/context.xml 看起来像:

<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true">
    <Resource name="mail/Session" 
          auth="Container" 
          type="javax.mail.Session" 
          mail.smtp.host="smtp.gmail.com"
          mail.smtp.port="587"
          mail.smtp.auth="true"
          mail.smtp.user="someone@gmail.com"
          mail.smtp.password="secretpassword" 
          mail.smtp.starttls.enable="true"/>    
</Context>

我的 WEB-INF/web.xml 中有下一个资源引用,就在 之前。 Web.xml 验证。我使用McDowell's way 进行了验证。

<resource-ref>
    <description>Resource reference to a factory for javax.mail.Session instances that may be used for sending electronic mail messages, preconfigured
    to connect to the appropiate SMTP server.
    </description>
    <res-ref-name>mail/Session</res-ref-name>
    <res-type>javax.mail.Session</res-type>
    <res-auth>Container</res-auth>
    </resource-ref>

我正在使用下一个代码片段访问我的 javax.mail.Session 对象。

Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session)envCtx.lookup("mail/Session");
System.out.println("HERE smtp.user: " + session.getProperty("mail.smtp.user"));

我在一个示例应用程序中对其进行了测试,它确实有效。不幸的是,当我将相同的代码移动到一个 struts 应用程序时,我在上面的打印语句中得到了 NULL。我在名为 mailer 的单例类中查找上下文(在我的 WEB-INF/classes 文件夹中定义),但如果我在 Struts 动作类中查找上下文,我会遇到同样的问题。

我一直在想有什么不同的地方才能找到问题。我的 struts 应用程序 web.xml 比简单应用程序的 web.xml 更复杂。它具有安全约束、过滤器和 Struts Servlet 配置。我将 resource-ref 定位在 servlet 定义之前。似乎资源引用被忽略了。

我还有一个问题。如果我在 myapp/WEB-INF/lib 文件夹中有 javax.mail.Session 所需的 mailapi.jar,我会得到:

java.lang.NoClassDefFoundError: javax/mail/Authenticator

如果我把它放在 $CATALINA_HOME/lib 中找到。

有什么想法吗?我使用struts和hibernate。或许与此有关。

调试

我尝试将调试属性放在上下文中进行调试

<Context reloadable="true" debug="99" ...  

但我没有看到任何有趣的东西。

01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: SessionListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log
INFO: ContextListener: contextInitialized()
01-feb-2009 17:39:09 org.apache.catalina.core.ApplicationContext log

我试过了:

Session session = (Session) initCtx.lookup("java:comp/env/mail/Session");

代替:

Context envCtx = (Context) initCtx.lookup("java:comp/env");
Session session = (Session)envCtx.lookup("mail/Session");

但我仍然得到一个 NULL Session 对象。

部分解决方案

当我将 Resource 元素放在 $CATALINA_HOME/conf/context.xml 文件中时,它可以工作。

【问题讨论】:

请注意,您不应在答案中添加更多信息,而应编辑问题。答案将随着任何投票赞成或反对而重新排列,因此添加它们的答案是不可识别的。对于有相同问题的人来说,对所有信息提出准确的问题也很有价值。 我不知道为什么,但是mail.smtp.password 对我不起作用(tomcat8),应该改用password 【参考方案1】:

JNDI 查找代码怪癖

我看到了多个找不到 JNDI 资源的问题。在 Websphere 上(我知道,你不使用它,但很高兴知道......)你会遇到问题

上下文 envCtx = (Context) initCtx.lookup("java:comp/env"); 会话会话 = (会话)envCtx.lookup("邮件/会话");

有效的(在 Websphere 上)是

会话会话 = (Session) initCtx.lookup("java:comp/env/mail/Session");

根据您在另一个答案中所写的内容,我知道这不是您的问题 - 我将其留在这里,以供以后在不同情况下遇到相同问题的人使用。

从自生线程中查找 JNDI 资源

此外,对 JNDI 资源的访问可能取决于查找资源的线程。据我记得,线程在 servlet api(或 Java EE 或相关领域)中没有很好地定义。它甚至可能是自愿和明确地未定义的。因此服务器提供 JNDI 资源不是强制性的在你自己产生的线程中(Websphere 再次咬我,我没有在这方面测试过 Tomcat6,早期版本用于为所有线程提供 JNDI 资源)

您已经写道,您正在从单例中查找 JNDI 资源。 如果您,在查找资源时,检查堆栈跟踪(在您的 IDE 中,通过抛出异常或与Thread.currentThread().getStacktrace() 混淆):是堆栈跟踪中是否有任何 Tomcat 连接器或者是您自己的 Thread 的 run() 方法之一位于堆栈跟踪的根目录 这将回答 Jacks 背后的问题询问您是否从 Action 类进行查找。 (见杰克的回答)

线程和调用环境第二部分

创建一个新的 Struts Action 并从那里调用您的 JNDI 查找代码,看看如果放置在靠近 struts 的地方并在 http 请求的处理中,这是否有效。如果在此处有效,请继续执行上述步骤。

web.xml 的有效性

此外,您可能希望查看 web.xml 的架构定义,以确保您的资源引用正确定位。 servlet 规范 2.4 可在 jcp.org 获得,并且应该足以检查,即使 tomcat 实现 2.5。

毕竟,我相信 tomcat6 会验证 web.xml,因此您可能已经将它放在正确的位置。 (不记得了,因为我的 IDEs 编辑器在我出错时会抱怨,我是否需要编写 web.xml)

Tomcat 调试选项

许多 context.xml 条目都遵循“调试”属性。虽然我相信低一位数的值就足够了,但我已经养成了将 'debug="99"' 添加到 'Context' 或其他元素等元素的习惯。您可能想看看这是否会产生一些有用的日志条目。

确保它不是类路径

由于您似乎从根本上改变了环境,确保您拥有所有必需的库 - 邮件 api 包含几个 jar。下载一个新副本并将 所有 库解压缩到 $CATALINA_HOME/lib。一旦它与那里的所有库一起使用,您可能会将未使用的东西拿走。

关于你的类路径问题

在 $CATALINA_HOME/lib 中找到类的原因是,连接是由服务器完成的(请记住 - 您已经在 context.xml 中定义了它,服务器会读取它以启动应用程序),因此 jar 必须在 servers 类路径上 - 而不仅仅是在应用程序上(有关更多信息,请参阅tomcat class loader HOWTO)

编辑:

关于您的部分解决方案

$CATALINA_HOME/conf/context.xml 包含全局“默认”上下文元素。这不是您希望应用程序特定配置的位置。

tomcat 的标准位置要么在 webapps META-INF/context.xml 中,要么在 $CATALINA_HOME/conf/Catalina/localhost/ 的 xml 文件中(随意命名,以 .xml 结尾)。就 META-INF/context.xml 而言,后一种解决方案实际上更受欢迎,因为这样配置独立于应用程序,并且在部署新应用程序时不会被覆盖。

此上下文通常包含附加属性,例如 docBase 和路径:

<Context docBase="/location/where/you/deployed/your/application" path="/app">
  ...
</Context>

这样您的应用程序就可以在http://servername:8080/app 获得。如果部署到 $CATALINA_HOME/webapps 目录,则 docBase 值可以相对于 webapp。但请注意竞争条件:Tomcat 将在 $CATALINA_HOME/webapps 中自动部署应用程序,并可能创建上下文文件。此外,删除 webapp 以部署新的可能会导致 tomcat 删除 xml 配置文件。

因此-无论您的问题是什么:尝试将您的上下文定义/应用程序放置在 $CATALINA_HOME/conf/Catalina/localhost/app.xml 中时是否有效。我觉得这是一件非常简单的事情,只缺少最后一点信息才能看到真正的问题。

【讨论】:

"创建一个新的 Struts Action 并从那里调用你的 JNDI 查找代码,看看它是否在靠近 struts 并在处理 http 请求时工作。如果在这里工作,继续上面的步骤。”我试过了,还是不行 我想这很短 - 关心将操作代码发布到问题中吗?此外,确保 META-INF/context.xml 最终出现在您的 WAR(不仅仅是 IDE)中。确保大写字母用于 META-INF。尝试放置文件(使用 在 conf/Catalina/localhost/c.xml 现在我有更多时间,我已将我最后的 cmets 内容添加到答案中,并提供了一些更深入的细节。希望对您有所帮助。 >在您自己创建的线程中提供 JNDI 资源不是服务器强制要求的 - 确实,但您几乎总是可以从此类线程中引用 java:global。在 Java EE 7 中,终于有了容器管理线程的概念,它继承了在这些线程上工作的代码的组件环境(以及其他)。【参考方案2】:

由于与上述解决方案相比,这是一个完全不同的场景,我选择添加另一个答案而不是编辑前一个答案:

以防万一:做extra-extra-extra-确保你的上下文定义中没有错别字。仔细比较 $CATALINA_HOME/conf/context.xml 中的工作版本

我们不希望“邮件/Sessoin”有所作为...

【讨论】:

【参考方案3】:

你有什么推荐的?

在 JNDI 中定义它,但在您的 Web 应用程序/WAR 之外。在 Tomcat 中,您可以通过将其放在 $CATALINA_BASE/conf/context.xml 文件中来执行此操作。这允许在您的 Web 应用程序之外定义外部资源(邮件、数据库等)配置,从而避免在数据库配置更改时重新打包您的 WAR,或者您移动到具有不同数据库的不同环境,例如。

我在名为 mailer 的单例类中查找上下文。

这个邮件类,是在 WEB-INF/classes 中,还是在 WEB-INF/lib 中的 JAR?或者它是否在您的类路径中的其他地方定义?如果是后者,您可能需要考虑将其移至您的应用程序中。


编辑:根据您的最新发现,您的网络应用程序的 META-INF/context.xml 似乎没有生效。 Tomcat 中有几种情况会导致这种情况。我不知道这些细节,但这里有一些我能找到的信息:

每 - http://tomcat.apache.org/tomcat-5.5-doc/config/host.html

如果您的 Host 元素中的“deployXML”属性设置为 false(我相信 server.xml)。

deployXML - 如果需要,设置为 false 禁用解析 context.xml 嵌入在应用程序中的文件 (位于 /META-INF/context.xml)。 安全意识强的环境应该 将此设置为 false 以防止 应用程序从与交互 容器的配置。这 管理员将负责 提供外部环境 配置文件,然后放入 $CATALINA_HOME/conf/[引擎名]/[主机名]/。 该标志的值默认为 true。

每 - http://tomcat.apache.org/tomcat-5.5-doc/config/context.html

如果您定义了 $CATALINA_HOME/conf/[enginename]/[hostname]/[context-path].xml 文件。

我确定还有其他的,这些只是我能够快速找到的。

【讨论】:

Mailer 在我的 WEB-INF/classes 文件夹中定义 看到了吗?您现在还有另一个理由不使用 META-INF :) 我会发布一些我认为可能对您的情况有所帮助的内容。【参考方案4】:

我认为您应该在 META-INF/context.xml 中定义您的上下文,而不是 META-INF/web.xml(尽管这可能只是您原始帖子中的错字)。

当您说您将代码移至 Struts 应用程序时,您能说得更具体些吗?您的意思是您现在正在 Action 类中查找上下文?

此外,您可能已经知道这一点,但是在您的 Web 应用程序中定义您的上下文(JNDI 条目等)时,META-INF/context.xml 在开发人员的环境中是可以接受的,我强烈反对在任何形式的共享环境中使用它,当然不是在生产环境中。

【讨论】:

感谢您的回答。我对你的回答做了一些 cmet

以上是关于邮件/会话资源工厂在 Struts 应用程序中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

会话 cookie 在 Electron 中不起作用

Dojo 插件在 Struts 2 中不起作用

过滤器在 Struts2 中不起作用

除了烧瓶应用程序的 url 之外,Flask 会话在另一个 url 中不起作用

传出电子邮件在 SharePoint 2019 中不起作用

电子邮件验证在 MVC 中不起作用