Home > Java > Implementing URL Shortener with Servlet

Implementing URL Shortener with Servlet

I bet that most of you already tried Url Shortener Service to make your long link shorter and easier to write and remember. And perhaps you use more than one service, you name it ow.ly, goo.gl, bit.ly and still tons of services like that available freely on the cloud. But, how it works? here i will share its implementation with Servlet. It’s easy to implement, believe me.

First of all, prepare several tools below:

  • MySql Database Server. I use version 5.1.49 Community Edition, you can download newest MySql from http://www.mysql.com/downloads/mysql/. Or you can choose another DBMS implementation, like Oracle, Sql Server, etc.
  • MySql Connector/J, as our JDBC driver for MySql. You can download it from http://www.mysql.com/downloads/connector/j/. Please use suitable JDBC Driver if you choose another DBMS.
  • Servlet Container, here i use Apache Tomcat 6.0.32, you can download ithttp://tomcat.apache.org/. Of course, you can replace it with your own most favourite Web Server; Jetty, Glassfish, JBoss, etc.
  • servlet-api.jar, this is jar of Servlet API. You will need it to create a simple Http Servlet. You can download it from http://www.java2s.com/Code/Jar/STUVWXYZ/Downloadservletapijar.htm just in case you dont have it.
  • Your favourite Java IDE. In this tutorial I’m using Eclipse Helios 3.6, feel free to use similar IDE.

After you have all of these things above, we can start it. In order to make this post shorter, i assume that you have experience in creating new Web Project and adding required jars (servlet-api.jar and Mysql Connector/J ) to the classpath.

Scenario .

Before we started to the code, maybe i have to describe the business scenario first. My scenario is i want to make a simple program that take input of my long url and return a shorter link that formed like http://myserver/{id} , where {id} is my identifier to find the original url and turn my browser to open it.

Create Database

Run this Sql Script on your DBMS engine to create a table that stores our data. Dont forget, the id column has to be auto-increment. This is our primary key and we need it as a short url. You need to modify the Sql if you use other DBMS.

CREATE DATABASE /*!32312 IF NOT EXISTS*/`url_shortener` /*!40100 DEFAULT CHARACTER SET latin1 */;

CREATE TABLE `url_data` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `long_url` text NOT NULL,
  PRIMARY KEY (`id`)
);


Creating Servlet to Insert Long Url.

Now, create a new Java Class that extends javax.servlet.http.HttpServlet object and type below code.

