Display JSON Data using ExtJS 4 Store

I am sharing a short example of how to display JSON data using ExtJS 4 Store. In previous version of ExtJS, there is a small helper class call JsonStore which is used to simplify creation Stores from JSON data. In ExtJS 4 the class is no longer there. In this example, I am retrieving USGS data as JSON and display it in Grid as shown below.

USGS Data in Gri

As shown below in line 20, I use proxy of type JSONP in Ext.data.Store to retrieve the JSON data.

Ext.onReady(function(){
  Ext.define('UsgsList', {
    extend: 'Ext.data.Model',
    fields: [
       {name: 'fid',       type: 'int'},
       {name: 'title',     type: 'string'},
       {name: 'description',  type: 'string'},
       {name: 'link',      type: 'string'},
       {name: 'pubDate',    type: 'date'},
       {name: 'lat',      type: 'string'},
       {name: 'long',      type: 'string'}
    ],
    idProperty: 'fid'
});

var store = Ext.create('Ext.data.Store', {
    id: 'store',
    model: 'UsgsList',
    proxy: {
       type: 'jsonp',
       url: 'http://query.yahooapis.com/v1/public/yql',
    extraParams: {
       q: 'select * from rss where url="http://earthquake.usgs.gov/earthquakes/catalogs/eqs7day-M2.5.xml"',
       format: 'json'
   },
   reader: {
      root: 'query.results.item',
   }
 }
});

function renderTitle(value, p, record) {
   return Ext.String.format('<a href="{1}" target="_blank">{0}</a>',
   value,
   record.data.link
   );
}

var grid = Ext.create('Ext.grid.Panel', {
   width: 700,
   height: 500,
   title: 'USGS - M2.5+',
   store: store,
   loadMask: true,
   disableSelection: true,
   invalidateScrollerOnRefresh: false,
   viewConfig: {
     trackOver: false
   },
   // grid columns
   columns:[{
      xtype: 'rownumberer',
      width: 50,
      sortable: false
   },{
      id: 'title',
      text: "Title",
      dataIndex: 'title',
      flex: 1,
      renderer: renderTitle,
      sortable: false
   },{
      id: 'pubDate',
      text: "Published Date",
      dataIndex: 'pubDate',
      width: 130,
      renderer: Ext.util.Format.dateRenderer('n/j/Y g:i A'),
      sortable: true
   }],
   renderTo: Ext.getBody()
});

// trigger the data store load
store.load();
});

HTML5 @Google I/O 2011

Just sharing some of the talk/presentations on HTML5 at Google I/O 2011. HTML5 seems to be moving fast and you will see some of the cool stuff in the “HTML5 versus Android” demo,

  • I/O BootCamp 2011: Getting Started with HTML5

 

  • HTML5 Showcase for Web Developers: The Wow and the How

 

  • HTML5 and What’s Next

 

  • GWT + HTML5: A web developers dream!

 

  • HTML5 vs. Android: Apps or Web Mobile Development?

 

  • HTML5 Today with Google Chrome Frame

 

  • Kick-Ass Game Programming with Google Web Toolkit

 

 

Integrating JSR303 with Spring MVC 3 and ExtJS Forms

Previously in Spring MVC and ExtJS Forms I created a simple data entry form and there was no data validation implemented. Typically data validation occurs throughout application layers, from presentation to persistence layer. Here I will be using JSR-303 Bean Validation, where the data validation is defined in the domain model and can be used thoughout application layers. I will walk through how to integrate data validation into Spring MVC and will be using Hibernate Validator 4.x – which is the reference implementation for JSR-303 – to integrate into my previous example.

What is JSR-303?

“This JSR defines a metadata model and API for JavaBean validation. The default metadata source is annotations,
with the ability to override and extend the meta-data through the use of XML validation descriptors.
The validation API developed by this JSR is not intended for use in any one tier or programming model. It is specifically
not tied to either the web tier or the persistence tier, and is available for both server-side application programming,
as well as rich client Swing application developers.” – JSR-303 Specification

