【问题标题】:Get full servlet URL during startup under Tomcat 7在Tomcat 7下启动时获取完整的servlet URL
【发布时间】:2010-09-18 00:20:41
【问题描述】:

我有一个使用 Tomcat 6 编写的 Web 应用程序,我正在尝试使其与 Tomcat 7 一起工作。在启动期间,该应用程序除其他事项外,还在某个远程目录中注册其 Web 服务组件。为此,它需要提供自己的 URL。以下(有点天真)方法应该返回 web 服务 URL:

import org.apache.catalina.ServerFactory;
import org.apache.catalina.connector.Connector;
.
.
.
private String getWsUrl(ServletContext context)
            throws UnknownHostException, MalformedURLException {
    String host = java.net.InetAddress.getLocalHost().getCanonicalHostName();
    int port = -1;
    for (Connector c : ServerFactory.getServer().findServices()[0].findConnectors()) {
        if (c.getProtocol().contains("HTTP")) {
            port = c.getPort();
            break;
        }
    }
    URL wsURL = new URL("http", host, port, context.getContextPath()
                + C.WEB_SERVICE_PATH /* this is just a constant string */ );
    return wsURL.toString();
}

ServerFactory.getServer() 部分被证明是有问题的:在 Tomcat 7 中没有 org.apache.catalina.ServerFactory 类。关于如何为 Tomcat 7 重写这个有什么建议吗?我也很乐意拥有更多可移植的、非 tomcat 特定的代码。

