简体   繁体   English

将Webapp的资源部署到Maven存储库?

[英]Deploying webapp's resources to maven repository?

This question is a bit of a "best-practice" question, my team is new to Maven and I am looking for the best way forward on this topic: 这个问题有点像“最佳实践”问题,我的团队是Maven的新手,我正在寻找有关此主题的最佳方法:

When working on a project that has packaging = war , what's the best way to deploy it to your Maven repository (such as a company-wide Nexus installation)? 在处理具有包装= war的项目时,将其部署到Maven存储库(例如公司范围内的Nexus安装)的最佳方法是什么?

For example, let's say you have a webapp where the environment-specific properties files (such as database connection strings, logging configuration, etc., which differ based on dev/QA/production environments) are included in the final packaged app based on properties or environment variables. 例如,假设您有一个Web应用程序,其中基于环境的特定属性文件(例如数据库连接字符串,日志记录配置等,根据开发/质量保证/生产环境的不同而有所不同)包含在基于属性的最终打包应用程序中或环境变量。 When building this type of app, what makes the most sense to deploy to your repository? 在构建此类应用程序时,最有意义的是将其部署到存储库中? Should it be the WAR file with production settings, or a JAR of all of the classes and none of the resources? 应该是带有生产设置的WAR文件,还是所有类都没有资源的JAR?

The reason I am asking is that when you are building a webapp such as this, you really have a codebase plus a set of environment-specific resource files. 我问的原因是,当您构建这样的Web应用程序时,您确实有一个代码库以及一组特定于环境的资源文件。 The former makes a lot of sense to deploy to your repository so it is available to other projects, but the latter doesn't make much sense to share and make available to others. 前者在部署到您的存储库时非常有意义,因此它可用于其他项目,但后者在共享和提供给其他人时没有多大意义。

I suggest you build a raw war project with perhaps some default files for development and deploy that to the repository. 我建议您构建一个原始战争项目,其中可能包含一些用于开发的默认文件,然后将其部署到存储库中。

Then you can build multiple projects which depend on the war project and provide their own specific resources. 然后,您可以构建依赖于战争项目的多个项目,并提供自己的特定资源。


The JavaOne 2009 presentation Getting Serious About Build Automation: Using Maven in the Real World has a good example on how this can be done JavaOne 2009演示文稿认真对待构建自动化:在现实世界中使用Maven有一个很好的例子说明了如何实现

  1. Create a 'myapp-deploy' maven project 创建一个“ myapp-deploy” Maven项目
  2. In the deploy project, reference the war project 在部署项目中,参考战争项目

     <dependency> <groupId>myorg.myapp</groupId> <groupId>myapp-web</groupId> <version>${webapp.version}</version> <type>war</type> </dependency> 
  3. In the deploy project, use an overlay to import the files from the web project 在部署项目中,使用叠加层从Web项目中导入文件

     <plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <warName>myapp-web</warName> <overlays> <overlay> <groupId>myorg.myapp</groupId> <artifactId>myapp-web</artifactId> <excludes> <exclude>WEB-INF/classes/config.properties</exclude> </excludes> </overlay> </overlays> <!-- some config elements not shown here --> </plugin> 
  4. In the deploy project, include the extra resources from the deploy project into the web project 在部署项目中,将来自部署项目的额外资源包括到Web项目中

     <plugin> <artifactId>maven-war-plugin</artifactId> <configuration> <!-- some config elements not shown here --> <webResources> <resource> <directory>${patch.path}</directory> </resource> </webResources> </configuration> </plugin> 

I think you should build one war. 我认为你应该打一场战争。 Mucking about with overlays is too much of a temptation for developers to "just drop this fix in for that environment". 对于开发人员而言,“过度使用此修复程序只是为了解决该问题”是一种过度的诱惑。

Use JNDI resources for environment variables and attach external JNDI resource file(s) (you can attach one for each type of environment if needed). JNDI资源用于环境变量并附加外部JNDI资源文件(如果需要,可以为每种类型的环境附加一个)。

Of course you then need a process to retrieve the correct resource file and apply it to your environment (tweaking it with passwords and other sensitive variables), but that is a fairly straightforward scripting exercise. 当然,您随后需要一个过程来检索正确的资源文件并将其应用于您的环境(使用密码和其他敏感变量对其进行调整),但这是一个相当简单的脚本练习。

I put the properties in my maven pom.xml. 我将属性放在我的Maven pom.xml中。 First off, I chop up the whole web app so that there are separate jars for the different layers; 首先,我将整个Web应用程序切碎,以便为不同的层提供单独的jar; persistenc/db, service, web (eg, controllers for spring mvc), and war. persistenc / db,服务,Web(例如spring mvc的控制器)和war。 The war project has the jsps and properties/config/xml files in src/main/resources. 战争项目在src / main / resources中具有jsps和properties / config / xml文件。