The data validation is achieved by defining constraints in the beans. Constraints are defined by a combination of constraint annotation and a list of constraint validation implementations. The constraint annotation can be applied at field-level, property-level (getter), class-level. Currently there are 22 built-in constraints for example @NotNull to check that the annotated value is not null or @Size(min=, max=) to check whether the annotated value lies between the specified range. You can also create your own custom constraint to meet your specific requirement. The concept here is similar to database constraints where the constraint can be applied to table column.

For now, I will walk through how to use the built-in constraints only. As usual, I will start with the configuration required to make the project work. Open the Maven pom.xml and add the following dependencies and repository:

<!-- JSR 303 with Hibernate Validator -->
<dependency>
	<groupId>javax.validation</groupId>
	<artifactId>validation-api</artifactId>
	<version>1.0.0.GA</version>
</dependency>
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>4.1.0.Final</version>
</dependency>
...
<!-- For Hibernate Validator Repository -->
<repository>
	<id>org.jboss.repository.release</id>
	<name>JBoss Maven Release Repository</name>
	<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
	<snapshots><enabled>false</enabled></snapshots>
</repository>

In the example, the form is submitted to HomeController and the form is mapped to PersonalContact bean. I added 3 built-in constraints into the PersonalContact bean, @NotBlank, @Patter (using regular expression) and @Email. When message is not define in the constraint annotation, the validator will assign a default value. The second part of the code below shows the validation process. The HomeController is autowired to the Validator bean and the validation() is executed inside the add().

public class PersonalContact implements Serializable
{
	private static final long serialVersionUID = 1L;
	private Long id;

	@NotBlank(message="Please enter name")
	private String name;
               // using regular expression to define the constraint
	@Pattern(regexp="[0-9]{8}", message="Please enter 8 digit phone number")
	private String phone;

	@Email
	private String email;

	public PersonalContact() {}

	public PersonalContact(Long id, String name, String phone, String email) {
		super();
		this.id = id;
		this.name = name;
		this.phone = phone;
		this.email = email;
	}
	//getter & setter
}
@Controller
public class HomeController
{
	@Autowired
	private Validator validator;

	@RequestMapping(value="/", method=RequestMethod.GET)
	public String home() {
		return "home";
	}

	@RequestMapping(value="/load", method=RequestMethod.POST)
	public @ResponseBody Map<String, ? extends Object> load(PersonalContact input) {
	...
	}

	@RequestMapping(value="/add", method=RequestMethod.POST)
	public @ResponseBody Map<String, ? extends Object> add(PersonalContact input, HttpSession session) {
		Map<String, Object> data = new HashMap<String, Object>();

		Set<ConstraintViolation<PersonalContact>> failures = validator.validate(input);
		if (!failures.isEmpty()) {
			//structure the response for ExtJS Form.
			data.put("success",Boolean.FALSE);
			data.put("errors", validationMessages(failures));
			data.put("errorMessage", "Add Failed!");
		} else {
			session.setAttribute(input.getName(), input);
			data.put("success",Boolean.TRUE);
		}

		return data;
	}
	//iterate to retrieve validation errors and store it in HashMap
	private Map<String, String> validationMessages(Set<ConstraintViolation<PersonalContact>> failures) {
		Map<String, String> failureMessages = new HashMap<String, String>();
		for (ConstraintViolation<PersonalContact> failure : failures) {
			failureMessages.put(failure.getPropertyPath().toString(), failure.getMessage());
		}
		return failureMessages;
	}
}

Since I used ExtJS forms, I must return JSON response in a specific format and the errors are mapped to the field and displayed as quicktips.


The spring-mvc-forms project is updated and available for download at myGit. Hope you find it useful. Happy coding! 🙂

References

{
   success: true,
   errors: { field1: 'error for field 1',
                 field2: 'error for field 2',
   	   ...
   }
}

Customizing Spring Security Login using ExtJS

This tutorial will walk through the steps to customize Spring Security login page using Ext JS form. There are a few steps need to be done to customize the login form, because Ext JS form does not work in the same way as the standard HTML form. By default Ext Forms are submitted through Ajax and response packets are assumed to be JSON. I will be adding the customize login page into my previous example (in Spring 3 MVC and ExtJS Forms). I will walk through:
  1. configuration required to integrate with Spring Security 3 (3.0.5 to be exact),
  2. customize login page, and
  3. implement login handler to return JSON.
Step 1: Configuration required to integrate with Spring Security. If you are using the Spring MVC project template from STS, you will need to add dependencies to Spring Security by modifying the Maven pom.xml file. Add the following property and dependencies:
<properties>
	...
	<org.springframework.security-version>3.0.5.RELEASE</org.springframework.security-version>
	...
</properties>
<dependencies>
      ...
      <!-- Spring Security -->
      <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${org.springframework.security-version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
      </dependency>
    <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${org.springframework.security-version}</version>
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
      </dependency>
    <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${org.springframework.security-version}</version>
      </dependency>
    <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${org.springframework.security-version}</version>
      </dependency>
      ...
</dependencies>
Now, create security context file. Let’s name it applicationContext-security.xml. For this tutorial I used in memory user service and declare user id and password as part of the authentication manager. In the configuration, I declared the form login URL and the login handler. The login page is pointing to the login controller which forward to login.jsp. While login handler beans are used to return JSON to Ext JS form. The interceptor defined that every URL must be authenticated except for login and resources (images,css,javascript). Remember to set the access permission of login page to permit all to avoid endless loop. It is a good practice to default all URL to isAuthenticate() and only permit the necessary URL.
<http use-expressions="true">
    <intercept-url pattern="/resources/**" filters="none"/>
    <intercept-url pattern="/app/login.do" access="permitAll()" />
    <intercept-url pattern="/**" access="isAuthenticated()" />
      <form-login login-page="/app/login.do"
      			authentication-success-handler-ref="loginSuccessHandler"
      			authentication-failure-handler-ref="loginFailureHandler" />
      <logout invalidate-session="true" logout-success-url="/" logout-url="/j_spring_security_logout"/>
      <remember-me key="xaab.springmvclogin" />
      <session-management session-fixation-protection="newSession" >
          <concurrency-control max-sessions="1" error-if-maximum-exceeded="false"/>
      </session-management>
</http>
<!-- all password = password -->
<authentication-manager>
     <authentication-provider>
      	<password-encoder hash="md5" />
        <user-service>
            <user name="user1" password="5f4dcc3b5aa765d61d8327deb882cf99" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
            <user name="user2" password="5f4dcc3b5aa765d61d8327deb882cf99" authorities="ROLE_USER,ROLE_TELLER" />
            <user name="user3" password="5f4dcc3b5aa765d61d8327deb882cf99" authorities="ROLE_USER" />
            <user name="user4" password="5f4dcc3b5aa765d61d8327deb882cf99" authorities="ROLE_USER" />
         </user-service>
      </authentication-provider>
</authentication-manager>

<beans:bean id="loginSuccessHandler" class="org.xaab.springmvc.LoginSuccessHandler" />
<beans:bean id="loginFailureHandler" class="org.xaab.springmvc.LoginFailureHandler" />
In order to activate the above configuration, you need to include the security context into the context parameter and include the security filter in web.xml.
<!-- part of web.xml -->
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/spring/root-context.xml
		/WEB-INF/spring/applicationContext-security.xml
	</param-value>
</context-param>

<filter>
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
Step 2: Customize login page. There are basic 3 elements in the default login page generated by Spring Security. They are:
  1. Form action: j_spring_security_check
  2. User name input: j_username
  3. Password input: j_password
Those are the form fields needed for the Ext login form. The UsernamePasswordAuthenticationFilter watches for a request to the virtual URL (/j_spring_security_check) used for form-based authentication, and attempts to authenticate the user. If necessary, You can customize it to use your own controller to authenticate. Take a look at the spring-mvc-login.js below. One thing to note is, this example redirect to a default URL upon successful login. It is done by modifying the window.location.
Ext.onReady(function(){
	Ext.QuickTips.init();

	var loginForm = new Ext.FormPanel({
		url: defLoginUrl,
		title: 'Login',
		renderTo: Ext.getBody(),
		frame: true,
		cls: 'my-form-class',
		width: 350,
		items: [{
			xtype: 'textfield',
			fieldLabel: 'Login',
			name: 'j_username'
	              },{
			xtype: 'textfield',
			inputType: 'password',
			fieldLabel: 'Password',
			name: 'j_password'
		}, {
			xtype: 'checkbox',
			fieldLabel: 'Remember Me?',
			name: '_spring_security_remember_me',
			checked: false
		}],
		buttons: [{
			id: 'lf.btn.login',
			text: 'Login',
			handler: function() {
				fnLoginForm(loginForm);
			}
		},{
			id: 'lf.btn.reset',
			text: 'Reset',
			handler: function() {
				fnResetForm(loginForm);
			}
		}]
	});

});
//Submit login and handler response
function fnLoginForm(theForm)
{
theForm.getForm().submit({
	success: function(form, action) {
		Ext.Msg.alert('Success', 'Login Successful!', function(btn, text) {
			if (btn == 'ok') {
				window.location = homeUrl;
			}
		});
	},
	failure: function(form, action) {
		Ext.Msg.alert('Warning', action.result.errorMessage);
	}
});
} //end fnLoginForm

function fnResetForm(theForm)
{
theForm.getForm().reset();
} //end fnResetForm
Step 3: Implement login handler to return JSON. Remember the authentication handlers declared in applicationContext-security.xml? now you will need implement it to handle succcess and failure case. For this purpose I used Jackson JSON processor and to include it add the dependency to pom.xml.
<!-- Jackson JSON Processor -->
<dependency>
	<groupId>org.codehaus.jackson</groupId>
	<artifactId>jackson-mapper-asl</artifactId>
	<version>1.7.4</version>
</dependency>
public class LoginSuccessHandler implements AuthenticationSuccessHandler
{
	public void onAuthenticationSuccess(HttpServletRequest request,
			HttpServletResponse response, Authentication auth) throws IOException,
			ServletException {

		ObjectMapper mapper = new ObjectMapper();
		LoginStatus status = new LoginStatus(true, auth.isAuthenticated(), auth.getName(), null);
		OutputStream out = response.getOutputStream();
		mapper.writeValue(out, status);
	}

}

public class LoginFailureHandler implements AuthenticationFailureHandler
{
	public void onAuthenticationFailure(HttpServletRequest request,
			HttpServletResponse response, AuthenticationException auth)
			throws IOException, ServletException {

		ObjectMapper mapper = new ObjectMapper();
		LoginStatus status = new LoginStatus(false, false, null, "Login failed. Try again.");
		OutputStream out = response.getOutputStream();
		mapper.writeValue(out, status);
	}

}
public class LoginStatus
{
  private final boolean success;
  private final boolean loggedIn;
  private final String username;
  private final String errorMessage;

  public LoginStatus(boolean success, boolean loggedIn, String username, String errorMessage) {
    this.success = success;
    this.loggedIn = loggedIn;
    this.username = username;
    this.errorMessage = errorMessage;
  }
}
Time to test drive the code. Lauch http://localhost:8080/spring-mvc-login/ in the browser and you will be redirected to the login page http://localhost:8080/spring-mvc-login/app/login.do.
Some of the things to improve on :
  • Use of SSL
  • Authenticate to LDAP
  • Securing “remember me” using Token.
Hope you find the tutorial useful. Happy coding! 🙂
Update: the source project is downloadable at myGit.

Spring 3 MVC and ExtJS Forms

In my previous post Beginning Spring MVC 3, I shared a simple tutorial to start developing Spring MVC 3. It covered the tools required and the steps to setup the project. This tutorial will take a step further and walk through how to work with forms – Ext JS form to be specific – for loading of data and submission of data for processing. I will be assuming that you have the tools and project setup.

Step 1. The model. Here I assumed a single bean will represent the form and data model (for data access/persistence). The attributes in the bean are mapped to the form fields.

public class PersonalContact implements Serializable
{
	private static final long serialVersionUID = 1L;
	private Long id;
	private String name;
	private String phone;
	private String email;

	public PersonalContact() {}

	public PersonalContact(Long id, String name, String phone, String email) {
		super();
		this.id = id;
		this.name = name;
		this.phone = phone;
		this.email = email;
	}

	//regenerate the getter & setter using STS.
}

Step 2. The controller. Using the default “HomeController”, I added 2 methods to handle the load and add request. Both methods have simple implementation to illustrate the interaction between the form and Spring MVC. There is no data access/persistence code implemented here.

@Controller
public class HomeController {

	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@RequestMapping(value="/", method=RequestMethod.GET)
	public String home() {
		logger.info("Welcome home!");
		return "home";
	}

	@RequestMapping(value="/load", method=RequestMethod.POST)
	public @ResponseBody Map<String, ? extends Object> load(PersonalContact input) {
		logger.info("Inside load");
		PersonalContact pc = new PersonalContact(1L, "Wowi", "89281932", "wo.wi@abcxyz.com");
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("success",Boolean.TRUE);
		data.put("data", pc);

		return data;
	}

	@RequestMapping(value="/add", method=RequestMethod.POST)
	public @ResponseBody Map<String, ? extends Object> add(PersonalContact input, HttpSession session) {
		logger.info("Inside add");

		Map<String, Object> data = new HashMap<String, Object>();

		if (input.getName() == null) {
			data.put("success",Boolean.FALSE);
			data.put("errorMessage", "No Name?");
		} else if (session.getAttribute(input.getName()) != null) {
			data.put("success",Boolean.FALSE);
			data.put("errorMessage", "There is an existing data, unable to add. Please enter a different name");
		} else {
			session.setAttribute(input.getName(), input);
			data.put("success",Boolean.TRUE);
		}

		return data;
	}
}

Step 3. The view. Similar to the controller, I built on the default home.jsp. As you can see there isn’t much code in the JSP. The core UI codes are in the JavaScript (spring-mvc-forms.js). By default the response assumed to be in JSON. Do remember to add the Jackson into the pom.xml and set the header to “Accept” application/json.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
	<link href="<c:url value="/resources/lib/ext-3.3.1/resources/css/ext-all.css" />" rel="stylesheet" type="text/css" />
	<script type="text/javascript" src="<c:url value="/resources/lib/ext-3.3.1/adapter/ext/ext-base.js" />"></script>
	<script type="text/javascript" src="<c:url value="/resources/lib/ext-3.3.1/ext-all.js" />"></script>
	<script type="text/javascript">
		if (Ext.BLANK_IMAGE_URL.substr(0, 5) != 'data:') {
			Ext.BLANK_IMAGE_URL = '<c:url value="/resources/lib/ext-3.3.1/resources/images/default/s.gif" />';
		}
		var loadUrl = '<c:url value="/load" />';
		var addUrl = '<c:url value="/add" />';
	</script>
	<script type="text/javascript" src="<c:url value="/resources/js/spring-mvc-forms.js" />"></script>
	<style type="text/css">
		body {
		  	font: normal 12px helvetica,arial,verdana,tahoma,sans-serif;
		}
		.my-form-class {
			margin:  20px 30px;
		}
	</style>
</head>
<body>
</body>
</html>
Ext.onReady(function(){
	Ext.QuickTips.init();

	var mf = new Ext.FormPanel({
			url: addUrl,
			renderTo: Ext.getBody(),
			frame: true,
			cls: 'my-form-class',
			width: 350,
			items: [{
					xtype: 'textfield',
					fieldLabel: 'Name',
					name: 'name'
			},{
					xtype: 'textfield',
					fieldLabel: 'Phone No.',
					name: 'phone'
			},{
					xtype: 'textfield',
					fieldLabel: 'EMail',
					name: 'email'
			}],
			buttons: [{
					id: 'mf.btn.load',
					text: 'Load',
					handler: function() {
						fnLoadForm(mf);
					}
				},{
					id: 'mf.btn.add',
					text: 'Add',
					disabled: true,
					handler: function() {
						fnUpdateForm(mf);
					}
			},{
					id: 'mf.btn.reset',
					text: 'Reset',
					disabled: true,
					handler: function() {
						fnResetForm(mf);
					}
			}]
	});

});

function fnLoadForm(theForm)
{
	//for the purpose of this tutorial, load 1 record.
	theForm.getForm().load({
		url: loadUrl,
		headers: {Accept: 'application/json, text/javascript, */*; q=0.01'},
    waitMsg: 'loading...',
		params : {
			id: 1
		},
		success: function(form, action) {
			Ext.getCmp('mf.btn.add').setDisabled(false);
			Ext.getCmp('mf.btn.reset').setDisabled(false);
			Ext.getCmp('mf.btn.load').setDisabled(true);
		},
		failure: function(form, action) {
			Ext.Msg.alert('Warning', 'Error Unable to Load Form Data.');
		}
	});
} //end fnLoadForm
function fnUpdateForm(theForm)
{
	theForm.getForm().submit({
		success: function(form, action) {
			Ext.Msg.alert('Success', 'Data is stored in session.');
			form.reset();
		},
		failure: function(form, action) {
			Ext.Msg.alert('Warning', action.result.errorMessage);
		}
	});
} //end fnUpdateForm
function fnResetForm(theForm)
{
	theForm.getForm().reset();
	Ext.getCmp('mf.btn.add').setDisabled(true);
	Ext.getCmp('mf.btn.reset').setDisabled(true);
} //end fnResetForm

Now that all the components are ready, launch the example and to begin with click “load” button. The form will be pre-populated with example data. To try the form submission, click “add”. Hope you find the tutorial useful. Happy coding! 🙂

Update: the source project is downloadable at myGit.

Beginning Spring MVC 3

It’s been awhile since I used Spring framework. It has evolved and gotten simpler & easier to work with. This tutorial will walk through how to setup a simple Spring MVC project and to return JSON object to client browser. In this tutorial I will be using SpringSource Tool Suite, its project template helps to reduce the time to get a Spring MVC project up and running.

In order to start the tutorial, you will need

  1. JDK installed. SpringSource Tool Suite requires full JDK, and
  2. SpringSource Tool Suite (STS). The installer includes the IDE and tc Server Developer Edition.

Let’s start with creating the Spring MVC project in STS.

Step 1: Create a new project:  File -> New -> Spring Template Project. You will be prompted to download the template, go ahead and download.

Step 2: Define project and top-level package name, then click “Finish”

Step 3: After the project created you will see the file structure and default controller (HomeController). The dependencies are defined in pom.xml and you will need to add Jackson JSON Processor to complete the tutorial. Without the library you will get HTTP 406 when getting JSON object. Add the following to pom.xml.

<!-- Jackson JSON Processor -->
<dependency>
 <groupId>org.codehaus.jackson</groupId>
 <artifactId>jackson-mapper-asl</artifactId>
 <version>1.6.4</version>
</dependency>


Step 4: Deploy the project into SpringSource tc Server. It cannot get easier then this.

Step 5: Deploy the project then start the server.


Step 6: Once the server is ready. Test you configuration by opening http://localhost:8080/spring-mvc-basic/ in your browser. That is all for the setup, now we move on to add a simple function to get JSON data and to get request information.

Step 7: Open HomeController and add 2 methods. The displayRequest() is a simple GET method which take an input parameter “input”, servlet request and request header. The content will be passed back to the view, in this case display.jsp. The 2nd method is getJsonData(), a simple method that return JSON object.

	@RequestMapping(value="/display", method=RequestMethod.GET)
	public String displayRequest(HttpServletRequest request,
		@RequestHeader(value="Accept") String accept,
		@RequestHeader("Accept-Encoding") String encoding,
		@RequestHeader("Accept-Charset") String charset,
                @RequestParam("input") String input,
                Model model)  {
	  logger.info("Calling displayRequest");
	  model.addAttribute("RemoteAddress", request.getRemoteAddr());
	  model.addAttribute("HeaderAccept", accept);
	  model.addAttribute("HeaderAcceptEncoding", encoding);
	  model.addAttribute("HeaderAcceptCharset", charset);
	  model.addAttribute("Output", input);
	  return "display";
	}

	@RequestMapping(value="/extractJson", method=RequestMethod.GET)
	public @ResponseBody Map<String,String> getJsonData(@RequestParam("input") String input)  {
	  logger.info("Calling extractJson");
	  person.put("name", "Simba");
	  person.put("website", "http://www.tanbh.net");
	  person.put("output", input);
	  return person;
	}

Step 8: Let’s work on the views now, by adding the link to call the controller “/display” and jQuery code to get JSON.

<!-- home.jsp -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
	<script type="text/javascript" src="http://code.jquery.com/jquery-1.5.1.min.js"></script>
</head>
<body>
<h1>Hello Spring MVC 3!</h1>
<a href="<c:url value="/display?input=HelloWorldEcho" />">Click to Get Request Info</a>
<br/><br/>
<div id="result"></div>
</body>
</html>
<script type="text/javascript">
$(document).ready(function() {

	$.getJSON('<c:url value="extractJson?input=HelloWorldEcho" />', function(data) {
	    $('#result').append('Result from ajax/json<br/>');
	    $('#result').append('Name: ' + data.name);
	    $('#result').append('<br/>');
	    $('#result').append('Website: ' + data.website);
	    $('#result').append('<br/>');
	    $('#result').append('Input Parameter: ' + data.output);
	});
});
</script>
<!-- display.jsp -->
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<!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>Insert title here</title>
</head>
<body>
<strong><c:out value="Remote Address: ${RemoteAddress}"></c:out></strong><br/>
<strong><c:out value="Accept ${HeaderAccept}"></c:out></strong><br/>
<strong><c:out value="Accept-Encoding: ${HeaderAcceptEncoding}"></c:out></strong><br/>
<strong><c:out value="Accept-Charset: ${HeaderAcceptCharset}"></c:out></strong><br/><br/>
<strong><c:out value="Input Parameter: ${Output}"></c:out></strong><br/>

<br/>
<br/>
<br/>
<a href="<c:url value="/" />">Home</a>

</body>
</html>

Now save all the file and sit back and wait for tc Server to reload. Once reloaded, launch trigger http://localhost:8080/spring-mvc-basic/. I also observed, I need to restart the tc Server after compilation error in the controller. Anyway, you should see your result:

Update: the source is downloadable at myGit.

ExtJS Google Maps Panel

I was browsing the Ext JS (3.3.x) example and saw the Google Maps Panel which was written based on Google Maps API v2. I thought it might be a good idea to migrate it to use v3, since v2 has been officially deprecated for sometime. Beside migrating the code, I modified the input parameter to accept MapOptions and also added 2 new features:

  • option to show InfoWindow at the center & other markers.
  • option to draw circle overlay at the center marker.

The full source code and example is available at myGit. I did not include Ext JS 3.3.1 into the repository.

Ext.ux.GoogleMapPanel = Ext.extend(Ext.Panel, {
		...
    addMarker : function(point, marker, clear, center, listeners, infoWindowOptions){
        if (clear === true){
            this.getMap().clearOverlays();
        }
        if (center === true) {
            this.getMap().setCenter(point);
        }

				var mark = new google.maps.Marker({
				       map: this.getMap(),
				       position: point,
				       title: marker.title
				});

				var infoWindow = null;
				if (infoWindowOptions != null) {
				   infoWindow = new google.maps.InfoWindow(infoWindowOptions);
				   	google.maps.event.addListener(mark, 'click', function() {
			  			infoWindow.open(this.getMap(),mark);
					});
				}
        if (typeof listeners === 'object'){
            for (evt in listeners) {
                google.maps.event.addListener(mark, evt, listeners[evt]);
            }
        }
        return mark;
    },
    drawCircle: function(circleOptions) {
	      this.circleOverlays = new google.maps.Circle(circleOptions);
        this.circleOverlays.setCenter(this.getCenter());
        this.circleOverlays.setMap(this.getMap());
     }
     ...
});

Ext.reg('gmappanel', Ext.ux.GoogleMapPanel);