SpringMVC4 + Spring Data JPA + SpringSecurity configuration using JavaConfig

In this article we will see how to configure and integrate SpringMVC4, Spring Data JPA with Hibernate and SpringSecurity using JavaConfig.

1. First let’s configure all the necessary dependencies in pom.xml



  4.0.0
  com.sivalabs
  springmvc-datajpa-security-demo
  1.0
  war 
  
	
		1.7
		4.11
		1.7.5
		1.0.13
		4.0.0.RELEASE
		1.4.1.RELEASE
		3.2.0.RELEASE
		4.2.6.Final
		1.7.2
		5.1.26
		2.3.1
		1.2.2
		3.1
	
	
	
		${project.artifactId}
		
			
				org.apache.maven.plugins
				maven-compiler-plugin
				3.1
				
					${java.version}
					${java.version}
				
			
		
	

	
	
		
			org.slf4j
			jcl-over-slf4j
			${slf4j.version}
		

		
			org.slf4j
			slf4j-api
			${slf4j.version}
		
		
		
			ch.qos.logback
			logback-classic
			${logback.version}
				

				
		
			org.springframework
			spring-context-support
			
				
					commons-logging
					commons-logging
				
			
		
		
		
			org.springframework
			spring-webmvc
		
		
			org.springframework
			spring-test
		
		
		
		
			org.springframework.data
			spring-data-jpa
			${spring-data-jpa.version}
		

		
			org.hibernate
			hibernate-entitymanager
			${hibernate.version}
		
		
		
		
			org.springframework.security
			spring-security-core
			${spring-security.version}
		
		
			org.springframework.security
			spring-security-web
			${spring-security.version}
		
		
			org.springframework.security
			spring-security-config
			${spring-security.version}
		
		
			org.springframework.security
			spring-security-taglibs
			${spring-security.version}
			
		
		
			org.aspectj
			aspectjweaver
			${aspectj.version}
		
		
			org.aspectj
			aspectjrt
			${aspectj.version}
			

		
		
			junit
			junit
			${junit.version}
			test
				

		
		
			mysql
			mysql-connector-java
			${mysql.version}
		
				
		
			commons-dbcp
			commons-dbcp
			${commons-dbcp.version}
		
				
		
			com.fasterxml.jackson.core
			jackson-databind
			${jackson-json.version}
		
		
		
		    javax.mail
		    mail
		    1.4.3
	    
	    
		
		
			javax.servlet
			javax.servlet-api
			3.0.1
			provided
		

		
			taglibs
			standard
			1.1.2
			compile
		
		
			jstl
			jstl
			1.2
			compile
		
	

	
		
			
				org.springframework
				spring-framework-bom
				${spring.version}
				pom
				import
					
		
	
	


2. Configure database connection properties and email settings in application.properties


################### DataSource Configuration ##########################

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=admin

init-db=false

################### Hibernate Configuration ##########################

hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update

################### JavaMail Configuration ##########################
smtp.host=smtp.gmail.com
smtp.port=465
smtp.protocol=smtps
smtp.username=sivaprasadreddy.k@gmail.com
smtp.password=
support.email=sivaprasadreddy.k@gmail.com

3. Configure common Service Layer beans such as PropertySourcesPlaceholderConfigurer and JavaMailSender etc in com.sivalabs.springapp.config.AppConfig.java



package com.sivalabs.springapp.config;

import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration
@ComponentScan(basePackages={"com.sivalabs.springapp"},
		excludeFilters=@ComponentScan.Filter(type=FilterType.REGEX, pattern={"com.sivalabs.springapp.web.*"}))
@PropertySource(value = { "classpath:application.properties" })
@EnableScheduling
@EnableAspectJAutoProxy
@EnableCaching
public class AppConfig 
{
	@Autowired
	private Environment env;

	@Bean
	public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer()
	{
		return new PropertySourcesPlaceholderConfigurer();
	}
	
