WAR
1、基于Java的Web应用,其标准的打包方式是WAR
2、WAR与JAR类似,不过它包含更多的内容,如JSP文件、Servlet、Java类、web.xml配置文件、依赖JAR包、静态web资源(如HTML、CSS、JavaScript文件)等
一个典型的WAR文件的目录结构
- war /
+ META-INF /
+ WEB-INF /
| + classes /
| | + ServletA.class
| | + config.properties
| | + ...
| |
| |
| + lib /
| | + dom4j-1.4.1.jar
| | + mail-1.4.1.jar
| | + ...
| |
| + web.xml
|
+ img /
|
+ css /
|
+ js /
|
+ index.html
+ sample.jsp
1、一个WAR包下至少包含两个子目录,META-INF和WEB-INF,前者包含了一些打包元数据信息,不用关心,后者是WAR包的核心,WEB-INF下必须包含一个Web资源表示文件web.xml
2、WEB-INF的子目录classes包含所有该Web项目的类,而另一个子目录lib则包含所有该Web项目的依赖的JAR包,classes和lib目录都会在运行的时候被加入到Classpath中
3、除了META-INF和WEB-INF外,一般的WAR包都会包含很多Web资源,例如你往往可以在WAR包的根目录下看到很多html或者jsp文件,此外,还能看到一些文件夹如img、css和js
显式指定Web项目的打包方式为war
<project>
...
<groupId>com.juvenxu.mvnbook</groupId>
<artifactId>sample-war</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
...
</project>
如果不显示指定packaging,Maven会使用默认的jar打包方式,从而导致无法正确打包Web项目
一个典型的Web项目的Maven目录结构如下
+ project
|
+ pom.xml
|
+ src/
+ main /
| + java /
| | + ServletA.java
| | + ...
| |
| + resources /
| | + config.properties
| | + ...
| |
| + webapp /
| + WEB-INF /
| | + web.xml
| |
| + img /
| |
| + css /
| |
| + js /
| +
| + index.html
| + sample.jsp
|
+ test /
+ java /
+ resources /
一般配置finalName元素,更改war包的名称
1、该元素默认值已在超级的POM中设定,值为 $ {project.artifactId}-$ {project.version}
2、不过上面这样的名称显然不利于部署
3、配置<finalName>account</finalName>,项目生成的war包名称就会成为account.war,方便部署
关于Web测试
1、一般方式,将war包部署到应用服务器,然后打开浏览器进行测试,比如验证程序功能、验证页面布局,尤其是一些与页面相关的的特性
2、近年来也出现了很多自动化的Web测试技术如Selenium,它能够录制Web操作,生成各种语言脚本,然后自动重复这些操作以进行测试,这类技术方法是未来的趋势,但是还是无法完全替代,手动的、亲眼对比的验证的测试
关于Web页面测试和底层代码测试的一些建议
1、在介绍jetty-maven-plugin之前,要强调一点,虽然手动的Web页面测试是必不可少的,但这种方法绝不应该被滥用
2、现实中常见的情况是,很多程序员即使修改了一些较为底层的代码 (如数据库访问、业务逻辑),都会习惯性地打开浏览器测试整个应用,这往往是没有必要的
3、可以用单元测试覆盖的代码就不应该依赖于Web页面测试,且不说页面测试更加耗时耗力,这种方式还无法自动化,更别提重复性了
4、因此Web页面测试应该仅限于页面的层次,例如JSP、CSS、JavaScript的修改,其他代码修改 (如数据访问),请编写单元测试
为什么使用jetty-maven-plugin这个插件帮助测试?
1、传统的Web测试方法要求我们编译、测试、打包及部署,这往往会消耗数10秒至数分钟的时间,jetty-maven-plugin能够帮助我们节省时间,它能够周期性地检查项目内容,发现变更后自动更新到内置的Jetty Web容器
2、换句话说,它帮我们省去了打包和部署的步骤,jetty-maven-plugin默认就很好地支持了Maven的项目目录结构,在通常情况下,我们只需要直接在IDE中修改源码,IDE就能够执行自动编译,jetty-maven-plugin发现编译后的文件变化后,自动将其更新到Jetty容器,这时就可以直接测试Web页面了
配置jetty-maven-plugin
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.1.6.v20100715</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webAppConfig>
<contextPath>/test</contextPath>
</webAppConfig>
</configuration>
</plugin>
对上述配置进行解释
1、jetty-maven-plugin并不是官方的Maven插件,它的groupId是org.mortbay.jetty
2、使用了Jetty 7的最新版本,在该插件的配置中,scanIntervalSeconds顾名思义表示该插件扫描项目变更的时间间隔,这里的配置是每隔10秒
3、需要注意的是,如果不进行配置,该元素的默认值是0,表示不扫描,用户也就失去了所谓的自动化热部署的功能
4、webappConfig元素下的contextPath表示项目部署后的context path,例如这里的值为/test,那么用户就可以通过http://hostname:port/test/访问该应用
配置jetty-maven-plugin插件的命令行简化操作
默认情况下,只有org.apache.maven.plugins和org.codehaus.mojo两个groupId下的插件才支持简化的命令行调用,即可以运行mvn help:system,但mvn jetty:run就不行了
这是因为,maven-help-plugin是groupId是org.apache.maven.plugins,而jetty-maven-plugin的groupId是org.mortbay.jetty,为了直接能在命令行直接运行mvn jetty:run,用户需要配置settings.xml:
<settings>
<pluginGroups>
<pluginGroup>org.mortbay.jetty</pluginGroup>
</pluginGroups>
</settings>
启动Jetty
命令mvn jetty:run
jetty-maven-plugin会启动Jetty,并且默认监听本地的8080端口,并将当前项目部署到容器中,同时它还会根据用户配置扫描代码改动
如果希望使用其他端口,运行jetty
可以添加jetty.port参数
mvn jetty:run -Djetty.port=9999
关于jetty-maven-plugin插件自动扫描的说明
启动jetty后,用户可以在IDE中修改各类文件,如JSP、HTML、CSS、JavaScript甚至是Java类。只要不是修改类名、方法名等较大的操作,jetty-maven-plugin都能够扫描到变更并正确地将变化更新至Web容器中
jetty-maven-plugin插件的进一步研究
1、热部署仅仅是jetty-maven-plugin插件最核心的配置点
2、还可以自定义web.xml的位置、项目class文件的位置、web资源目录的位置等
3、用户还能够以WAR包的方式部署项目,然后执行一些集成测试,最后停止容器
4、进一步研究地址,http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin
使用Cargo实现自动化部署,Cargo是什么?
Cargo是一组帮助用户操作Web容器的工具,它能够帮助用户实现自动化部署,而且它几乎支持所有的Web容器,如Tomcat、JBoss、Jetty和Glassfish等。
Gargo通过cargo-maven2-plugin提供了Maven集成,Maven用户可以使用该插件将Web项目部署到Web容器中
cargo-maven2-plugin和jetty-maven-plugin的区别
虽然cargo-maven2-plugin和jetty-maven-plugin的功能看起来很相似,但它们的目的是不同的
1、jetty-maven-plugin主要用来帮助日常的快速开发和测试
2、cargo-maven2-plugin主要服务于自动化部署
Cargo的部署
Cargo支持两种本地部署的方式,分别为standalone模式和existing模式
1、standalone模式中,Cargo会从Web容器的安装目录复制一份配置到用户指定的目录,然后在此基础上部署应用,每次重新构建的时候,这个目录都会被清空,所有配置被重新生成
2、而在existing模式中,用户需要指定现有的Web容器配置目录,然后Cargo会直接使用这些配置并将应用部署到其对应的位置
使用standalone模式部署应用至本地Web容器(tomcat6x)
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.0</version>
<configuration>
<container>
<containerId>tomcat6x</containerId>
<home>D:\cmd\apache-tomcat-6.0.29</home>
</container>
<configuration>
<type>standalone</type>
<home>${project.build.directory}/tomcat6x</home>
</configuration>
</configuration>
</plugin>
对上面的配置进行解释:
1、cargo-maven2-plugin是groupId是org.codehaus.cargo,这不属于官方的两个Maven插件groupId,因此用户需要将其添加到settings.xml的pluginGroup元素中以方便命令行调用
2、cargo-maven2-plugin包括了container和configuration两个元素,configuration的子元素type表示部署的模式(这里是standalone)configuration的子元素home表示复制容器配置到什么位置,这里的值为${project.build.directory}/tomcat6x,表示构件输出目录,即target/下的tomcat6x子目录
3、container元素下的containerId表示容器的类型,home元素表示容器的安装目录
4、基于该配置Cargo会从D:\cmd\apache-tomcat-6.0.29目录下复制配置到当前项目的target/tomcat6x/目录下
5、执行mvn cargo:start,让Cargo启动Tomcat并部署应用
Cargo会让Web容器监听8080端口,如何修改端口号为8081
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.0</version>
<configuration>
<container>
<containerId>tomcat6x</containerId>
<home>D:\cmd\apache-tomcat-6.0.29</home>
</container>
<configuration>
<type>standalone</type>
<home>${project.build.directory}/tomcat6x</home>
<properties>
<cargo.servlet.port>8081</cargo.servlet.port>
</properties>
</configuration>
</configuration>
</plugin>
使用existing模式部署应用至本地Web容器
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.0</version>
<configuration>
<container>
<containerId>tomcat6x</containerId>
<home>D:\cmd\apache-tomcat-6.0.29</home>
</container>
<configuration>
<type>existing</type>
<home> D:\cmd\apache-tomcat-6.0.29</home>
</configuration>
</configuration>
</plugin>
部署至远程Web容器?没测出来,他妈的。