├── .gitignore ├── web ├── index.html └── WEB-INF │ └── web.xml ├── lib ├── embed │ ├── guava-15.0.jar │ └── jetty-all-9.1.0.v20131115.jar ├── compile │ └── servlet-api-3.1.jar └── runtime │ ├── slf4j-api-1.7.5.jar │ ├── slf4j-simple-1.7.5.jar │ └── minimal-json-0.9.2-SNAPSHOT.jar ├── .project ├── .classpath ├── src ├── java │ └── mypackage │ │ └── HelloworldServlet.java └── embed-src │ └── mypackage │ └── WebAppUnassembled.java └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | This is static resource! -------------------------------------------------------------------------------- /lib/embed/guava-15.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/embed/guava-15.0.jar -------------------------------------------------------------------------------- /lib/compile/servlet-api-3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/compile/servlet-api-3.1.jar -------------------------------------------------------------------------------- /lib/runtime/slf4j-api-1.7.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/runtime/slf4j-api-1.7.5.jar -------------------------------------------------------------------------------- /lib/runtime/slf4j-simple-1.7.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/runtime/slf4j-simple-1.7.5.jar -------------------------------------------------------------------------------- /lib/embed/jetty-all-9.1.0.v20131115.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/embed/jetty-all-9.1.0.v20131115.jar -------------------------------------------------------------------------------- /lib/runtime/minimal-json-0.9.2-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ferdynice/helloworld-war/HEAD/lib/runtime/minimal-json-0.9.2-SNAPSHOT.jar -------------------------------------------------------------------------------- /web/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | index.html 9 | 10 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | helloworld-war 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/java/mypackage/HelloworldServlet.java: -------------------------------------------------------------------------------- 1 | package mypackage; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.annotation.WebServlet; 6 | import javax.servlet.http.HttpServlet; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.eclipsesource.json.JsonObject; 14 | 15 | @WebServlet("/helloworld/*") 16 | public class HelloworldServlet extends HttpServlet { 17 | private static final long serialVersionUID = -7759593256585062849L; 18 | private static final Logger LOG = LoggerFactory.getLogger(HelloworldServlet.class); 19 | 20 | @Override 21 | public void doGet(HttpServletRequest req, HttpServletResponse resp) 22 | throws IOException { 23 | LOG.info("serving request"); 24 | if ("json".equals(req.getParameter("format"))) { 25 | LOG.info("special format for request {}", req); 26 | resp.setContentType("application/json"); 27 | String json = new JsonObject().add("msg", "Hello!").toString(); 28 | resp.getWriter().print(json); 29 | } else { 30 | resp.setContentType("text/plain"); 31 | resp.getWriter().println("Hello, world"); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Helloworld WAR 2 | 3 | ### A example Java WAR project / template project 4 | 5 | Contains: 6 | - Helloworld servlet (using Annotations) 7 | - an example static html file 8 | - a most basic web.xml 9 | - compile time servlet-api.jar (so doesn't need Java EE) 10 | - Ant build.xml that builds the WAR 11 | - Simple logging, with slf4j-api and sl4j-simple 12 | - Jetty embedded server for running directly in Eclipe 13 | 14 | It should work with Java 6, 7 and upwards. 15 | It doesn't contain any dependendency injection specific frameworks, 16 | such as Spring or Guice. (Although you can add this easily). 17 | 18 | The nature is an Eclipse project, 19 | it contains a minimal .classpath and .project file. 20 | 21 | #### Building the WAR 22 | To build a WAR that you can deploy (for example to Tomcat or Jetty), 23 | you can run 'ant' from the project root. 24 | By default the Java source and target version is **1.7**, 25 | this can be changed in the build.xml file. 26 | 27 | The WAR is tested to work with Apache Tomcat 7 and Jettyrunner 9. 28 | 29 | #### Running in Eclipse 30 | Typically, during development, you want run the application directly 31 | in Eclipse, for quick results and easy debugging. 32 | (Including working breakpoints and hot code swap). 33 | 34 | This is possible thanks to embedding Jetty. 35 | For this, run 'WebAppUnassembled' as a Java application. 36 | 37 | Note that it is not trivial to dynamically load the annotated servlets this way. 38 | (Most examples around the web involve around creating a war file, which defeat some purposes). 39 | However WebAppUnassembled tries a best effort to do this by using Classpath scanning, 40 | still picking up the essential annotations with basic options. 41 | The annotations are WebServlet, WebFilter and WebListener. 42 | 43 | It uses the Google Guava helper library, which is a nice utility to have anyway. 44 | (If you want to call it from within your web app itself, move the library to lib/runtime 45 | or it won't be included in the war file when you build it). 46 | 47 | #### LICENSE 48 | Licensed under [Eclipse Public License](http://www.eclipse.org/legal/epl-v10.html). 49 | 50 | -------------------------------------------------------------------------------- /src/embed-src/mypackage/WebAppUnassembled.java: -------------------------------------------------------------------------------- 1 | package mypackage; 2 | import java.util.Arrays; 3 | import java.util.EnumSet; 4 | import java.util.EventListener; 5 | 6 | import javax.servlet.DispatcherType; 7 | import javax.servlet.Filter; 8 | import javax.servlet.annotation.WebFilter; 9 | import javax.servlet.annotation.WebListener; 10 | import javax.servlet.annotation.WebServlet; 11 | import javax.servlet.http.HttpServlet; 12 | 13 | import org.eclipse.jetty.server.Server; 14 | import org.eclipse.jetty.servlet.FilterHolder; 15 | import org.eclipse.jetty.servlet.ServletHolder; 16 | import org.eclipse.jetty.webapp.WebAppContext; 17 | 18 | import com.google.common.collect.ObjectArrays; 19 | import com.google.common.reflect.ClassPath; 20 | 21 | public class WebAppUnassembled 22 | { 23 | static { 24 | //this will log to to standard out instead of standard err. 25 | System.setProperty("org.slf4j.simpleLogger.logFile", "System.out"); 26 | //have nice datetime stamps in the log lines 27 | System.setProperty("org.slf4j.simpleLogger.showDateTime", "true"); 28 | System.setProperty("org.slf4j.simpleLogger.dateTimeFormat", "yyyy-MM-dd HH:mm:ss.SSS"); 29 | } 30 | 31 | public static void main(String[] args) throws Exception 32 | { 33 | Server server = new Server(8080); 34 | 35 | WebAppContext context = new WebAppContext(); 36 | 37 | context.setResourceBase("./web"); 38 | loadAnnotations(context); 39 | server.setHandler(context); 40 | 41 | server.start(); 42 | server.join(); 43 | } 44 | 45 | 46 | 47 | private static void loadAnnotations(WebAppContext context) throws Exception { 48 | // Add annotations from classpath, using only file resources 49 | // (thus using only classes from this project's src folder). 50 | // NOTE: This mimics the annotation behaviour of loading a WAR, 51 | // but it is certainly not fully functional 52 | // (some annotations and/or annotate elements are not implemented). 53 | ClassPath classpath = ClassPath.from(WebAppUnassembled.class 54 | .getClassLoader()); 55 | for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClasses()) { 56 | if (classInfo.url().toString().startsWith("file:")) { 57 | String cname = classInfo.getName(); 58 | Class type = Class.forName(cname); 59 | 60 | WebServlet servletAnn = type.getAnnotation(WebServlet.class); 61 | if (servletAnn != null) { 62 | for (String pattern : ObjectArrays.concat( 63 | servletAnn.value(), servletAnn.urlPatterns(), 64 | String.class)) { 65 | System.out.println("pattern:" + pattern + " servlet:" 66 | + cname); 67 | context.addServlet(new ServletHolder((HttpServlet) type 68 | .getConstructor().newInstance()), pattern); 69 | } 70 | } 71 | 72 | WebFilter filterAnn = type.getAnnotation(WebFilter.class); 73 | if (filterAnn != null) { 74 | for (String pattern : ObjectArrays.concat( 75 | filterAnn.value(), filterAnn.urlPatterns(), 76 | String.class)) { 77 | System.out.println("pattern:" + pattern + " filter:" 78 | + cname); 79 | DispatcherType[] disTypes = filterAnn.dispatcherTypes(); 80 | EnumSet dispatches = EnumSet 81 | .copyOf(Arrays.asList(disTypes)); 82 | context.addFilter(new FilterHolder((Filter) type 83 | .getConstructor().newInstance()), pattern, 84 | dispatches); 85 | } 86 | } 87 | 88 | WebListener listenAnn = type.getAnnotation(WebListener.class); 89 | if (listenAnn != null) { 90 | System.out.println("listener:" + cname); 91 | context.addEventListener((EventListener) type 92 | .getConstructor().newInstance()); 93 | } 94 | } 95 | } 96 | } 97 | 98 | } --------------------------------------------------------------------------------