	@Bean
	public JavaMailSenderImpl javaMailSenderImpl() {
		JavaMailSenderImpl mailSenderImpl = new JavaMailSenderImpl();
		mailSenderImpl.setHost(env.getProperty("smtp.host"));
		mailSenderImpl.setPort(env.getProperty("smtp.port", Integer.class));
		mailSenderImpl.setProtocol(env.getProperty("smtp.protocol"));
		mailSenderImpl.setUsername(env.getProperty("smtp.username"));
		mailSenderImpl.setPassword(env.getProperty("smtp.password"));

		Properties javaMailProps = new Properties();
		javaMailProps.put("mail.smtp.auth", true);
		javaMailProps.put("mail.smtp.starttls.enable", true);

		mailSenderImpl.setJavaMailProperties(javaMailProps);

		return mailSenderImpl;
	}
		
	@Bean
	public CacheManager cacheManager()
	{
		return new ConcurrentMapCacheManager();
	}
}

Observe that we have excluded the package “com.sivalabs.springapp.web.*” from component scanning using new REGEX excludeFilter type.
If we don’t exclude web related packages and tries to run JUnit test for service layer beans we will encounter the following Exception:

java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling

Also note that we have enabled Caching using @EnableCaching, so we should declare CacheManager bean.

4. Configure Persistence Layer beans in com.sivalabs.springapp.config.PersistenceConfig.java as follows:


package com.sivalabs.springapp.config;

import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="com.sivalabs.springapp.repositories")
public class PersistenceConfig 
{
	@Autowired
	private Environment env;

	@Value("${init-db:false}")
	private String initDatabase;
	
	@Bean
	public PlatformTransactionManager transactionManager()
	{
		EntityManagerFactory factory = entityManagerFactory().getObject();
		return new JpaTransactionManager(factory);
	}

	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory()
	{
		LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();

		HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
		vendorAdapter.setGenerateDdl(Boolean.TRUE);
		vendorAdapter.setShowSql(Boolean.TRUE);

		factory.setDataSource(dataSource());
		factory.setJpaVendorAdapter(vendorAdapter);
		factory.setPackagesToScan("com.sivalabs.springapp.entities");

		Properties jpaProperties = new Properties();
		jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
		factory.setJpaProperties(jpaProperties);

		factory.afterPropertiesSet();
		factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
		return factory;
	}

	@Bean
	public HibernateExceptionTranslator hibernateExceptionTranslator()
	{
		return new HibernateExceptionTranslator();
	}
	
	@Bean
	public DataSource dataSource()
	{
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
		dataSource.setUrl(env.getProperty("jdbc.url"));
		dataSource.setUsername(env.getProperty("jdbc.username"));
		dataSource.setPassword(env.getProperty("jdbc.password"));
		return dataSource;
	}
	
	@Bean
	public DataSourceInitializer dataSourceInitializer(DataSource dataSource) 
	{
		DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
		dataSourceInitializer.setDataSource(dataSource);
		ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
		databasePopulator.addScript(new ClassPathResource("db.sql"));
		dataSourceInitializer.setDatabasePopulator(databasePopulator);
		dataSourceInitializer.setEnabled(Boolean.parseBoolean(initDatabase));
		return dataSourceInitializer;
	}	
}

Here we have configured DataSource and JPA EntityManagerFactory bean using Hibernate implementation.
Also we have configured DataSourceInitializer bean to initialize and populate our tables with seed data. We can enable/disable executing this db.sql script by changing init-db property value in application.properties.
And finally we have enabled Spring Data JPA repositories scanning using @EnableJpaRepositories to scan “com.sivalabs.springapp.repositories” package for JPA repository interfaces.

5. Now let us configure Web related beans in com.sivalabs.springapp.web.config.WebMvcConfig.java


package com.sivalabs.springapp.web.config;

import java.util.Properties;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;


@Configuration
@ComponentScan(basePackages = { "com.sivalabs.springapp.web"}) 
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter
{
	@Override
	public void addViewControllers(ViewControllerRegistry registry)
	{
		super.addViewControllers(registry);
		registry.addViewController("login/form").setViewName("login");		
		registry.addViewController("welcome").setViewName("welcome");
		registry.addViewController("admin").setViewName("admin");
	}

	@Bean
	public ViewResolver resolver()
	{
		InternalResourceViewResolver url = new InternalResourceViewResolver();
		url.setPrefix("/WEB-INF/jsp/");
		url.setSuffix(".jsp");
		return url;
	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry)
	{
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
	}

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

	@Bean(name = "messageSource")
	public MessageSource configureMessageSource()
	{
		ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
		messageSource.setBasename("classpath:messages");
		messageSource.setCacheSeconds(5);
		messageSource.setDefaultEncoding("UTF-8");
		return messageSource;
	}

	@Bean
	public SimpleMappingExceptionResolver simpleMappingExceptionResolver()
	{
		SimpleMappingExceptionResolver b = new SimpleMappingExceptionResolver();
		Properties mappings = new Properties();
		mappings.put("org.springframework.dao.DataAccessException", "error");
		b.setExceptionMappings(mappings);
		return b;
	}
}

6. Configure DispatcherService using AbstractAnnotationConfigDispatcherServletInitializer convinient class.



package com.sivalabs.springapp.web.config;

import javax.servlet.Filter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.sivalabs.springapp.config.AppConfig;

public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{

	@Override
	protected Class[] getRootConfigClasses()
	{
		return new Class[] { AppConfig.class};
	}

	@Override
	protected Class[] getServletConfigClasses()
	{
		return new Class[] { WebMvcConfig.class };
	}

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

	@Override
    protected Filter[] getServletFilters() {
       return new Filter[]{ new OpenEntityManagerInViewFilter()	  };
    }

}

Here few things to note are we configured AppConfig.class as RootConfig classes and WebMvcConfig.class as ServletConfigClasses which is similar to how we configure in web.xml using ContextLoaderListener and DispatcherServlet’s contextConfigLocation .
Also we have registered OpenEntityManagerInViewFilter to enable lazy loading of JPA entity graphs in view rendering phase.

7. Let us configure SpringSecurity.

First let us create a SecurityUser class which extends our application specific User class and implements org.springframework.security.core.userdetails.UserDetails.


package com.sivalabs.springapp.web.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.sivalabs.springapp.entities.Role;
import com.sivalabs.springapp.entities.User;

public class SecurityUser extends User implements UserDetails
{

	private static final long serialVersionUID = 1L;
	public SecurityUser(User user) {
		if(user != null)
		{
			this.setId(user.getId());
			this.setName(user.getName());
			this.setEmail(user.getEmail());
			this.setPassword(user.getPassword());
			this.setDob(user.getDob());
			this.setRoles(user.getRoles());
		}		
	}
	
	@Override
	public Collection getAuthorities() {
		
		Collection authorities = new ArrayList<>();
		Set userRoles = this.getRoles();
		
		if(userRoles != null)
		{
			for (Role role : userRoles) {
				SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRoleName());
				authorities.add(authority);
			}
		}
		return authorities;
	}

	@Override
	public String getPassword() {
		return super.getPassword();
	}

	@Override
	public String getUsername() {
		return super.getEmail();
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}	
}

We will implement a custom UserDetailsService and use Spring Data JPA repositories to load User details.


package com.sivalabs.springapp.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.sivalabs.springapp.entities.User;
import com.sivalabs.springapp.services.UserService;
import com.sivalabs.springapp.web.config.SecurityUser;

@Component
public class CustomUserDetailsService implements UserDetailsService
{
	@Autowired
	private UserService userService;
	
	@Override
	public UserDetails loadUserByUsername(String userName)
			throws UsernameNotFoundException {
		User user = userService.findUserByEmail(userName);
		if(user == null){
			throw new UsernameNotFoundException("UserName "+userName+" not found");
		}
		return new SecurityUser(user);
	}
}

Now create com.sivalabs.springapp.config.SecurityConfig.java which contains SpeingSecurity related bean definitions.


package com.sivalabs.springapp.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
//import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
	@Autowired
	private DataSource dataSource;

	@Autowired
	private CustomUserDetailsService customUserDetailsService;

	@Override
    protected void configure(AuthenticationManagerBuilder registry) throws Exception {
	/*
        registry
        .inMemoryAuthentication()
        .withUser("siva")
          .password("siva")
          .roles("USER")
          .and()
        .withUser("admin")
          .password("admin")
          .roles("ADMIN","USER");
        */
        
        //registry.jdbcAuthentication().dataSource(dataSource);
	registry.userDetailsService(customUserDetailsService);
    }


	  @Override
	  public void configure(WebSecurity web) throws Exception {
	    web
	      .ignoring()
	         .antMatchers("/resources/**");
	  }

	  @Override
	  protected void configure(HttpSecurity http) throws Exception {
	    http
	    .csrf().disable()
	    .authorizeRequests()
	        .antMatchers("/login","/login/form**","/register","/logout").permitAll()
	        .antMatchers("/admin","/admin/**").hasRole("ADMIN")
	        .anyRequest().authenticated()
	        .and()
	    .formLogin()
	        .loginPage("/login/form")
	        .loginProcessingUrl("/login")
	        .failureUrl("/login/form?error")
	        .permitAll();
	  }
}

Update SpringWebAppInitializer which we created eariler to add SecurityConfig configuration class.


public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
	@Override
	protected Class[] getRootConfigClasses()
	{
		return new Class[] { AppConfig.class};
		//As we have SecurityConfig.java in same package as AppConfig.java 
                // and enabled ComponentScan to scan "com.sivalabs.springapp.config" we don't need to explicitely configure it.
		//otherwise we should add SecurityConfig.class to getRootConfigClasses()
		//return new Class[] { AppConfig.class, SecurityConfig.class};
	}
	...
	...
	@Override
    protected Filter[] getServletFilters() {
       return new Filter[]{ 
    		   new DelegatingFilterProxy("springSecurityFilterChain"),
    		   new OpenEntityManagerInViewFilter()};
    } 

}	

As per our SpringSecurity custom Form Login configuration, we will use the following login form in login.jsp.



<%@taglib uri="http://www.springframework.org/tags"  prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>



Login






		
Invalid UserName and Password.
You have been logged out.

User Login Form

Once we successfully login we can obtain the authenticated use details using and secure parts of the view using as follows:


Email:

Administration

Logout

You can find the source code at github https://github.com/sivaprasadreddy/sivalabs-blog-samples-code/tree/master/springmvc-datajpa-security-demo

There are few issues while running the same application on JBoss AS 7.1. I have made few changes to run on JBossAS7.1 and published code at https://github.com/sivaprasadreddy/sivalabs-blog-samples-code/tree/master/springmvc-datajpa-security-demo-jboss7

Context root relative URLs using Spring’s

While developing web applications the common problem is to reference the static resources like js, stylesheets,images in JSPs from the relative URLs.
Suppose in your project you have the following structure.
MyApp
        src
        WebContent
              home.jsp
              jsp
                  createUser.jsp
              js
                  util.js
              css
                   style.css
              images
                      logo.jpg
             WEB-INF
                          …
             …….

So here if your current URL is http://localhost:8080/MyApp/home.do, you need to reference static resources as follows:

<script type="text/javascript" src="js/util.js"/>

Suppose your current URL is http://localhost:8080/MyApp/jsp/createUser.do, you need to reference static resources as follows:

<script type="text/javascript" src="../js/util.js"/>

This becomes messy to reference the static resources like this.

Spring framewrok is providing a custom tag <spring:url> to resolve this issue.
<spring:url> tag resolves the path from context root. So you can always give the path for static resources from context root irrespective of current URL.

<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<script type="text/javascript" src='<spring:url value="/js/ajax.js" htmlEscape="true"/>'></script>

You can also pass the query parameters like this:

<s:url value="/messages/" var="messages_url" htmlEscape="true">
<s:param name="name" value="siva"></s:param>
</s:url>
<a href="${messages_url}">Messages</a>

This results in <a href=”/MyApp/messages/?name=siva”>Messages</a>

If you want to pass the param values as part of URI you can do like this:

<s:url value="/messages/{name}" var="messages_url" htmlEscape="true">
<s:param name="name" value="siva"></s:param>
</s:url>
<a href="${messages_url}">Messages</a>

This results in <a href=”/MyApp/messages/siva”>Messages</a>

This tag helped me a lot while developing web application following REST approach.

How to POST and GET JSON between EXTJS and SpringMVC3

After one month of evaluation of the frameworks and tools, i choose ExtJS for UI and Spring/SpringMVC for business layer for my pet project.

Again by using ExtJS we can send data to server by form submits or as request parameters or in json format through Ajax requests. ExtJS uses JSON format in many situations to hold data. So I thought using JSON as data exchange format between EXTJS and Spring will be consistent.

The following code snippets explains how we can use ExtJS and SpringMVC3 to exchange data in JSON format.

1. Register MappingJacksonHttpMessageConverter in dispatcher-servlet.xml

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>

Don’t forget to copy jackson-json jar(s) to WEB-INF/lib

2. Trigger the POST request from ExtJS script as follows:

Ext.Ajax.request({
url : 'doSomething.htm',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
params : { "test" : "testParam" },
jsonData: {
"username" : "admin",
"emailId" : "admin@sivalabs.com"
},
success: function (response) {
var jsonResp = Ext.util.JSON.decode(response.responseText);
Ext.Msg.alert("Info","UserName from Server : "+jsonResp.username);
},
failure: function (response) {
var jsonResp = Ext.util.JSON.decode(response.responseText);
Ext.Msg.alert("Error",jsonResp.error);
}
});

3. Write a Spring Controller to handle the “/doSomething.htm” reguest.

@Controller
public class DataController
{
@RequestMapping(value = "/doSomething", method = RequestMethod.POST)
@ResponseBody
public User handle(@RequestBody User user) throws IOException
{
System.out.println("Username From Client : "+user.getUsername());
System.out.println("EmailId from Client : "+user.getEmailId());
user.setUsername("SivaPrasadReddy");
user.setEmailId("siva@sivalabs.com");
return user;
}
}

Any other better approaches?

Authentication Checking using SpringMVC Interceptors

For many web applications, some URLs need to protect from public access and some other URLs need to be protected based on the User Roles and privileges. To achieve this we can use Filters that comes with Servlet API or we can use JAAS(Java Authentication and Authorization Service).

SpringMVC provides Interceptors which can be used to intercept the URL and pre-process, post-process the requests.

Let us write a simple AuthenticationInterceptor to check whether the user is already logged in or not. If the User is already logged into the system we will let him continue otherwise we will redirect him to login page.

AuthenticationInterceptor .java

package com.sivalabs.web.controllers;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.sivalabs.entities.User;

@Component
public class AuthenticationInterceptor extends HandlerInterceptorAdapter
{
 @Override
 public boolean preHandle(HttpServletRequest request,
   HttpServletResponse response, Object handler) throws Exception
 {
  String uri = request.getRequestURI();
  if(!uri.endsWith("login.do") && !uri.endsWith("logout.do"))
  {
   User userData = (User) request.getSession().getAttribute("LOGGEDIN_USER");
   if(userData == null)
   {
    response.sendRedirect("login.do");
    return false;
   }   
  }
  return true;
 }
}

LoginController.java

package com.sivalabs.web.controllers;

@Controller
public class LoginController
{
 @RequestMapping(value="/login", method=RequestMethod.POST)
    public ModelAndView login(@ModelAttribute("login")User user, 
         BindingResult result, SessionStatus status,
         HttpServletRequest request)
    {
     String viewName = "login";
     ModelAndView mav = new ModelAndView(viewName);
     loginFormValidator.validate(user, result);
        if (result.hasErrors())
        {
            return mav;
        }
        User userData = userService.login(user);
        status.setComplete();
        
        if(userData == null){
         mav.getModel().put("ERROR", "Invalid UserName and Password");
        }else{
         viewName = "welcome";
         request.getSession().setAttribute("LOGGEDIN_USER", userData);
        }
        mav.setViewName(viewName);
        return mav;
    }
}

WEB-INF/dispatcher-servlet.xml


<beans>

    <context:annotation-config/> 
    <context:component-scan base-package="com.sivalabs"/>
 
     <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
     <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
      <property name="interceptors">
        <ref bean="authenticationInterceptor"/>
      </property>
     </bean>

     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
      p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
      
</beans>

Now if we try to access any other URLs without logging into the application it will automatically redirect to login page.

SpringMVC 3 + Tiles 2.2.2 Integration

Apache Tiles is a popular and mostly used templating framework for java based web application.
Tiles became more popular because Struts 1.x uses Tiles as its default templating framework.
SpringMVC which is an MVC framework, like Struts, also supports integration of Tiles as its templating framework.

Let us see how we can integrate SpringMVC and Tiles.

You can download Tiles binaries from http://tiles.apache.org/ .

Step#1: Add the following tiles jars to WEB-INF/lib folder.

tiles-api-2.2.2.jar
tiles-core-2.2.2.jar
tiles-jsp-2.2.2.jar
tiles-servlet-2.2.2.jar
tiles-template-2.2.2.jar

Step#2: Configure tiles integration in WEB-INF/dispatcher-servlet.xml






/WEB-INF/tiles.xml





<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>



Step#3: Configure tiles definitions in WEB-INF/tiles.xml

 



<put-attribute name="title" value="SivaLabs" />
<put-attribute name="header" value="/jsp/layout/header.jsp" />
<put-attribute name="navigation" value="/jsp/layout/navigation.jsp" />
<put-attribute name="body" value="" />
<put-attribute name="footer" value="/jsp/layout/footer.jsp" />



<put-attribute name="title" value="SivaLabs : Login" />
<put-attribute name="navigation" value="" />
<put-attribute name="body" value="/jsp/login.jsp" />



<put-attribute name="title" value="SivaLabs : Welcome" />
<put-attribute name="body" value="/jsp/welcome.jsp" />



Step#4: Code the layout JSPs

layout.jsp

<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<html>
<head>
<title><tiles:insertAttribute name="title" ignore="true" /></title>

</head>
<body>












<tiles:insertAttribute name="header" />


<tiles:insertAttribute name="navigation" />


<tiles:insertAttribute name="body" />


<tiles:insertAttribute name="footer" />

</body>
</html>

header.jsp


SivaLabs : My Experiments On Technology


footer.jsp


© 2011 SivaLabs All Rights Reserved

navigation.jsp

Create User

View Users

Logout

welcome.jsp


Welcome to SpringMVC+Tiles Sample Application


Step#5:

WelcomeController.java

package com.sivalabs.web.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class WelcomeController
{
@RequestMapping("welcome")
public String welcome()
{
return "welcome";
}
}

Here the String “welcome” will be resolved as a tile name and display the UI as per “welcome” tile configuration.

You can download the code from https://github.com/sivaprasadreddy/sivalabs-blog-samples-code/tree/master/springmvc-tiles