Clojure 用bootclj创建一个war

Clojure 用bootclj创建一个war,clojure,war,boot-clj,Clojure,War,Boot Clj,我想创建一个可以用tomcat部署的战争。使用leinuberwar做得很好,但是用boot做同样的事情似乎不起作用。我可以建造一个罐子并运行它,但是战争失败了 2015年12月9日上午12:15:31 org.apache.catalina.loader.WebappClassLoader validateJarFile信息: validateJarFile(/var/lib/tomcat7/sites/geeknow.guru/DEBUG##0.1.7/WEB-INF/lib/javax.s

我想创建一个可以用tomcat部署的战争。使用
leinuberwar
做得很好,但是用boot做同样的事情似乎不起作用。我可以建造一个罐子并运行它,但是战争失败了

2015年12月9日上午12:15:31 org.apache.catalina.loader.WebappClassLoader validateJarFile信息: validateJarFile(/var/lib/tomcat7/sites/geeknow.guru/DEBUG##0.1.7/WEB-INF/lib/javax.servlet-api-3.1.0.jar) -jar未加载。参见Servlet规范3.0,第10.7.2节。有问题的类:javax/servlet/servlet.class

我正在使用以下build.boot

(set-env!
 :source-paths #{"src/clj"}
 :resource-paths #{"resources" "src/clj"}
 :dependencies '[[org.clojure/clojure "1.7.0"]
                 [clj-time "0.9.0"]
                 [org.clojure/java.jdbc "0.3.7"]
                 [org.postgresql/postgresql "9.4-1202-jdbc41"]
                 [yesql "0.5.1"]
                 [migratus "0.8.6"]
                 [markdown-clj "0.9.67"]
                 [jarohen/nomad "0.7.2"]
                 [com.draines/postal "1.11.3"]
                 [compojure "1.4.0"]
                 [ring/ring-core "1.4.0"]
                 [ring/ring-devel "1.4.0"]
                 [ring/ring-defaults "0.1.5"] 
                 [ring/ring-jetty-adapter "1.4.0"]
                 [ring-refresh "0.1.1"]
                 [ring-logger-timbre "0.7.5"]
                 [com.taoensso/timbre "4.1.4"]
                 [hiccup "1.0.5"]
                 [garden "1.3.0"]
                 [danlentz/clj-uuid "0.1.6"]
                 [speclj "3.3.1" :scope "test"]
                 [pandeiro/boot-http "0.7.1-SNAPSHOT"]])

(require '[pandeiro.boot-http :as http])
(require '[ring.middleware.reload :refer [wrap-reload]])
(require '[ring.adapter.jetty :as jetty])
(require '[ring.middleware.refresh :refer [wrap-refresh]])
(require '[blog.handler])

;;;;taken from boot-http.util
(defn resolve-sym [sym]
  (require (symbol (namespace sym)) :reload)
  (resolve sym))

(deftask ring-server
  []
  (comp (jetty/run-jetty (wrap-refresh (wrap-reload (resolve-sym 'blog.handler/app))) {:port 3000}) (wait)))

(deftask uberwar
  []
  (comp (aot) (pom) (web) (uber) (war)))

(deftask uberjar
  []
  (comp (aot) (pom) (uber) (jar)))

(task-options!
 pom {:project 'geeknow
      :version "0.1.7"}
 ;uber {:as-jars true}
 aot {:all true}
 jar {:main 'blog.core
      :manifest {"Description" "blog"}}
 web {:serve 'blog.handler/app}
 war {:main 'blog.core
      :manifest {"Description" "blog"}}
 repl {:init-ns 'blog.core})

Tomcat在抱怨,因为war文件中包含的一个JAR包含一个只有容器环境才能提供的类。战争中令人不快的jar是
WEB-INF/lib/javax.servlet-api-3.1.0.jar

默认情况下,
uber
任务在
WEB-INF/lib
--as jars
设置为true时,向war添加所有直接和可传递的依赖项<代码>--as JAR是将依赖项绑定到servlet容器的首选方法

问题似乎是您的一个直接依赖项引入了
javax.servlet api
,而
uber
正在打包它,从而导致了Tomcat问题

首先,我们需要弄清楚哪个依赖项引入了
javax.servlet api
boot show
包含许多用于诊断此类依赖性问题的选项。您可以通过
bootshow-h
了解所有这些功能。我们现在想要的是
bootshow-d
,它打印依赖关系树

以下是相关输出的片段:

[ring/ring-jetty-adapter "1.4.0"]
├── [org.eclipse.jetty/jetty-server "9.2.10.v20150310"]
│   ├── [javax.servlet/javax.servlet-api "3.1.0"]
│   ├── [org.eclipse.jetty/jetty-http "9.2.10.v20150310"]
│   │   └── [org.eclipse.jetty/jetty-util "9.2.10.v20150310"]
│   └── [org.eclipse.jetty/jetty-io "9.2.10.v20150310"]
└── [ring/ring-servlet "1.4.0"]
从这个输出中,我们知道我们对
ring/ring-jetty适配器的依赖是导致引入
javax.servlet/javax.servlet api
的原因

因为这种依赖性是本地开发所必需的,所以我们不想完全忽略它。相反,我们可以使用
“test”
范围添加依赖项:

[ring/ring-jetty-adapter "1.4.0" :scope "test"]
在这样的场景中,作用域是限制依赖项传递性的一种方法。Boot使用Maven作为其底层依赖项解析机制
uber
对Maven作用域敏感,可以根据需要配置为包括或排除各种作用域。有关更多信息,请参见
boot uber-h

默认情况下,
uber
任务不会在
“测试”
范围内打包依赖项。通过这样标记
环/环码头适配器
,我们将其从优步战争中排除


“test”
范围对于您可能在测试(当然!)中使用的依赖项,或者对于部署,或者对于您需要依赖项但不想将其与您的工件一起分发的其他任务(无论是库jar还是uberwar web应用程序)也很有用。

您正在使用jdkI know构建。这就是为什么我自己尝试构建clojure适配器servlet,但没有任何帮助。如果这有助于
boot-src-d tailrecursion/clojure适配器servlet:0.2.1--pom-p clojure适配器servlet-v 0.2.1--jar--install
I在服务器上更新了Java。现在我得到一个新的错误。我更新了这个问题,因为您在依赖项中包含了jetty适配器,这将与您对Tomcat的部署相冲突。但不确定这是错误消息的原因。我需要jetty适配器来运行本地服务器。我试着移除它来制造战争,但是没有用。谢谢你的详细回复。这真的帮助我理解了这个问题。不幸的是,
ringdefaults
也带来了
javax.servlet/servlet api
。我认为我在项目中使用的
ring.middleware.defaults
需要
ring defaults
。您知道如何解决这个问题吗?@hold您可以使用
[ring/ring defaults“0.1.5”:排除[javax.servlet/servlet api]
环默认值中排除
servlet api
。然后,单独引入
servlet api
仅在开发中使用
[javax.servlet/servlet-api“2.5”:scope“test”]
。忽略我所说的关于再次引入servlet api的内容,它已经由ring jetty adapter在本地提供。我尝试了它,但又出现了另一个错误。然而,由于我已经放弃了我的web项目,这帮助我摆脱了一个错误,并且包含了一些有用的信息,所以我将它标记为完整。再次感谢。