In a previous post I explained how to set up spring with maven project, manually in eclipse. In this post we will do the same using the STS eclipse, which is much easier.
First of all, to have a common background and help the new ones in spring, let’s explain a few things. STS stands for Spring Tool Suite and is pretty much an Eclipse IDE with the Spring tools pre installed. You may download it from here . It comes in different versions, which differ in eclipse version and spring tools.
If you do not like to change your current eclipse installation and still want to have all the benefits of spring tools, download just the plugin and install it in your existing plugin. The tools plugin can be found and installed from eclipse market place, find information for the market site in here
I currently use the STS version 2.9.2 whith an indigo eclipse.
Open your STS or your eclipse with the sts plugin installed and choose
File -> New -> Other -> SpringSource Tool Suite -> Spring Template Project
So, in our STS we will create an mvc project, with loggging and junit testing ready – in another post we’ll add a datasource to work with.
On template selection select the obvious, Spring MVC Project:
On the next step of the wizard name your project, e.g. springSample, give a root level package :
And click finish.
Now let’s have a look what was created for us:
Pretty much everything we need:
– Directory to place our source code: src/main/java
– Directory to put our resources – xmls, properties files … – src/main/resources
– directory to place our test code: src/test/java
– Directory to place our test resources
– Web application root directory to place our web app pages and assets: src/main/webapp
Most importantly we have the spring environment set. The web xml has all apropriate configuration, such as the ContextListener, the servlet Dispatcher and forwarding all requests to the dispatcher set.
Additional configuration, is ready as follows:
– The annotation driven environment is ready, configured int he servlet-context.xml
– We can add any number of spring bean files in the src/main/resources directory
– we can add our pages in the src/main/webapp/WEB-INF/views, directory. There is already a sample page there the home.jsp.
You can also check the pom.xml file to see what libraries imports. Actually NOT all libraries found there are important to have a spring mvc project. I will not go into this. We will leave the pom as is. The only thing I will do is to change version of the spring, to show how easy it is to do.
We will do this in the properties of the maven file, the pom.xml. So we will alter from the 3.1.0:
<properties> <java-version>1.6</java-version> <org.springframework-version>3.1.0.RELEASE</org.springframework-version> <org.aspectj-version>1.6.9</org.aspectj-version> <org.slf4j-version>1.5.10</org.slf4j-version> </properties>
To the following:
<properties> <java-version>1.6</java-version> <org.springframework-version>3.1.2.RELEASE</org.springframework-version> <org.aspectj-version>1.6.9</org.aspectj-version> <org.slf4j-version>1.6.1</org.slf4j-version> </properties>
I also altered the org.slf4j-version from 1.5.10 to 1.6.1 because of some compatibilities issues I run into. Do the same if you too wish to use the 3.1.2 version of spring. Otherwise leave ALL properties as they are.
Right click the project, choose maven -> Update Dependencies, let eclipse finish the job, then again right click and choose maven -> Update Project Configuration and let it finish.
Now, let’s see if everything works as expected. Go to com.spring.sample.HomeController page. There is already a web method the home. This listens to the root path ‘/’ of our application as the @RequestMapping indicates. Let’s check if it actually works.
Most probably the home method will be as follows:
@RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) { logger.info("Welcome home! the client locale is "+ locale.toString()); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "home"; }
Which means that once it is called it returns as model attribute – request attribute – the time in your machine and afterwards it calls the home view, or the home page. This will be the home.jsp.
Let us change the method a bit, so we add our own signature in the testing – and for some new of us to understand how this spring works – as follows:
/** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) { logger.info("Welcome home! the client locale is "+ locale.toString()); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); formattedDate = "The date in my machine is: " + formattedDate + "."; model.addAttribute("myHomeMessage", formattedDate ); return "home"; }
So we will show in the page the message: The date on my machine is: February 8, 2013 …
Go to the home.jsp and alter as follows:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %> <html> <head> <title>Home</title> </head> <body> <h1> Hello world! </h1> <P> ${myHomeMessage}. </P> </body> </html>
Now we will run the project. Set up a tomcat – or a jboss, or any other jee – server and deploy the project – if you do NOT know you definetely need to read some documentation about the eclipse. Run the server and hit the following url in the browser:
http://localhost:8080/sample
If the previous is not working or you are not sure about the context-root of the app, right click your project in the package explorer and choose web project settings. The context-root of your app appear on the right:
and you will see the following in the browser:
Hello world!
The date in my machine is: February 8, 2013 6:21:57 PM EET..
Which means that we are ok!! Our method called successfully and our message has been displayed correctly!
Additionally in tomcat’s output console we can see the follogin line:
INFO : com.spring.sample.HomeController – Welcome home! the client locale is en_US
Which also means that our log4j is setup correctly – the previous line was output due to the follwoing piece of code in our method: logger.info(“Welcome home! the client locale is “+ locale.toString());
To gain more confidence in our project we will create a fresh new controller and a new page which the controller will feed and call. We will create a page which will output a message, taken from the controller. The method will listens to the path: /sample/halloAction
First we will create a dedicated package for our controllers. We can add it anywhere we like – there is no limitation to which package a controller is placed – though with this we can have our code in order. In a few classes projects order may sound useless though in a few dozens it can be very helpful.
So, lets create a dedicated package for our controllers. We will create the package: com.spring.sample.controller. Now we create a class named com.spring.sample.controller.GreetController – another handy thing is to use as suffix the actuall name of the component. E.g. all controller java class names end in Controller, all services in Service and so on. THis help us understand from the name of the class what component is the class.
In order to make the spring understands that this class is a controller the only thing we need to add, is the annotation @Controller on the class as follows:
package com.spring.sample.controller; import org.springframework.stereotype.Controller; /** * @author gred * */ @Controller public class GreetController { }
We will create a method which will listens to the path sample/halloAction. The method name will be hallo taking as argument the model, in which we will place the message to send to the page.
Our method will be:
@RequestMapping(value="/halloAction", method = RequestMethod.GET) public String hallo(Model model) { String theMessage = "Hallo Stranger!"; model.addAttribute("halloMessage", theMessage); return "hallo"; }
Let’s examine the method a little:
– RequestMapping: is the annotation that tells spring to which http request this method must be called. The value inside the RequestMapping annotation is the request, relative to context-root of the app. THis means that we do not need to add the whole request path: /sample/halloAction but the rest beyond the sample, cause the sample is the root of our web app and should be ommited. The RequestMethod.GET indicates that it is a GET Http request.
– We send to the hallo page the Hallo Stranger message.
Spring understands from the hallo that it should try to find a hallo.jsp page in the views directory from the configuration in the servlet-context.xml file. The following lines do that:
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --> <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <beans:property name="prefix" value="/WEB-INF/views/" /> <beans:property name="suffix" value=".jsp" /> </beans:bean>
So whether you wish to alter the directory of your pages feel free to do so by altering these lines – actually the second line.
Next we create our hallo.jsp file in the view and add the following lines:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %> <html> <head> <title>Home</title> </head> <body> <h1> Hello world! </h1> <P> ${halloMessage} </P> </body> </html>
And we are ready to test our page. Deploy the app again and use the following url in your browser:
http://localhost:8080/sample/halloAction
and we see the following:
Hello world!
Hallo Stranger!
I believe that you got it and you are ready to build your app. A couple of things are missing.
The first is testing and is the one that follows in the next paragraphs. The other is the datasource!! Normally we will need a datasource and a persistence framework to use in our application! I will post in the next days a related post, as an extension to this. For now let’s see how to set up the environment for junit testing.
Before doing anything else we need our appropriate dependencies. Add the following xml lines in your pom.xml file:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework.version}</version> <scope>test</scope> </dependency>
Actually the junit already existed. Just alter the version and add the spring-test dependency.
The test packages are there and ready to use them. Let’s create a test class named com.sample.spring.MainTests in the src/test/java source directory.
The MainTests class should look like the following:
package com.spring.sample; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"}) public class MainTests { }
The 2 annotations are:
– The annotation @RunWith(SpringJunit4ClassRunner.class) is to add the spring unit testing capability in our testing and the
– The @ContextConfiguration… tells the spring where to find the context files. Currently we only use one, the springapp-serlvlet.xml. If we used more and we wanted them in the tests we would add it here, as comma seperated strings.
We will test our halloAction with Mock request. So alter the MainTests as follows:
package com.spring.sample; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; import com.spring.sample.controller.GreetController; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"}) public class MainTests { @Autowired ApplicationContext applicationContext; private MockHttpServletRequest request; private MockHttpServletResponse response; private HandlerAdapter handlerAdapter; @Autowired private GreetController greetController; @Before public void setUp() { request = new MockHttpServletRequest(); response = new MockHttpServletResponse(); handlerAdapter = new AnnotationMethodHandlerAdapter(); } @Test public void testHallo() throws Exception { request.setRequestURI("/halloAction"); request.setMethod("GET"); final ModelAndView mav = handlerAdapter.handle(request, response, greetController); assertEquals("Hallo Stranger!", mav.getModel().get("halloMessage")); assertEquals("hallo", mav.getViewName()); } }
The method setUp which is annotated as before will be called before the tests because of the annotation.
This is the approach to test the actual web request and not just the method in our controller. To test the methods in our controllers we would use just the junit tests as we know it, just by adding the context xml files. In order to test web requests and verify proper running this is the way. These are the steps:
– Create a mockRequest and response before the tests
– Use the handlerAdapter to call the request you wish, by passing the mock request, mock response and the corresponding controller. The handlerAdapter will return a ModelAndView with which you can test if proper model attributes exist, with proper values and if the appropriate view.
Our controller adds in model an attribute named halloMessage with the value Hallo Stranger! which will be tested with the following line:
assertEquals(“Hallo Stranger!”, mav.getModel().get(“halloMessage”));
While the view returned by our method is the hallo, which will be tested with the following:
ssertEquals(“hallo”, mav.getViewName());
You may add as many methods in the class to test other web methods, or add other classes and use the same trick. Of course you can test other classes or layers – e.g. service layer, or dao layer – without the mock requests and responses. Just by plain junit testing!
Datasource set up in spring will be explained in a seperate post!
ENJOY!
gred