package com.namex.shortener;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Insert extends HttpServlet {

    /**
     * Both POST and GET method are allowed to insert new record
     *
     */

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
	    throws ServletException, IOException {

	doGet(request, response);
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
	    throws ServletException, IOException {

	String longUrl = request.getParameter("longUrl");
	request.getSession().setAttribute("a", "a");
	String a = response.encodeURL(request.getRequestURI());
	request.getSession().setAttribute("a", "a");
	System.out.println("->"+request.getRequestURI());
	System.out.println(a);
	System.out.println("shortening " + longUrl);
	String serverName = request.getServerName();
	int port = request.getServerPort();
	String contextPath = request.getContextPath();
	String shortUrl = null;
	try {
	    shortUrl = new Logic().getShort(serverName, port, contextPath,
		    longUrl);
	} catch (Exception e) {

	    e.printStackTrace();
	}
	System.out.println("short url: " + shortUrl);
	request.getSession().setAttribute("shortUrl", shortUrl);
	response.sendRedirect("index.jsp");
    }
}

In my case, i want my program to handle both of POST and GET method, so i need to implement both of doGet and doPost method. Just in case you only want to handle GET method and not the POST, so you only need to override the doGet method.

See the new Logic().getShort(serverName, port, contextPath, longUrl); line. That is our Logic class that handle the whole business-logic problem. So we can see our servlet neater. Below is complete Logic source code, just type the whole thing, including not used yet function. And dont forget to adjust the getConnection according to your DBMS IP Address and credential.

package com.namex.shortener;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Logic {
    public Connection getConnection() throws IllegalAccessException,
	    ClassNotFoundException, SQLException {
	//adjust it
	String url = "jdbc:mysql://localhost/url_shortener";
	Class.forName("com.mysql.jdbc.Driver");
	Connection conn = DriverManager.getConnection(url, "root", "root");
	return conn;
    }

    public String getId(String longUrl) throws Exception {
	Connection conn = null;
	ResultSet rs = null;
	Statement st = null;

	String query = "SELECT id FROM url_data WHERE long_url='"
		+ longUrl.trim() + "'";
	String id = null;
	try {
	    try {
		conn = getConnection();
		st = conn.createStatement();
		rs = st.executeQuery(query);
		if (rs.next()) {
		    id = rs.getString("id");
		}
	    } finally {

		if (rs != null) {
		    rs.close();
		}
		if (st != null) {
		    st.close();
		}
		if (conn != null) {
		    conn.close();
		}
	    }
	} catch (Exception e) {
	    throw e;
	}
	return id;
    }

    public String getShort(String serverName, int port, String contextPath,
	    String longUrl) throws Exception {

	Connection conn = null;

	Statement st = null;
	String id = getId(longUrl);// check if URL has been shorten already
	if (id != null) {
	    // if id is not null, this link has been shorten already.
	    // nothing to do

	} else {
	    // at this point id is null, make it shorter
	    String sqlInsert = "INSERT INTO url_data(long_url) VALUES('"
		    + longUrl.trim() + "')";
	    try {
		conn = getConnection();
		st = conn.createStatement();
		st.execute(sqlInsert);
	    } finally {
		if (st != null) {
		    st.close();
		}
		if (conn != null) {
		    conn.close();
		}
	    }
	    // after we insert the record, we obtain the ID as identifier of our
	    // new short link
	    id = getId(longUrl);

	}
	return "http://" + serverName + ":" + port + contextPath + "/" + id;
    }

    public String getLongUrl(String urlId) throws Exception {
	if (urlId.startsWith("/")) {
	    urlId = urlId.replace("/", "");
	}
	String query = "SELECT long_url FROM url_data where id=" + urlId;
	String longUrl = null;
	Connection conn = null;
	ResultSet rs = null;
	Statement st = null;

	try {
	    conn = getConnection();
	    st = conn.createStatement();
	    rs = st.executeQuery(query);
	    if (rs.next()) {
		longUrl = rs.getString("long_url");
	    }
	} finally {

	    if (rs != null) {
		rs.close();
	    }
	    if (st != null) {
		st.close();
	    }
	    if (conn != null) {
		conn.close();
	    }
	}

	return longUrl;
    }

}

Adjusting web.xml for Insert Servlet.

To let the Server identify your new created servlet, adjust your web.xml like this.

<?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_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>URLShortener</display-name>

	<servlet>
		<servlet-name>Insert</servlet-name>
		<servlet-class>com.namex.shortener.Insert</servlet-class>
		<load-on-startup>-1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Insert</servlet-name>
		<url-pattern>/insert</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

You see the <servlet></servlet> tag, between that tag is our servlet class and we give it a name Insert. So whenever we need to do configuration to this servlet, we use the name Insert. Dont forget to give negative integer to <load-on-startup></load-on-startup> because we wont need it to be loaded when the server is up. We only need the servlet loaded when it called explicitly from our program. You can see more detail about <servlet></servlet> tag here http://download.oracle.com/docs/cd/E13222_01/wls/docs81/webapp/web_xml.html#1039287

The <servlet-mapping></servlet-mapping> identify when the servlet is called by the program. In our case, the Insert servlet will be called when someone make request to /{context-path}/Insert.

Create User Interface.

Now it’s time to provide some user interface, i make a simple one with only 1 text-field and a simple scriptlet to view our recently shorted link. You can beautify it if you want. Put it on top of WEB-INF folder as index.jsp, because we want it to be the first page of our program.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title></title>
</head>
<body>
	<form action="/url/insert" method="GET">
		Long URL: <input type="text" name="longUrl" size="100" /> <input
			type="submit" value="Get Short !" />

	</form>
	</p>
	<%
	    if (session.getAttribute("shortUrl") != null) {
	%>
	Hi, your short url is:
	<br />
	<br />
	<%=session.getAttribute("shortUrl")%>

	<%
	    }
	%>
</body>
</html>

url short 001

Testing Shortening

After we did all the steps above, now we can try it in action. Compile and make a WAR of your recently create application and deploy it on Tomcat. And open the program using your browser. Input the long URL, press the button and you can see the short URL generated below.

url short 002

the result would be

url short 003

IF, remember the BIG IF everything runs perfectly, our task isnt done yet. We still have to make a redirector that transforming the short url to the original url.

Creating Servlet to Transform Short Url.

Similar proses like here. Just type the Retrieve servlet, and be aware of line new Logic().getLongUrl(urlId);. We have had created this before and if you did what i told you before to code the Logic class completely, with all of its functions, the Retrieve servlet code should be perfect.

package com.namex.shortener;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Retrieve extends HttpServlet {

    private static final long serialVersionUID = 1293961717469276130L;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
	    throws ServletException, IOException {

	String urlId = request.getServletPath();

	String longUrl = null;
	if (urlId != null && !"".equals(urlId)) {
	    try {
		longUrl = new Logic().getLongUrl(urlId);
	    } catch (Exception e) {
		// handling exception here
		e.printStackTrace();
	    }
	}

	if (longUrl == null) {
	    // if long url not found, send to index.jsp
	    System.out.println("long url not found, back to index.jsp");
	    response.sendRedirect("index.jsp");
	} else {
	    //if long url found, so redirect the browser
	    System.out.println("redirecting to "+longUrl );
	    response.sendRedirect(longUrl);
	}
    }

}

Adjusting web.xml for Retrieve Servlet.

Dont forget we have to adjust the web.xml setting to let the Tomcat identify our servlet. The whole web.xml would be like this.

<?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_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>URLShortener</display-name>

	<servlet>
		<servlet-name>Insert</servlet-name>
		<servlet-class>com.namex.shortener.Insert</servlet-class>
		<load-on-startup>-1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Insert</servlet-name>
		<url-pattern>/insert</url-pattern>
	</servlet-mapping>

	<servlet>
		<servlet-name>Retrieve</servlet-name>
		<servlet-class>com.namex.shortener.Retrieve</servlet-class>
		<load-on-startup>-1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Retrieve</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

Test the Whole Shortener.

This is our last part, now you can test the program completely. Run your Tomcat and open our program. Insert the long url and open the short url in your browser, see if it return your page or not.

Now, our Url Shortening service has been created. There are still many ways to implement it using various techniques, we can use SOAP, REST or even EJB to handle the shortening and retrieving url. Now it’s your turn to improve it and implement it for your own need.

About these ads
Categories: Java
  1. 22 June 2012 at 17:02

    Thanks for every other informative web site.
    The place else may just I get that kind of information written in such
    a perfect means? I have a project that I’m just now working on, and I have been on the look out for such info.

  2. 29 June 2012 at 09:20

    Really good post. Looking forth to the next one.
    Provided that you maintain this quality. I am sure you will definitely have a lot of followers in no time.

    All the best, and definitely checking for your further blog posts.

  3. Kunal
    4 August 2012 at 19:10

    I tried this program on NetBeans using Apache. I was able to run the index.jsp page, but it does not show the shortened URL at all. It just keeps redirecting to the same page over and over again. Kindly help ! I have used the same code as you have given here, except for the JDBC parameters for MySQL connection.

    • RDeJourney
      9 August 2012 at 10:23

      is the app store the record in database already? if not yet, maybe you have a little logical error in response.sendRedirect or Form action part.

  4. Anchal
    7 August 2012 at 17:07

    I am not able to run this program successfully. Can you please help –

    when run , the welcome page where Long Url need to be provided is coming – After providing URL , when ” Get Short” button is clicked .. it gives a HTTP Status 404 page… ie. no response is coming.

    • RDeJourney
      9 August 2012 at 10:24

      have you set the form action correctly?

  5. Anchal
    22 August 2012 at 20:07

    Thankuu… But the Problem solved… i had a problem in database connectivity…

  6. Farheena
    8 March 2013 at 17:33

    This is the output am getting when i compile the program Insert.java:—–
    ———- Compile ———-
    Insert.java:27: cannot find symbol
    symbol : class Logic
    location: class com.namex.shortener.Insert
    shortUrl = new Logic().getShort(serverName, port, contextPath,longUrl);
    ^
    1 error

    Output completed (0 sec consumed) – Normal Termination
    please solve this out..i am in need of the code immediately….

    • RDeJourney
      8 March 2013 at 20:38

      have u put the code of
      public class Logic
      ?

  7. 28 April 2013 at 03:38

    Greate article. Keep posting such kind of info on your site.

    Im really impressed by your blog.
    Hi there, You’ve done a great job. I’ll certainly digg it and in
    my opinion suggest to my friends. I’m sure they’ll be benefited from this site.

  8. 3 May 2013 at 08:07

    Do you mind if I quote a couple of your articles as long as I
    provide credit and sources back to your webpage? My blog site is in
    the exact same niche as yours and my users would really benefit from a lot of the information you provide here.
    Please let me know if this ok with you. Thanks!

    • RDeJourney
      3 May 2013 at 10:03

      Hi Cathern,
      Sure i have no problem with that

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 725 other followers

%d bloggers like this: