I am attempting to setup a sample dynamic web project in Eclipse using Java EE, Spring and Maven (using Nexus repository manager). I was wondering if anybody knows the "best practice" directory structure that I should setup for an enterprise web app in Eclipse? Should I just stick with the default structure that is setup for me? I ask because looking around the internet I see wide variation (for instance, where the WEB-INF and META-INF folders are..if there is a 'war' directory etc.). Thanks!
If you're using Maven, it's best to follow their convention.
If you're using Spring, you don't need an EAR. A WAR will do just fine.
A WAR file has a definite standard that you must follow. As long as you can generate a proper WAR file, you can use any directory structure for your source code that makes sense to you.
I use something like this:
/project
+---/src (.java)
+---/test (TestNG .java here)
+---/test-lib (testNG JAR, Spring test JAR, etc.)
+---/resources (log4j.xml, etc.)
+---/web (root of web content here)
+---+---/WEB-INF
+---+---+---/classes (compile .java to this directory)
+---+---+---/lib (JAR files)
I use IntelliJ, so it creates an exploded WAR file as output for me.
I have an Ant build.xml that generally follows the IntelliJ directory structure. You're welcome to crib it if you find it useful.
<?xml version="1.0" encoding="UTF-8"?>
<project name="xslt-converter" basedir="." default="package">
<property name="version" value="1.6"/>
<property name="haltonfailure" value="no"/>
<property name="out" value="out"/>
<property name="production.src" value="src"/>
<property name="production.lib" value="lib"/>
<property name="production.resources" value="config"/>
<property name="production.classes" value="${out}/production/${ant.project.name}"/>
<property name="test.src" value="test"/>
<property name="test.lib" value="lib"/>
<property name="test.resources" value="config"/>
<property name="test.classes" value="${out}/test/${ant.project.name}"/>
<property name="exploded" value="out/exploded/${ant.project.name}"/>
<property name="exploded.classes" value="${exploded}/WEB-INF/classes"/>
<property name="exploded.lib" value="${exploded}/WEB-INF/lib"/>
<property name="reports.out" value="${out}/reports"/>
<property name="junit.out" value="${reports.out}/junit"/>
<property name="testng.out" value="${reports.out}/testng"/>
<path id="production.class.path">
<pathelement location="${production.classes}"/>
<pathelement location="${production.resources}"/>
<fileset dir="${production.lib}">
<include name="**/*.jar"/>
<exclude name="**/junit*.jar"/>
<exclude name="**/*test*.jar"/>
</fileset>
</path>
<path id="test.class.path">
<path refid="production.class.path"/>
<pathelement location="${test.classes}"/>
<pathelement location="${test.resources}"/>
<fileset dir="${test.lib}">
<include name="**/junit*.jar"/>
<include name="**/*test*.jar"/>
</fileset>
</path>
<path id="testng.class.path">
<fileset dir="${test.lib}">
<include name="**/testng*.jar"/>
</fileset>
</path>
<available file="${out}" property="outputExists"/>
<target name="clean" description="remove all generated artifacts" if="outputExists">
<delete dir="${out}" includeEmptyDirs="true"/>
<delete dir="${reports.out}" includeEmptyDirs="true"/>
</target>
<target name="create" description="create the output directories" unless="outputExists">
<mkdir dir="${production.classes}"/>
<mkdir dir="${test.classes}"/>
<mkdir dir="${reports.out}"/>
<mkdir dir="${junit.out}"/>
<mkdir dir="${testng.out}"/>
<mkdir dir="${exploded.classes}"/>
<mkdir dir="${exploded.lib}"/>
</target>
<target name="compile" description="compile all .java source files" depends="create">
<!-- Debug output
<property name="production.class.path" refid="production.class.path"/>
<echo message="${production.class.path}"/>
-->
<javac srcdir="src" destdir="${out}/production/${ant.project.name}" debug="on" source="${version}">
<classpath refid="production.class.path"/>
<include name="**/*.java"/>
<exclude name="**/*Test.java"/>
</javac>
<javac srcdir="${test.src}" destdir="${out}/test/${ant.project.name}" debug="on" source="${version}">
<classpath refid="test.class.path"/>
<include name="**/*Test.java"/>
</javac>
</target>
<target name="junit-test" description="run all junit tests" depends="compile">
<!-- Debug output
<property name="test.class.path" refid="test.class.path"/>
<echo message="${test.class.path}"/>
-->
<junit printsummary="yes" haltonfailure="${haltonfailure}">
<classpath refid="test.class.path"/>
<formatter type="xml"/>
<batchtest fork="yes" todir="${junit.out}">
<fileset dir="${test.src}">
<include name="**/*Test.java"/>
</fileset>
</batchtest>
</junit>
<junitreport todir="${junit.out}">
<fileset dir="${junit.out}">
<include name="TEST-*.xml"/>
</fileset>
<report todir="${junit.out}" format="frames"/>
</junitreport>
</target>
<taskdef resource="testngtasks" classpathref="testng.class.path"/>
<target name="testng-test" description="run all testng tests" depends="compile">
<!-- Debug output
<property name="test.class.path" refid="test.class.path"/>
<echo message="${test.class.path}"/>
-->
<testng classpathref="test.class.path" outputDir="${testng.out}" haltOnFailure="${haltonfailure}" verbose="2" parallel="methods" threadcount="50">
<classfileset dir="${out}/test/${ant.project.name}" includes="**/*.class"/>
</testng>
</target>
<target name="exploded" description="create exploded deployment" depends="testng-test">
<copy todir="${exploded.classes}">
<fileset dir="${production.classes}"/>
</copy>
<copy todir="${exploded.lib}">
<fileset dir="${production.lib}"/>
</copy>
</target>
<target name="package" description="create package file" depends="exploded">
<jar destfile="${out}/${ant.project.name}.jar" basedir="${production.classes}" includes="**/*.class"/>
</target>
</project>
If you use Maven, I'd warmly recommend to just follow Maven's convention. This is the "best practice" in Maven's world (and I don't see any good reasons to not do so, not following this advice will lead to more work).
One easy way to create a webapp project is to use the maven-archetype-webapp:
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp \
-DgroupId=com.mycompany.app \
-DartifactId=my-webapp \
-Dversion=1.0-SNAPSHOT
(You can paste this command "as is" in a Linux shell; on Windows, type everything on single line without the "\"
.)
And this is the structure you'll get:
my-webapp
|-- pom.xml
`-- src
`-- main
|-- resources
`-- webapp
|-- WEB-INF
| `-- web.xml
`-- index.jsp
This layout is compliant with Eclipse WTP (whatever plugin you're using for the Eclipse integration). Just import this project into Eclipse and there you go.
If you have more specific question, feel free to ask (for example, most of time you don't have to worry about the META-INF
directory, but put it under src/main/resources
if really you need to have it).