【问题讨论】:

    标签: tomcat servlets tomcat7


    【解决方案1】:

    我遇到了同样的问题:我需要知道端口号来为特定的 Tomcat 实例构建 URL,端口号可能会有所不同(因为我运行多个实例进行测试),并且从 Tomcat 7 开始,ServerFactory 已经消失.

    我编写了以下代码来查找和解析 Tomcat server.xml 文件。它不会解析太多,只是获取 HTTP“端口”和“重定向端口”值。它取决于“catalina.home”或“catalina.base”系统属性,它们应该存在于任何正在运行的 Tomcat 实例中。美妙之处在于它不依赖任何 Tomcat 类,并使用 JVM 的 XML 解析器。

    我希望这会有所帮助。

    public final class TomcatConfigUtil {
    
    private static final String CONFIG_FILE_PATH = "conf/server.xml";
    
    private static Map<String, String> properties = null;
    
    // No instances, please.
    private TomcatConfigUtil() { }
    
    
    /**
     * Get the configuration as a map of name/value pairs, or throw an exception if it wasn't found.
     * All values are returned as Strings.
     * <ul>
     *   <li> httpPort - the HTTP port</li>
     *   <li> httpRedirectPort - the HTTP redirect port (which seems to be the SSL port) </li>
     * </ul>
     * @exception FileNotFoundException if the configuration file wasn't found
     * @exception IOException if there was a problem reading the configuration file
     * @exception SAXException if there was a problem parsing the configuration file
     */
    public static synchronized Map<String, String> getConfig() throws FileNotFoundException, IOException, SAXException {
    
        if (properties != null) {
    
            return properties;
        }
    
        final File serverConfigFile = findServerConfigFile();
        if (serverConfigFile == null) {
    
            throw new FileNotFoundException("Couldn't find the configuration file.");
        }
    
        final Map<String, String> tmpProperties = new HashMap<String, String>();
    
        // Content-handler does the actual parsing.
        final ServerConfigContentHandler contentHandler = new ServerConfigContentHandler(tmpProperties);
        final XMLReader xmlReader = XMLReaderFactory.createXMLReader();
        xmlReader.setContentHandler(contentHandler);
    
        // Pass the config file as the input source for parsing.
        final FileReader fileReader = new FileReader(serverConfigFile);
        xmlReader.parse(new InputSource(fileReader));
        fileReader.close();
    
        return (properties = Collections.unmodifiableMap(tmpProperties));
    }
    
    
    private static File findServerConfigFile() {
    
        if (System.getProperty("catalina.home") != null) {
    
            final File file = new File(System.getProperty("catalina.home"), CONFIG_FILE_PATH);
            if (file.isFile()) {
    
                return file;
            }
        }
    
        if (System.getProperty("catalina.base") != null) {
    
            final File file = new File(System.getProperty("catalina.base"), CONFIG_FILE_PATH);
            if (file.isFile()) {
    
                return file;
            }
        }
    
        return null;
    }
    
    
    /**
     * ContentHandler implementation for the XML parser.
     */
    private static class ServerConfigContentHandler implements ContentHandler {
    
        private final Map<String, String> map;
        private boolean inServerElement;
        private boolean inCatalinaServiceElement;
    
    
        private ServerConfigContentHandler(final Map<String, String> map) {
    
            this.map = map;
        }
    
        @Override
        public void startDocument() throws SAXException {
    
            this.inServerElement = false;
            this.inCatalinaServiceElement = false;
        }
    
        @Override
        public void startElement(final String uri, final String localName, final String qName, final Attributes atts) throws SAXException {
    
            if (!this.inServerElement && "Server".equals(localName)) {
    
                this.inServerElement = true;
            }
            else if (this.inServerElement && "Service".equals(localName) && "Catalina".equals(atts.getValue("name"))) {
    
                this.inCatalinaServiceElement = true;
            }
            else if (this.inCatalinaServiceElement && "Connector".equals(localName) && "HTTP/1.1".equals(atts.getValue("protocol"))) {
    
                if ((atts.getValue("SSLEnabled") == null || "false".equals(atts.getValue("SSLEnabled"))) &&
                        (atts.getValue("secure") == null || "false".equals(atts.getValue("secure"))) &&
                        (atts.getValue("scheme") == null || "http".equals(atts.getValue("scheme")))) {
    
                            final String portStr = atts.getValue("port");
                            if (portStr != null) {
    
                                this.map.put("httpPort", portStr);
                            }
                            final String redirectPortStr = atts.getValue("redirectPort");
                            if (redirectPortStr != null) {
    
                                this.map.put("httpRedirectPort", redirectPortStr);
                            }
                        }
            }
        }
    
        @Override
        public void endElement(final String uri, final String localName, final String qName) throws SAXException {
    
            if (this.inCatalinaServiceElement && "Service".equals(localName)) {
    
                this.inCatalinaServiceElement = false;
            }
            else if (this.inServerElement && "Server".equals(localName)) {
    
                this.inServerElement = false;
            }
        }
    
        @Override
        public void endDocument() throws SAXException {
    
            this.inServerElement = false;
            this.inCatalinaServiceElement = false;
        }
    
        @Override
        public void characters(final char[] ch, final int start, final int length) throws SAXException { }
    
        @Override
        public void endPrefixMapping(final String prefix) throws SAXException { }
    
        @Override
        public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException { }
    
        @Override
        public void processingInstruction(final String target, final String data) throws SAXException { }
    
        @Override
        public void setDocumentLocator(final Locator locator) { }
    
        @Override
        public void skippedEntity(final String name) throws SAXException { }
    
        @Override
        public void startPrefixMapping(final String prefix, final String uri) throws SAXException { }
    }
    

    }

    【讨论】:

    • 有趣的方法,虽然对于生产代码来说太脏了。 +1 原创性。
    • 它可以工作,但是它与 Tomcat 7 的用法相关联。另外,不是针对此回复而是针对原始帖子,.getLocalhost() 性能在某些系统中非常差,可能是由于查找 IP6从 Java 1.4.1 开始。我想知道我们是否可以在启动后向 servlet 本身发出转储请求,以通过 HttpRequest 获取必要的信息。
    【解决方案2】:

    我从未使用过它,它可能不会返回带有主机名和地址的 URL,但是ServletContext.getResource("/") 是否有机会满足您的需求?我知道它的目的是通过 servlet 在内部访问资源,但你永远不知道。

    【讨论】:

    • 它返回一个基于URL磁盘文件系统,指向公共网络内容的根目录。所以不,这绝对不是OP想要的:)
    • 好的。 API 文档没有指定它返回的 URL 类型,我也没有时间测试它。感谢您检查。
    猜你喜欢
    • 2011-07-17
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-24
    相关资源
    最近更新 更多