Preliminaries
For this tutorial you need:
- Eclipse Mars
- Apache Tomcat 8
- Java 8
Create a new Project
To get you a little bit more familiar with Spring, let's start with a short tutorial in which you set up a new Spring MVC project.
...
In the dialog that opens, from the folder 'Maven', select 'Maven Project'.
Click 'Next'. On the nex next page make sure the 'Use default Workspace location' checkbox is checked and 'Create a simple project' is unchecked. Click 'Next'.
...
So what just happened? You used Maven's archetype system to generate a new project with a particular structure, the structure of a typical webapp. Archetypes in Maven are blueprints of projects, and using those blueprints you can create new projects. There are a ton of archetypes for all kinds of purposes. We just used a very basic one.
Fix the Project
Next, we have to make sure our project has all necessary folders. Maven might have missed one or two. In the Project Explorer, open the folder 'Java Resources'. If this folder does not contain a folder called 'src/main/java' and/or 'src/test/java', do the following:
...
Once you've created those folders, right click on your project and select Maven > Update Project Select 'one' from the list of projects, and click 'OK'. You should now see the folder(s) you've just created under 'Java Resources'.
Add Spring Dependencies
...
Update Java Version
The maven archetype we used to create the project does not specify a Java version. Hence, the default compiler version is used, which is Java 1.5. We'll like to use the latest stable Java version (Java 8) though, so we need to tell Maven that.
Open the file 'pom.xml' of your new project. At the bottom of the editor, you have several tabs. Click on the 'pom.xml' tab.
Inside the 'dependencies' tag, add the following piece of code:
...
Add the following xml before the <dependencies>
tag.
Code Block | ||
---|---|---|
| ||
<properties> <maven.compiler.source>1.8</maven.compiler.source> <artifactId>spring-web</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <maven.compiler.target>1.8</maven.compiler.target> </properties> |
This will tell Maven to assume that your Java classes are written using Java 8 and that you want your compiled classes to be compatible with Java 8.
You can find more about this topic here.
Once you've updated your pom.xml, update the project again (right click your project > Maven > Update Project Select 'one'). If you check the build path of your project, you should now see that Java 8 is being used.
Add Spring Dependencies
Inside the 'dependencies' tag, add the following piece of code:
Code Block |
---|
<!-- Spring dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core<web</artifactId> <version>4.23.15.RELEASE</version> </dependency> |
Start up your project
Ok, so we are all set up. Let's see if the project starts up. Right click on your project and select 'Run As' > 'Run on Server'. Select what instance of Tomcat you want your project to run on (if you haven't done so, you need to add Tomcat to your Runtime Environments) and click 'Finish'. Once Tomcat has started, you should see a page that says 'Hello World!' in the browser that opens up in Eclipse.
Note: the project would have started just fine if we didn't add the Spring dependencies before. So far, Spring isn't doing anything.
Let Spring take over
Now, you are all setup to start with Spring. First, you need to tell Tomcat that you want Spring to handle incoming requests. You do this by specifying which servlet Tomcat should use as 'entry point' into your application. Open the file web.xml located in src > main > webapp > WEB-INF. Add the following code inside the 'web-app' tag after the 'display-name' section:
Code Block |
---|
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.5.RELEASE</version> </dependency> |
Start up your project
Ok, so we are all set up. If your Eclipse shows you an error marker saying that the HttpServlet is missing on the build path, ignore that for now. Your project should run just fine on Tomcat. After you ran it for the first time, follow the instructions in the info box below to get rid of the errors.
Let's see if the project starts up. Right click on your project and select 'Run As' > 'Run on Server'. Select what instance of Tomcat you want your project to run on (if you haven't done so, you need to add Tomcat to your Runtime Environments) and click 'Finish'. Once Tomcat has started, you should see a page that says 'Hello World!' in the browser that opens up in Eclipse.
Note: the project would have started just fine if we didn't add the Spring dependencies before. So far, Spring isn't doing anything.
Info | ||
---|---|---|
| ||
Eclipse might show you an error marker on your project, claiming that " |
Let Spring take over
Now, you are all setup to start with Spring. First, you need to tell Tomcat that you want Spring to handle incoming requests. You do this by specifying which servlet Tomcat should use as 'entry point' into your application. Open the file web.xml located in src > main > webapp > WEB-INF. Add the following code inside the 'web-app' tag after the 'display-name' section:
Code Block |
---|
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dispatcherspring/root-servletcontext.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> |
...
Code Block |
---|
<web-app id="WebApp_ID" version="23.31" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_23_31.xsd"> |
Your file should now look like this:
Code Block |
---|
<web-app id="WebApp_ID" version="23.31" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_23_31.xsd"> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> </web-app> |
What did you just do? First, you specified a servlet that Tomcat should know (the 'servlet' section). You named the servlet 'dispatcher' and you told Tomcat that you wanted it to be of type 'org.springframework.web.servlet.DispatcherServlet'. You also told Tomcat to initialize the dispatcher servlet with a file named servlet-context.xml located in WEB-INF > spring > appServlet.
Code Block |
---|
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
</servlet>
|
...
Now, we need to create the context specification files we referenced in the web.xml file. Create two new files called root-context.xml and servletFirst, let's create the folder structure. In your folder WEB-INF, create a folder spring. Inside this folder, create a folder called appServlet.
Then, create a new file called root-context.xml in the folder src > main > webapp > WEB-INF > spring (also create a spring folder in WEB-INF if you haven't done so yet). . And a file called servlet-context.xml in the folder src > main > webapp > WEB-INF > spring > appServlet.
The file root-context.xml should contain the following
Code Block |
---|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"4.3.xsd"> <context:component-scan base-package="edu.asu.diging.tutorial.spring.service" /> </beans> |
Basically, this This context specification tells Spring not to load anything. The file is empty besides the XML root element. This is okto scan everything in the package edu.asu.diging.tutorial.spring.service
and to load annotated classes. The root context specifies beans that should be present in all contexts (you can register more than just one servlet in web.xml and each creates its own context)). In our webapp, we want any business logic classes to be available everywhere, while controller classes (the first layer of responsibility) should only be accessible of the dispatcher servlet.
The file servlet-context.xml should contain:
Code Block |
---|
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="edu.asu.diging.tutorial.spring.web" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
|
...
And you specified that you want to use annotations for the registration of beansour controllers, which are all located in sub-packages inside of edu.asu.diging.tutorial.spring.web
:
Code Block |
---|
<context:component-scan base-package="edu.asu.diging.tutorial.spring.web" />
|
Restart your Tomcat or redeploy your application. It should start up without errors again. Note: check the output in your console at the bottom of the Eclipse window to see if exceptions were thrown. Also, scroll up in the console to make sure you're not missing any.
The first controller
Let's get started with the first controller. First, create a package called edu.asu.diging.tutorial.spring.web
in your Java source folder (under Java Resources > src/main/java). In this package, create a class called HomeController.
...
Code Block |
---|
INFO: Root mapping to handler 'homeController' |
How does Spring now know to serve up our index.jsp when all we return is 'index' in our controller method? Let's take a look at the servlet-context.xml again. We've specified the following bean:
...
This view resolver takes the path we return in our controller method, appends what we specified through the property suffix, prepends what we specified with the property prefix, and then tries to find the resulting file path. Try modifying our home() method in the HomeController to return 'index2
' instead instead of index
(you have to wait a second after you did the modifcation modification so that Eclipse can update the code in Tomcat (hotdeploy) or restart the server). If you now reload the page http://localhost:8080/one/ you should see a 404 error. If you rename index.jsp to index2.jsp, everything should work fine again.
Let's create a service
Ok, in the last section we looked at the 'view' and the 'controller' part of the MVC architecture. Let's connect our controller to a model. We start by creating a new package called 'edu.asu.diging.tutorial.spring.service
'. Inside this package, we create a class called 'MoodService
'. Let's also create a second class called 'Mood
' in another new package 'edu.asu.diging.tutorial.spring.domain
'. Your package structure should now look like this:
...
What did you just do? First we 'autowired' our our new service class MoodService
using Dependency Injection. Instead of instantiating the service class ourselves, we let Spring handle that for us. We just tell Spring that we want an object of type MoodService
. We do a similar thing in our home() method. We tell Spring that we want an object of type ModelMap
and Spring gives us an appropriate one object when calling the method. We than add an attribute to the ModelMap
that we can access in our JSP page.
...
Restart your server and reload *http://localhost:8080/one* you you should now see:
...
And now, on your own!
Whoohoo, you made it through the whole tutorial! Now, it's time for you to fly try it on your own. Try if you can get the following done:
...
- Remember how you autowired the MoodService? To use this technique to its whole extend, you also need to use an interface instead of a concrete implementation when autowiring. Try to use an interface when autowiring MoodService intead.
- Let's go crazy, and add a second page! Put a link on your index2 page that bring brings the user to a second page that explains why Tomcat feels the way it feels (e.g. if the first page says that Tomcat feels sad, the second page could say something like because it didn't catch any mice today).
- Last but not least, add your app to a repository in your GitHub account and send us a link so we can look at it.
You can find the source code for this tutorial here.
Comments/Updates
Removing pom.properties/additonal pom.xml
If you notice that you have an additional folder in your project that contains additional pom.properites and pom.xml files (in my case it duplicated the complete directory structure to my project folder starting with '/Users/') that are not your actual POM files, it is likely Maven's fault. If you want Maven to stop creating those files/directories, add the following to your pom.xml inside the build tag:
...