Playing with Spring MVC

In Spring MVC, the following is a pattern of a simplified request handling mechanism:

  1. DispatcherServlet receives a request and confers the request with handler mappings to find out which controller can handle the request, and then passes the request to that controller.
  2. The controller performs the business logic (can delegate the request to a service or business logic processor) and returns some information back to DispatcherServlet for user display or response. Instead of sending the information (model) directly to the user, the controller returns a view name that can render the model.
  3. DispatcherServlet then resolves the physical view from the view name and passes the model object to the view. This way, DispatcherServlet is decoupled from the view implementation.
  4. The view renders the model. A view could be a JSP page, a servlet, a PDF file, an excel report, or any presentable component.

The following sequence diagram represents the flow and interaction of Spring MVC components:

Playing with Spring MVC

We will build a Spring web application and unit test the code using JUnit. The following are the steps to be performed:

  1. Launch Eclipse and create a dynamic web project named SpringMvcTest.
  2. Open web.xml and enter the following lines:
    <display-name>SpringMVCTest</display-name>
    <servlet>
      <servlet-name>dispatcher</servlet-name>
      <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
      </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/dispatcher-servlet.xml
        </param-value>
      </context-param>
    </web-app>

    The dispatcher is named DispatcherServlet, and it maps all requests. Note the contextConfigLocation parameter. This indicates that the Spring beans are defined in /WEB-INF/dispatcher-servlet.xml.

  3. Create an XML file named dispatcher-servlet.xml in WEB-INF and add the following lines:
    <?xml version="1.0" encoding="UTF-8"?>
    <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.packt" />
     <bean class= "org.springframework.web.servlet.view.
        InternalResourceViewResolver">
      <property name="prefix">
        <value>/WEB-INF/pages/</value>
      </property>
      <property name="suffix">
          <value>.jsp</value>
        </property>
      </bean>
    </beans>

    This XML defines a Spring view resolver. Any view will be found under the /WEB-INF/pages location with the .jsp suffix, and all beans are configured under the com.packt package with Spring annotations.

  4. Create a class named LoginInfo in the com.packt.model package. This class represents the login information. Add two private String fields, userId and password, and generate the getters and setters.
  5. Create a JSP page named login.jsp under /WEB-INF/view, and add the following lines to create a form using the Spring tag library. Modify the form and add normal HTML input for username and password:
    <%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
    <sf:form method="POST" modelAttribute="loginInfo" action="/onLogin">
      
    </sf:form>
  6. Create a controller class named com.packt.controller.LoginController to handle login requests. Add the following lines:
    @Controller
    @Scope("session")
    public class LoginController implements Serializable {
      @RequestMapping({ "/", "/login" })
      public String onStartUp(ModelMap model) {
        model.addAttribute("loginInfo", new LoginInfo());
        return "login";
      }
    }

    The @Controller annotation indicates that the class is a Spring MVC controller class. In smapl-servlet.xml, we defined <context:component-scan base-package="com.packt" />, so Spring will scan this @Controller annotation and create a bean. The @RequestMapping annotation maps any request with the default path /SpringMvcTest/ or /SpringMvcTest/login to the onStartUp method. This method returns a logical view name login. The view resolver defined in the XML file will map the login request to the physical view login.jsp page under /WEB-INF/pages.

  7. Create another method in the Login class to handle the login and submit requests, as follows:
    @RequestMapping({ "/onLogin" })
    public String onLogin(@ModelAttribute("loginInfo") LoginInfo loginInfo, ModelMap model) {
      if(!"junit".equals(loginInfo.getUserId())) {
        model.addAttribute("error", "invalid login name");
        return "login";
      }
      if(!"password".equals(loginInfo.getPassword())) {
        model.addAttribute("error", "invalid password");
        return "login";
      }
      model.addAttribute("name", "junit reader!");
      return "greetings";
    }

    The onLogin method is mapped with /onLogin. The @ModelAttribute("loginInfo") method is the model submitted from the login.jsp form. This method checks whether the username is junit and password is password. If the user ID or password does not match, then an error message is shown on the login page, otherwise, the greetings view is opened.

  8. Change the content of the login.jsp file to submit the form to /SpringMvcTest/onLogin and the modelattribute name to loginInfo, as follows:
    <sf:form method="POST" modelAttribute="loginInfo" action="/SpringMvcTest/onLogin">

    Also, add the <h1>${error}</h1> JSTL expression to display the error message.

  9. Create a JSP file named greetings.jsp and add the following lines:
    <h1>Hello :${name}</h1>
  10. In the browser, enter http://localhost:8080/SpringMvcTest/; this will open the login page. On the login page, do not enter any value and just click on Submit. It will show the invalid login name error message. Now, enter junit in the User Id field and password in the Password field and hit Enter. The application will greet you with the message shown in the following screenshot:
    Playing with Spring MVC

We can unit test the controller class. The following are the steps:

  1. Create a LoginControllerTest.java class in com.packt.controller.
  2. Using the following code, add a test to check that when the user ID is null, the error message is thrown:
    public class LoginControllerTest {
      LoginController controller = new LoginController();
      @Test
      public void when_no_name_entered_shows_error_message(){
        ModelMap model = new ModelMap();
        String viewName = controller.onLogin(new LoginInfo(), model);
        assertEquals("login", viewName);
        assertEquals("invalid login name", model.get("error"));
      }
    }
  3. Add another test to check invalid passwords, as follows:
    @Test
    public void when_invalid_password_entered_shows_error_message()   {
      ModelMap model = new ModelMap();
      LoginInfo loginInfo = new LoginInfo();
      loginInfo.setUserId("junit");
      String viewName =controller.onLogin(loginInfo, model);
      assertEquals("login", viewName);
      assertEquals("invalid password", model.get("error"));
    }
  4. Add a happyPath test, as follows:
    @Test   public void happyPath(){
      loginInfo.setUserId("junit");
      loginInfo.setPassword("password");
      String viewName =controller.onLogin(loginInfo, model);
      assertEquals("greetings", viewName);
    }

This is just an example of Spring MVC, so we checked the username and password with the hardcoded constants. In the real world, a service looks up the database for the user and returns an error message; the service can be autowired to the controller. This way, we can unit test the controller and the service layer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.10.130