Ebooks

Spring @MatrixVariable tutorial

Spring @MatrixVariable tutorial shows how to parse URL parameters with @MatrixVariable.

Spring is a popular Java application framework for creating enterprise applications.

@MatrixVariable

@MatrixVariable is used to parse name-value pairs within a path segment and bind them to method parameters. Multiple pairs are separated with semicolon. Matrix variables must be enabled first.

Spring @MatrixVariable example

The following application parses name-value pairs from the URL path segments.

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   ├───resources
│   └───webapp
│           index.html
└───test
    └───java

This is the project structure.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>matrixvariableex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>

        </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.4.14.v20181114</version>
            </plugin>

        </plugins>
    </build>
</project>

In the pom.xml file, we have the project dependencies.

com/zetcode/config/MyWebInitializer.java
package com.zetcode.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

@Configuration
public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

MyWebInitializer initializes the Spring web application. It contains one configuration class: WebConfig.

com/zetcode/config/WebConfig.java
package com.zetcode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.util.UrlPathHelper;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        var urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

The WebConfig configures the Spring web application.

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    var urlPathHelper = new UrlPathHelper();
    urlPathHelper.setRemoveSemicolonContent(false);
    configurer.setUrlPathHelper(urlPathHelper);
}

Here we enable matrix variables.

com/zetcode/controller/MyController.java
package com.zetcode.controller;

import org.springframework.http.MediaType;
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.RestController;

import java.util.Map;

@RestController
public class MyController {

    @GetMapping(value = "/user/{first}/{last}",
            produces = MediaType.TEXT_PLAIN_VALUE)
    public String handler1(@MatrixVariable("first") String first,
                       @MatrixVariable("last") String last) {

        return String.format("Hello %s %s", first, last);
    }

    @GetMapping(value = "/data/{user:.*}",
            produces = MediaType.TEXT_PLAIN_VALUE)
    public String handler2(@MatrixVariable Map<String, String> data) {

        return String.format("Id: %s\nFirst name: %s\nLast Name: %s\nEmail: %s\n",
                data.get("id"), data.get("first"), data.get("last"), data.get("email"));
    }

    @GetMapping(value = "/geo/{continent}",
            produces = MediaType.TEXT_PLAIN_VALUE)
    public String handler3(@PathVariable("continent") String continent,
                         @MatrixVariable("country") String country,
                         @MatrixVariable("capital") String capital) {

        return String.format("Continent: %s\nCountry: %s\nCapital: %s\n",
                continent, country, capital);
    }
}

MyController contains mappings of request paths to handler methods.

@GetMapping(value = "/user/{first}/{last}",
        produces = MediaType.TEXT_PLAIN_VALUE)
public String handler1(@MatrixVariable("first") String first,
                    @MatrixVariable("last") String last) {

    return String.format("Hello %s %s", first, last);
}

Here we bind multiple matrix variables to method parameters with @MatrixVariable.

@GetMapping(value = "/data/{user:.*}",
        produces = MediaType.TEXT_PLAIN_VALUE)
public String handler2(@MatrixVariable Map<String, String> data) {

    return String.format("Id: %s\nFirst name: %s\nLast Name: %s\nEmail: %s\n",
            data.get("id"), data.get("first"), data.get("last"), data.get("email"));
}

Here we map multiple name-value pairs into a map.

@GetMapping(value = "/geo/{continent}",
        produces = MediaType.TEXT_PLAIN_VALUE)
public String handler3(@PathVariable("continent") String continent,
                        @MatrixVariable("country") String country,
                        @MatrixVariable("capital") String capital) {

    return String.format("Continent: %s\nCountry: %s\nCapital: %s\n",
            continent, country, capital);
}

In the third case, we combine @MatrixVariable with @PathVariable.

webapp/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>

<p>
    <a href="http://localhost:8080/user/first=John/last=Doe">Greet user</a>
</p>

<p>
    <a href="http://localhost:8080/data/id=1;first=John;last=Doe;email=johndoe@gmail.com">Show user data</a>
</p>

<p>
    <a href="http://localhost:8080/geo/Europe;country=Slovakia;capital=Bratislava">Show country info</a>
</p>

</body>
</html>

This is the home page. We have three links that contain name-value pairs which are parsed with @MatrixVariable annotations.

In this tutorial, we have used @MatrixVariable to parse name-value pairs on the path segments and bind them to method parameters.

You might also be interested in these related tutorials: Spring @GetMapping tutorial, Spring DefaultServlet tutorial, Introduction to Spring web applications, and Java tutorial.