Spring MVC 4 - @MatrixVariable annotation example

Posted on April 9, 2017


Technologies used:   JDK 1.8.0_121 | Spring 4.3.7.RELEASE | Maven 3.3.9 | Apache Tomcat 7.0.47 | Eclipse Neon.3

In Spring MVC, a name-value pair within a path segment is referred as matrix variable. Matrix variables can appear in any path segment, each variable separated with a semicolon (;) and multiple values are separated by comma (,);

Following are the examples of matrix variables-

 http://www.example.com/user/firstName=Sunil/lastName=Singh
 http://www.example.com/employee/Mike;salary=45000;dept=HR
 http://www.example.com/car/Audi;color=RED,BLACK,WHITE

The @MatrixVariable annotation is used to bind the matrix variables to method parameters in a controller.

The following examples demonstrate how the @MatrixVariable annotation works in Spring application.

Jar dependencies

Add the following jar dependencies in your pom.xml file.

<!-- Spring MVC Dependency -->
  <dependency>
	 <groupId>org.springframework</groupId>
	 <artifactId>spring-webmvc</artifactId>
	 <version>4.3.7.RELEASE</version>
  </dependency>

  <!-- JSTL Dependency -->
  <dependency>
	 <groupId>javax.servlet.jsp.jstl</groupId>
	 <artifactId>javax.servlet.jsp.jstl-api</artifactId>
	 <version>1.2.1</version>
  </dependency>
  <dependency>
	 <groupId>taglibs</groupId>
	 <artifactId>standard</artifactId>
	 <version>1.1.2</version>
  </dependency>

  <!-- Servlet Dependency -->
  <dependency>
	 <groupId>javax.servlet</groupId>
	 <artifactId>javax.servlet-api</artifactId>
	 <version>3.1.0</version>
	 <scope>provided</scope>
  </dependency>

Controller class

Create a @Controller class whose handler methods are annotated with @GetMapping annotation and method parameters are annotated with @MatrixVariable and @PathVariable annotation.

Use the @ResponseBody annotation to bind the handler method’s return type to the web response body.

MyController.java

package com.boraji.tutorial.spring.controller;

import java.time.LocalDate;
import java.util.Arrays;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author imssbora
 */
@Controller
public class MyController {

   /*
    * Binding a matrix variable to a method parameter
    */
   @GetMapping("/user/{name}")
   @ResponseBody
   public String handler(@MatrixVariable("name") String name) {

      return "Matxrix variable <br> "
            + "name =" + name;
   }
   
   /*
    * Binding multiple matrix variables to  method parameters
    */
   @GetMapping("/user/{firstName}/{lastName}")
   @ResponseBody
   public String handler(@MatrixVariable("firstName") String firstName,
         @MatrixVariable("lastName") String lastName
         ) {

      return "<br>Matxrix variable <br> "
            + "firstName =" + firstName +"<br>"
            + "lastName =" + lastName;
   }
   
   /*
    * Binding matrix variables and path variables
    */
   @GetMapping("/employee/{name}")
   @ResponseBody
   public String handler(@PathVariable("name") String name,
         @MatrixVariable("salary") double salary,
         @MatrixVariable("dept") String dept
         ) {

      return "Path Variables <br>"
            + "name = "+ name +"<br>"
            + "<br>Matxrix variable <br> "
            + "salary =" + salary +"<br>"
            + "dept =" + dept;
   }
   
   /*
    * Binding matrix variables having same name in different path segments
    */
   @GetMapping("/employee/{name}/{address}")
   @ResponseBody
   public String handler(@PathVariable("name") String name,
         @MatrixVariable(name="id", pathVar="name") int empId,
         @MatrixVariable("dept") String dept,
         @PathVariable("address") String address,
         @MatrixVariable(name="id", pathVar="name") int addrId
         ) {

      return "Path Variables <br>"
            + "name = "+ name +"<br>"
            + "address = "+ address +"<br>"
            + "<br>Matxrix variable <br> "
            + "empId =" + empId +"<br>"
            + "dept =" + dept +"<br>"
            + "addrId =" + addrId;
   }
   
   /*
    * Binding matrix variable with multiple values
    */
   @GetMapping("/car/{name}")
   @ResponseBody
   public String handler(@PathVariable("name") String name,
         @MatrixVariable("color") String[] color
         ) {

      return "Path Variables <br>"
            + "name = "+ name +"<br>"
            + "<br>Matxrix variable <br> "
            + "colors =" + Arrays.asList(color);
   }
   
   /*
    * Binding a matrix variable with optional and default value
    */
   @GetMapping("/person/{name}")
   @ResponseBody
   public String handler(@PathVariable("name") String name,
         @MatrixVariable("dob") @DateTimeFormat(pattern="yyyy-MM-dd") LocalDate dob,
         @MatrixVariable(required=false, defaultValue="91XXXXXXXX") String mobile
         ) {

      return "Path Variables <br>"
            + "name = "+ name +"<br>"
            + "<br>Matxrix variable <br> "
            + "dob =" + dob +"<br>"
            + "mobile =" + mobile;
   }
}

 

Spring configuration

By default, matrix variables are disabled in Spring MVC. To enable matrix variable add the following code snippet in configuration.

public void configurePathMatch(PathMatchConfigurer configurer) {
  UrlPathHelper pathHelper = new UrlPathHelper();
  //Enable matrix variable
  pathHelper.setRemoveSemicolonContent(false);
  configurer.setUrlPathHelper(pathHelper);
}

The following is a complete web @Configuration class annotated with @EnableWebMvc and @ComponentScan.

WebConfig.java

package com.boraji.tutorial.spring.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.util.UrlPathHelper;

/**
 * @author imssbora
 */

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.boraji.tutorial.spring.controller" })
public class WebConfig extends WebMvcConfigurerAdapter {

   @Bean
   public InternalResourceViewResolver resolver() {
      InternalResourceViewResolver resolver = new InternalResourceViewResolver();
      resolver.setViewClass(JstlView.class);
      resolver.setPrefix("/WEB-INF/views/");
      resolver.setSuffix(".jsp");
      return resolver;
   }

   @Override
   public void configurePathMatch(PathMatchConfigurer configurer) {
      UrlPathHelper pathHelper = new UrlPathHelper();
      //Enable matrix variable
      pathHelper.setRemoveSemicolonContent(false);
      configurer.setUrlPathHelper(pathHelper);
   }

}

The @EnableWebMvc enables default Spring MVC configuration and provides the functionality equivalent to <mvc:annotation-driven/> element in XML based configuration.

The @ComponentScan scans the stereotype annotations (@Controller@Service etc...) in a package specified by basePackages attribute.

Servlet container initialization

Create a container initializer class by extending the AbstractAnnotationConfigDispatcherServletInitializer class as follows.

MyWebAppInitializer.java

package com.boraji.tutorial.spring.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * @author imssbora
 */
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

   @Override
   protected Class<?>[] getRootConfigClasses() {
      return new Class[] {};
   }

   @Override
   protected Class<?>[] getServletConfigClasses() {
      return new Class[] { WebConfig.class };
   }

   @Override
   protected String[] getServletMappings() {
      return new String[] { "/" };
   }
}

The AbstractAnnotationConfigDispatcherServletInitializer class, implements the WebApplicationInitializer, is implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically.

 

Build + Deploy + Run application

Use the following maven commands to build, deploy and run embedded Tomcat server.

mvn clean install  (This command triggers war packaging)

mvn tomcat7:run (This command run embedded tomcat and deploy war file automatically)

You can refer this link to learn how to run the above commands in Eclipse IDE.

 

Type the following URLs in browser's address bar and see output…

1 - http://localhost:8080/user/name=sunil

SpringMVC-MatrixVariable1.png

2 - http://localhost:8080/user/firstName=Sunil/lastName=Singh

SpringMVC-MatrixVariable2.png

3 - http://localhost:8080/employee/Mike;salary=45000;dept=HR

SpringMVC-MatrixVariable3.png

4 - http://localhost:8080/employee/Mike;id=12;dept=HR;/India;id=25

SpringMVC-MatrixVariable4.png

5 - http://localhost:8080/car/Audi;color=RED,BLACK,WHITE

SpringMVC-MatrixVariable5.png

6 - http://localhost:8080/person/Mike;dob=2017-02-12

SpringMVC-MatrixVariable6.png