This page describes how to extract and tokenizing HTTP path variable(s).
Background
URL Path is often used by RESTful applications to pass scoping information. Applications often parse this information and use it to retrieve data from the server-side.
Modern frameworks like Spring MVC 3 and The RESTlet frameworks have means of extracting tokens from HTTP Path. However if you aren’t using those frameworks then the information on this page will be helpful.
The utility class described on this page will allow you to extract tokens present in URL paths. For example “item/{itemId}/subcomponent/{subComponentId}”
Requirements
- Maven 2
- Spring 2.5.6 or above
- Basic understanding of Struts MVC
Start a new project
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp
groupId: com.test
artifactId: pathVarTest
Answer the rest of the questions with defaults “Just hit the enter key”,
cd to the project base folder.
cd pathVarTest
Since this is a web project maven2 does not create the java source folder.
Create missing folders now.
mkdir -p src/main/java/com/test
mkdir -p src/main/webapp/WEB-INF/jsp
Modify the project Configuration
The pom.xml file should look something like this.
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>pathVarTest</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>pathVarTest Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-servlet_2.5_spec</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
<build>
<finalName>pathVarTest</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<scanIntervalSeconds>2</scanIntervalSeconds>
<stopKey>s</stopKey>
</configuration>
</plugin>
</plugins>
</build>
</project>
PathUtil
The following is where the URL path gets tokenized. It is a static utility class that could be used from a Spring MVC controller or a HTTPServlet Class.
src/main/java/com/test/PathUtil.java
package com.test;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Helper class to allow URL path's to be parsed into
* EL Expression type tokens.
*/
public class PathUtil {
public static final Map<String, String> getPathVariables(String patternStr,
String[] names, String path) {
String regExPattern = patternStr.replace("*", "(.*)");
Map<String, String> tokenMap = new HashMap<String, String>();
Pattern p = Pattern.compile(regExPattern);
Matcher matcher = p.matcher(path);
if (matcher.find()) {
// Get all groups for this match
for (int i = 0; i <= matcher.groupCount(); i++) {
String groupStr = matcher.group(i);
if (i != 0) {
tokenMap.put(names[i - 1], groupStr);
}
}
}
return tokenMap;
}
}
Spring MVC Controller
The following controller class responds to the following URL’s
- item/{itemId}
- item/{itemId}/subcomponent/{subComponentId}
src/main/java/com/test/ItemController.java
package com.test;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class ItemController {
@RequestMapping(value="/item/*", method = RequestMethod.GET)
public String itemInfo(HttpServletRequest request) {
final String pattern = "/item/*";
final String[] names = {"itemId"};
Map<String, String> pathMap = PathUtil.getPathVariables(pattern, names, request
.getPathInfo());
request.setAttribute("pathMap", pathMap);
return "index";
}
@RequestMapping(value="/item/*/subcomponent/*", method = RequestMethod.GET)
public String subComponentItemInfo(HttpServletRequest request) {
final String pattern = "/item/*/subcomponent/*";
final String[] names = {"itemId", "subComponentId"};
Map<String, String> pathMap = PathUtil.getPathVariables(pattern, names, request
.getPathInfo());
request.setAttribute("pathMap", pathMap);
return "index";
}
}
JSP
The following JSP is used to display the Hash Map that contains the results. I haven’t put any work in making it look pretty. Its just functional.
src/main/webapp/WEB-INF/jsp/index.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Language" content="en-us" />
</head>
<body>
<h3>This are the tokens from the URL Path Info String</h3>
<h3><c:out value="${pathMap}"/></h3>
</body>
</html>
Web App Configuration
src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
Spring MVC Configuration file
This is a pretty standard Spring MVC configuration file.
src/main/webapp/WEB-INF/spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="com.test" />
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Test the application
Start the Jetty Servlet Engine to test the application with 1 scoping variable.
- Open a command line window and navigate to the project base directory.
- Type the following at the command line:
mvn clean compile jetty:run
- Navigate to the following URL: http://localhost:8080/app/item/235
- You should see the next page which prints “{itemId=235}”.
Test the application with multiple scoping variables.
- Navigate to the following URL: http://localhost:8080/app/item/123/subcomponent/456
- You should see the next page which prints “{subComponentId=456, itemId=235}”.
Creating a WAR file
If you want to run the application in another environment you can create a war file and drop it into a server of your choice. This method will also package up any runtime dependencies and put them in the /WEB-INF/lib folder of the WAR file.
mvn clean compile package
The war file should appear in the project’s “target/” folder…
That’s all for now!
2 Responses to “Extracting and Tokenizing HTTP Path Variables”