Scaffold your ideas into application
Get your free alpha access now.
Only 445 left, Hurry!
24 Oct 2016

Spring MVC tutorial

Spring MVC

This is the sixth part of J2EE beginner series and in this post we would add Spring MVC to the application which we have been developing for a while now. Please take some time to read earlier parts

  1. What is a server?
  2. Servlets
  3. JSP
  4. JDBC
  5. Hibernate

To get started we would need the code base of the application we have been developing through this series. If you have not been following us, you can download the pre built source or clone it from github and checkout branch hibernate.

if you are new to Spring, I would highly recommend reading Spring IOC Primer.

We would start by adding our spring dependency to the pom.xml, though we would need only some of the modules of spring framework like web mvc and orm, it is important to understand how spring is split in modules.

  • Spring-core
    • Has the core utilities which are used by spring framework internally. Mostly as a developer you would not interact much with it.
  • Spring Context
    • Has the application context runtime related classes.
  • Spring Beans
    • Beans support, Bean Factory, Post Processors etc
  • Spring AOP
    • AOP related classes, even though you are not using aop directly, spring uses aop to provide transaction support and other features.
  • Spring orm
    • Integration with ORM like hibernate.
  • Spring web
    • Web support packages.
  • Spring web mvc
    • model-view-controller implementation for web applications

This looks confusing but maven helps us keep things clear, we need to include only top level modules i.e webmvc and orm and all the dependency would automatically get included.

pom.xml

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.0.9.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>4.0.9.RELEASE</version>
    </dependency>

We will continue to use servlet 2.5 in this series as its a beginner series, hence we would configure our spring controller in web.xml

if you remember from third part of the series JSP, we created our own sort of MVC by using servlet and JSP for controller and view.

In traditional MVC framework you would find following patterns.

  • Front Controller
    • All the request is intercepted by single Servlet and delegated to some classes, it is usually Controller in Spring, Action in Struts.
    • In Spring MVC, this class is DispatcherServlet
  • Command
    • A delegate class which executes a command from Front Controller. Typically Command object would have a execute or similar method which handles the request.
    • In Spring its AbstractHandlerMethodAdapter.handleInternal
  • Chain Of Responsibility
    • These are usually filters or interceptors which are called in loop before or after the request is processed.

Lets go ahead and add DispatcherServlet to our web.xml

web.xml

<servlet>
      <servlet-name>test</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>

    <servlet-mapping>
      <servlet-name>test</servlet-name>
      <url-pattern>*.htm</url-pattern>
   </servlet-mapping>

Notice the url-pattern as .htm, this is just a way to tell server to send all request ending with htm to this servlet. This ensures that request for static resources are not routed to this servlet.

If you are building REST style application the .htm extension may bother you, in such cases you can leave url-pattern as / and use mvc:resources to tell spring the location of folder for static resources.

Since we have defined our servlet name as test, spring would expect a file called test-servlet.xml in WEB-INF location. Quite frankly I find that very annoying as I prefer to keep my context file in src/main/resources instead of WEB-INF as we can use the same xml file and context for unit testing if we keep it in classpath.

We can override the default location by adding init-param like this.

<servlet>
      <servlet-name>test</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath*:app-context.xml
            </param-value>
        </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>

Now lets add app-context.xml to our src/main/resources directory.

app-context.xml

  <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-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:component-scan base-package="com.scaffoldthis" />

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="suffix" value=".jsp" />
   </bean>

</beans>

The most powerful line of this xml is

   <context:component-scan base-package="com.scaffoldthis" />

This essentially asks spring to look for any class marked with any spring related annotation in the package com.scaffoldthis. This would search not only for web controllers but every thing related to spring like @controller, @Service, @Component, @Repository, @Configuration etc.

You can also instantiate spring mvc using <mvc:annotation-driven>which is essentially same as above, but looks for only web related annotation i.e @Controller, in most of the simple cases like this, you would not need it but in more complex cases where we need to customize the spring mvc behavior, we would need to add the annotation-driven to our configuration.

Now if you remember our JSP, we had our DemoServlet and CreateUserServlet. Lets convert them now into Spring MVC Controllers.

DemoController.java

@Controller
public class DemoController {

    @Resource
    UserHibernateDao userHibernateDao;

    @RequestMapping(value="/login",method=RequestMethod.POST)
    public String login(@RequestParam("username") String username,@RequestParam("password")String password){
        if(userHibernateDao.isValidUser(username, password)){
            return "home";
        }
        else
        {
            return "redirect:login";
        }
    }
}

If you notice, now we are configuring the path in annotation instead of web.xml and using @RequestParam spring would extract the param for us and pass it as parameter which simplifies our code.

Also we are no longer creating a new reference of UserHibernateDao and using it as spring provided dependency, for which we need to add @Component annotation on UserHibernateDao

UserHibernateDao.java

@Component
public class UserHibernateDao {

CreateUserController.java

@Controller
public class CreateUserController {

    @Resource
    UserHibernateDao userHibernateDao;

    @RequestMapping(value="/createUser",method=RequestMethod.POST)
    public String createUser(@RequestParam("username") String username,@RequestParam("password")String password){

        userHibernateDao.createUser(username, password);

        return "redirect:login";
    }
}

The return from controller is a view name which would mapped as per the viewResolver rules which we have configured in our context. So

return "home";

is equivalent to

req.getRequestDispatcher("home.jsp").forward(req, resp);

and

 return "redirect:login";

is equivalent to

  resp.sendRedirect("login.jsp");

We would also need to update the JSP form url to /createUser.htm and /login.htm as we have defined in the controller.

It is generally considered best practice to put all jsp files under WEB-INF instead of webapp folder with MVC, this way no one can execute the JSP without going through MVC, thereby giving more control and security.

So lets move our jsps to WEB-INF/jsp and create a delegate controller method to render the JSP.


@Controller
public class CreateUserController {

    @RequestMapping(value="/createUser",method=RequestMethod.GET)
    public String showCreateUserPage(){
        return "createUser";
    }

    @RequestMapping(value="/createUser",method=RequestMethod.POST)
    public String createUser(@RequestParam("username") String username,@RequestParam("password")String password){

        userHibernateDao.createUser(username, password);

        return "redirect:login";
    }

If you notice we are using the same URL for GET and POST, since by default it the form does not have any action attribute defined, it would submit back to same URL it was loaded from.

@Controller
public class DemoController {

    @Resource
    UserHibernateDao userHibernateDao;

    @RequestMapping(value="/login",method=RequestMethod.GET)
    public String showLoginPage(){
        return "login";
    }

    @RequestMapping(value="/login",method=RequestMethod.POST)
    public String login(@RequestParam("username") String username,@RequestParam("password")String password){
        if(userHibernateDao.isValidUser(username, password)){
            return "home";
        }
        else
        {
            return "redirect:login";
        }
    }
}

Now lets update our viewResolver to tell Spring where to look for, for the JSP.


<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
   </bean>

In the next part, we would change our hibernate dao to look at spring integration with hibernate.


Stats:
102 views
Scaffold your ideas into application
Get your free alpha access now.
Only 445 left, Hurry!

Angular Directives Demystified

Directives are the most misunderstood aspect of angular JS. Learn how directives can help you keep your code clean.

Third wave of digital transformation

Third wave of digital transformation

Angularjs Tutorial: Understanding Scope

Scopes are one of the most important and rarely understood concept in angular, in this part we explore how scope works in angularjs.

Comments:

Leave your comments