For example, my parent pom starts like this: 例如,我的父pom开始如下:

<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>edu.berkeley.ist.waitlist</groupId>

<artifactId>waitlist-parent</artifactId>

<modules>
    <module>../waitlist-core</module>
    <module>../waitlist-db</module>
    <module>../waitlist-web</module>
    <module>../waitlist-war</module>
    <module>../waitlistd</module>
</modules>

and

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>

        <resource>
            <directory>src/main/hbm</directory>
            <filtering>true</filtering>
        </resource>
    </resources>

and

<dependencyManagement>
    <!-- dependencies with exclusions -->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>

            <version>${version.springframework}</version>

            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

Then I have a bunch of profiles, for the various builds: 然后,我有很多配置文件,适用于各种构建:

<profiles>
    <!-- ========================================================== -->
    <!-- local, hsql                                                -->
    <!-- ========================================================== -->
    <profile>
        <id>localhost-hsql</id>

        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>

        <properties>
            <!-- need to specify ${basedir} so that hsql creates its files in the right place -->
            <db2.url>jdbc:hsqldb:file:${basedir}/target/waitlistv2;shutdown=true</db2.url>

            <db2.user>sa</db2.user>
            <db2.password />

            <jdbc-db2.driverClass>org.hsqldb.jdbcDriver</jdbc-db2.driverClass>

            <db2.schema>public</db2.schema>

            <db2.hibernate.default_schema>public</db2.hibernate.default_schema>

            <db2.hibernate.dialect>org.hibernate.dialect.HSQLDialect</db2.hibernate.dialect>

            <dbunit.dataTypeFactoryName>org.dbunit.ext.hsqldb.HsqldbDataTypeFactory</dbunit.dataTypeFactoryName>

            <hbmtool.haltOnError>false</hbmtool.haltOnError>

            <log.filename>/tmp/waitlist.log</log.filename>
        </properties>
    </profile>

For example, in waitlist-war/src/main/resources is the file logback.xml, and it starts with 例如,在waitlist-war / src / main / resources中是文件logback.xml,它以

<configuration debug="true">
<appender class="ch.qos.logback.core.rolling.RollingFileAppender" name="RootFileAppender">
    <!-- set in the pom.xml file -->
    <file>${log.filename}</file>

So you can see how the log.filename property from the pom is used due to maven's filtering. 因此,您可以看到由于maven的过滤,如何使用pom中的log.filename属性。

(I'm specifying all of the versions in the parent's pom and the child projects just specify the dependencies they use, but without the version number. I'm not sure if this is the correct way, best practice, etc. (我在父级pom中指定了所有版本,而子项目仅指定了它们使用的依赖项,但没有版本号。我不确定这是否是正确的方法,最佳实践等。

Also, waitlist-war depends on waitlist-web, waitlist-web depends on waitlist-core (my service layer), and waitlist-core depends on waitlist-db. 另外,waitlist-war取决于waitlist-web,waitlist-web取决于waitlist-core(我的服务层),waitlist-core取决于waitlist-db。 Waitlistd is a separate app that has no ui to speak of and it depends on waitlist-core.) Waitlistd是一个单独的应用程序,没有ui可以说,它取决于waitlist-core。)

I'm a big fan of only having one version of each deployable. 我非常喜欢每个可部署版本只有一个版本。 If you have a production version, a test version etc, this will slow you down with the necessary checks and rebuilds. 如果您具有生产版本,测试版本等,则将通过必要的检查和重建来减慢您的速度。 Build the war once and use the same war for each environment. 建立一次战争,并对每个环境使用相同的战争。

This leads to question how do you handle environment specific properties. 这引发了一个问题,即您如何处理特定于环境的属性。 I usually take a hybrid approach. 我通常采用混合方法。 Where possible all needed properties for all environments are packaged within the war. 在战争中尽可能将所有环境的所有必需属性打包在一起。 The war then loads correct properties depending on which environment it is in. The app can determine what environment it is in using a system property. 然后,战争根据其所处的环境来加载正确的属性。应用程序可以使用系统属性来确定其所处的环境。

See here for an example using spring: http://www.developer.com/java/ent/article.php/3811931 有关使用spring的示例,请参见此处: http : //www.developer.com/java/ent/article.php/3811931

This could easily be adapted for use without spring though. 不过,这可以很容易地适应无弹簧使用。

Some properties aren't suitable for packaging up in the war eg production passwords. 一些属性不适用于战争中的打包,例如生产密码。 For these the above linked method can easily be used to load the properties from an external file path. 对于这些,上面链接的方法可以轻松地用于从外部文件路径加载属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM