Build a URL Shortener in Java Using Servlets
URL shorteners are ubiquitous in modern web applications, useful for creating concise, shareable links while logging traffic and managing redirection logic. In this tutorial, we’ll build a simple URL shortener using Java Servlets. We’ll generate unique slugs, handle HTTP redirects, and persist our link mappings in-memory using a HashMap.
Let’s walk through the entire process—starting from setting up your project to deploying and testing your service.
1. Project Setup and Requirements
To follow along, you’ll need basic knowledge of Java and an understanding of web programming with Servlets. We will use the following technologies:
- Java 8 or higher
- Apache Tomcat (or any servlet-compatible container)
- Maven (for dependency management)
Start by creating a new Maven web project. Your pom.xml
should include:
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
2. Designing the Core Servlet
Our URL shortener will have two core actions:
- Accept long URLs and return a short slug
- Redirect users from a short slug to the original long URL
Create a servlet named UrlShortenerServlet
that maps to both actions.
@WebServlet("/url/*")
public class UrlShortenerServlet extends HttpServlet {
private final Map<String, String> urlMap = new ConcurrentHashMap<>();
private final String domain = "http://localhost:8080/url/";
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String longUrl = req.getParameter("longUrl");
if (longUrl == null || longUrl.isEmpty()) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing longUrl parameter");
return;
}
String slug = generateSlug();
urlMap.put(slug, longUrl);
resp.setContentType("application/json");
PrintWriter writer = resp.getWriter();
writer.write("{\"shortUrl\": \"" + domain + slug + "\"}");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String slug = req.getPathInfo();
if (slug == null || slug.length() <= 1) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
slug = slug.substring(1); // remove leading '/'
String longUrl = urlMap.get(slug);
if (longUrl == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
} else {
resp.sendRedirect(longUrl);
}
}
}
This servlet can handle URL shortening via POST requests and redirections via GET to the generated slug.
3. Generating Unique Slugs
Our application needs to generate unique short slugs for each given URL. A simple strategy is to generate a short random alphanumeric string. Here’s a utility method to do that:
private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final int SLUG_LENGTH = 6;
private final Random random = new SecureRandom();
private String generateSlug() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < SLUG_LENGTH; i++) {
int index = random.nextInt(ALLOWED_CHARS.length());
sb.append(ALLOWED_CHARS.charAt(index));
}
return sb.toString();
}
This random generator can produce a large number of combinations (62^6). Collision probability is reasonably low, but if needed, you can check if the slug already exists in urlMap
and regenerate if it does.
4. Handling Persistence and Concurrency
The application stores URLs in an in-memory ConcurrentHashMap
to ensure thread safety, as multiple requests may arrive concurrently. This is fine for tiny applications or testing, but won’t persist data across restarts.
For better persistence, consider using:
- File-based storage like a JSON or properties file
- Database solutions like H2, SQLite, or MySQL
To enhance thread safety and avoid slug collisions, wrap generateSlug
and mapping insertion inside a synchronized block, or use a concurrent-safe loop:
String slug;
do {
slug = generateSlug();
} while (urlMap.containsKey(slug));
urlMap.put(slug, longUrl);
5. Testing and Deployment
Deploy the WAR file to your local Tomcat server. To shorten a URL:
curl -X POST -d "longUrl=https://example.com/some/long/path" http://localhost:8080/url
To redirect using a short URL obtained from the above response:
curl -v http://localhost:8080/url/abc123
Tips:
- Use Postman or a browser extension to test POST requests interactively.
- Implement logging using SLF4J to track mappings and usage.
- For production, rate-limit the service to prevent abuse.
Conclusion
We’ve successfully built a basic URL shortener service using Java Servlets. This application supports URL shortening, redirection, and uses an in-memory data store. With just a few enhancements, such as persistent storage and analytics, this could become a highly useful microservice in modern web stacks.
Up next, try integrating a database or adding authentication to track user links!
Useful links: