Spring 4 REST Security + Hibernate 5 CRUD Example using Annotation and XML

By Arvind Rai, March 02, 2017
This page will walk through spring 4 REST security + hibernate 5 CRUD example using annotation and XML configuration. We will create REST web service application that will be authenticated using hibernate and MySQL database. We will apply spring security with REST using Basic authentication using HTTP header. For the demo we will create two applications, one using java configuration and other using XML configuration. In our application we have create, read, update and delete (CRUD) operations. We will secure service layer methods using @Secured annotation. The controller class methods will return appropriate HTTP status code in response header and produce JSON output in response body as required. In spring security configuration, we need to provide BasicAuthenticationEntryPoint. We need to override its commence() method and return header with status code (401) and authentication scheme as Basic authentication. commence() method is executed when the request is unauthorized and a proper message is required to send to user for authentication. To encode password we will use BCrypt password encoding scheme. At client side we will use RestTemplate. For all our CRUD operation using RestTemplate, we will send HttpHeaders that will contain user credential encoded with Base64 in the username:password token. To indent our JSON response, we will use Jackson2 message converter. To build the project we will provide both gradle and maven. Now let us walk through the complete example step by step.

Software Used

We are using following software in our example.
1. Java 8
2. Spring 4.3
3. Gradle 3.3
4. Maven 3.3
5. Tomcat 8.0
6. MySQL 5.5
7. Eclipse Mars

Gradle and Maven to Build the Project

Find the gradle file to build the project.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
war.archiveName 'spring-app.war'
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web:1.5.1.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-data-jpa:1.5.1.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-security:1.5.1.RELEASE'
    compile 'mysql:mysql-connector-java:6.0.5'
    compile 'org.apache.commons:commons-dbcp2:2.1.1'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.5.1.RELEASE'    
}  
Find the maven file to build the project.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>SpringSecurity</name>
	<description>Spring Demo Project</description>
	<parent>
	    <groupId>org.springframework.boot</groupId>
  	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>1.5.1.RELEASE</version>
 	    <relativePath/>
	</parent>
	<properties>
	    <java.version>1.8</java.version>
	    <context.path>spring-app</context.path>
	</properties>
	<dependencies>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	  </dependency>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-jpa</artifactId>
	  </dependency>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	  </dependency>
	  <dependency>
		 <groupId>mysql</groupId>
		 <artifactId>mysql-connector-java</artifactId>
		 <version>6.0.5</version>
	  </dependency>	  	  	  
	  <dependency>
		 <groupId>org.apache.commons</groupId>
		 <artifactId>commons-dbcp2</artifactId>
		 <version>2.1.1</version>
	  </dependency>    	  	  	  
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-tomcat</artifactId>
		<scope>provided</scope>
	  </dependency>      
	</dependencies>
	<build>
	  <plugins>
	    <plugin>
		  <groupId>org.apache.maven.plugins</groupId>
		  <artifactId>maven-war-plugin</artifactId>
		  <version>3.0.0</version>
		  <configuration>
			 <warName>${context.path}</warName>
		  </configuration>
	    </plugin>
	  </plugins>
	</build>
</project> 

MySQL Database Schema and Java Entity

In our application, I am using MySQL and have created two tables. The table users have information about user and its credentials. Password has been encoded using BCrypt password encoding scheme. The table articles keeps article related data.
Database Schema
-- Dumping database structure for concretepage
CREATE DATABASE IF NOT EXISTS `concretepage`;
USE `concretepage`;
-- Dumping structure for table concretepage.articles
CREATE TABLE IF NOT EXISTS `articles` (
  `article_id` int(5) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL,
  `category` varchar(100) NOT NULL,
  PRIMARY KEY (`article_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.articles: ~3 rows (approximately)
INSERT INTO `articles` (`article_id`, `title`, `category`) VALUES
	(1, 'Java Concurrency', 'Java'),
	(2, 'Hibernate HQL ', 'Hibernate'),
	(3, 'Spring MVC with Hibernate', 'Spring');
-- Dumping structure for table concretepage.users
CREATE TABLE IF NOT EXISTS `users` (
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `full_name` varchar(100) NOT NULL,
  `role` varchar(50) NOT NULL,
  `country` varchar(100) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.users: ~2 rows (approximately)
INSERT INTO `users` (`username`, `password`, `full_name`, `role`, `country`, `enabled`) VALUES
	('mukesh', '$2a$10$N0eqNiuikWCy9ETQ1rdau.XEELcyEO7kukkfoiNISk/9F7gw6eB0W', 'Mukesh Sharma', 'ROLE_ADMIN', 'India', 1),
	('tarun', '$2a$10$QifQnP.XqXDW0Lc4hSqEg.GhTqZHoN2Y52/hoWr4I5ePxK7D2Pi8q', 'Tarun Singh', 'ROLE_USER', 'India', 1); 
Find a main class to generate BCrypt password.
Main.java
package com.concretepage;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class Main {
	public static void main(String[] args) {
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		System.out.println(encoder.encode("m123"));
	}
} 
Find the java entity related to tables.
UserInfo.java
package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="users")
public class UserInfo implements Serializable {
	private static final long serialVersionUID = 1L;
	@Id
	@Column(name="username")
	private String userName;
	@Column(name="password")
	private String password;
	@Column(name="role")	
	private String role;
	@Column(name="full_name")	
	private String fullName;
	@Column(name="country")	
	private String country;
	@Column(name="enabled")	
	private short enabled;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public String getFullName() {
		return fullName;
	}
	public void setFullName(String fullName) {
		this.fullName = fullName;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public short getEnabled() {
		return enabled;
	}
	public void setEnabled(short enabled) {
		this.enabled = enabled;
	}
} 
Article.java
package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="articles")
public class Article implements Serializable { 
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="article_id")
        private int articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public int getArticleId() {
		return articleId;
	}
	public void setArticleId(int articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
} 

Spring 4 REST Security + Hibernate 5 CRUD Example using Annotation

We will create spring 4 REST security + hibernate 5 CRUD example using annotation. We will create java configuration files for spring security, database integration and spring MVC configuration. We will create DAO classes for create, read, update and delete (CRUD) operation. We will create service class with secured method. In controller we will create REST web service methods that will produce JSON response with HTTP status code. For REST web service client we will use RestTemplate.

1. Project Structure using JavaConfig in Eclipse

Find the project structure using JavaConfig in eclipse.
Spring 4 REST Security + Hibernate 5 CRUD Example using Annotation and XML

2. Implement BasicAuthenticationEntryPoint

Let us know the working of BasicAuthenticationEntryPoint in our security configuration.

SecurityContextHolder: A holder for SecurityContext with the current execution thread.

ExceptionTraslationFilter: It handles any AccessDeniedException and AuthenticationException thrown within the filter chain. It translates java exception into HTTP response.

BasicAuthenticationFilter: It handles a HTTP header request for authorization and puts the result into SecurityContextHolder. BasicAuthenticationFilter processes the HTTP header request for authorization with an authentication scheme of Basic and a Base64-encoded username:password token. If authentication is successful, the resulting authentication object will be placed into the SecurityContextHolder. If authentication is failed, then BasicAuthenticationEntryPoint is called that will respond the user to authenticate again via Basic authentication.

BasicAuthenticationEntryPoint : This is used by ExceptionTraslationFilter to commence authentication via the BasicAuthenticationFilter. We need to override commence() method of BasicAuthenticationEntryPoint that will return HTTP status code (401) indicating that the request requires HTTP authentication.

MyAppBasicAuthenticationEntryPoint.java
package com.concretepage.service;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class MyAppBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response,
		     AuthenticationException authException) throws IOException, ServletException {
		response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"");
		response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
	}
	@Override
	public void afterPropertiesSet() throws Exception {
		setRealmName("MY APP REALM");
	}
} 

3. Implement UserDetailsService

UserDetailsService loads user authentication and authorization related data. To authenticate user using database, we need to implement it and override loadUserByUsername() method. We fetch username, password and roles from the database that is used by spring UserDetailsService to authenticate the user.
MyAppUserDetailsService.java
package com.concretepage.service;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.Service;
import com.concretepage.dao.IUserInfoDAO;
import com.concretepage.entity.UserInfo;
@Service
public class MyAppUserDetailsService implements UserDetailsService {
	@Autowired
	private IUserInfoDAO userInfoDAO;
	@Override
	public UserDetails loadUserByUsername(String userName)
			throws UsernameNotFoundException {
		UserInfo activeUserInfo = userInfoDAO.getActiveUser(userName);
		GrantedAuthority authority = new SimpleGrantedAuthority(activeUserInfo.getRole());
		UserDetails userDetails = (UserDetails)new User(activeUserInfo.getUserName(),
				activeUserInfo.getPassword(), Arrays.asList(authority));
		return userDetails;
	}
} 

4. Spring REST Security JavaConfig

In spring security configuration we are using HTTP basic authentication. We will configure realm name and authentication entry point. For password encoding we are using BCrypt password encoder.
SecurityConfig.java
package com.concretepage.config;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.concretepage.service.MyAppBasicAuthenticationEntryPoint;
import com.concretepage.service.MyAppUserDetailsService;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private MyAppUserDetailsService myAppUserDetailsService;	
	@Autowired
	private MyAppBasicAuthenticationEntryPoint myAppBasicAuthenticationEntryPoint;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable()
		    .authorizeRequests()
		    .antMatchers("/user/**").hasAnyRole("ADMIN","USER")
		    .and().httpBasic().realmName("MY APP REALM")
		    .authenticationEntryPoint(myAppBasicAuthenticationEntryPoint);
	} 
        @Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    	     BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
             auth.userDetailsService(myAppUserDetailsService).passwordEncoder(passwordEncoder);
	}
} 
We are not configuring form login and form logout in the above code because we are doing header based authentication and not form based. @EnableWebSecurity enables the spring web security. @EnableGlobalMethodSecurity is used to enable method level security in service layer. Now find the spring security initializer.
SecurityInitializer.java
package com.concretepage.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
} 


5. Spring and Hibernate JavaConfig

Find the java configuration file that will integrate spring and hibernate.
DBConfig.java
package com.concretepage.config;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration 
@EnableTransactionManagement
@PropertySource("classpath:database.properties")
public class DBConfig {
	@Autowired
        private Environment env;	
	@Bean
	public HibernateTemplate hibernateTemplate() {
		return new HibernateTemplate(sessionFactory());
	}
 	@Bean
	public SessionFactory sessionFactory() {
		LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
		lsfb.setDataSource(getDataSource());
		lsfb.setPackagesToScan("com.concretepage.entity");
		lsfb.setHibernateProperties(hibernateProperties());
		try {
			lsfb.afterPropertiesSet();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return lsfb.getObject();
	}
        @Bean
	public DataSource getDataSource() {
	    BasicDataSource dataSource = new BasicDataSource();
	    dataSource.setDriverClassName(env.getProperty("database.driverClassName"));
	    dataSource.setUrl(env.getProperty("database.url"));
	    dataSource.setUsername(env.getProperty("database.username"));
	    dataSource.setPassword(env.getProperty("database.password"));
	    return dataSource;
	}
	@Bean
	public HibernateTransactionManager hibernateTransactionManager(){
	    return new HibernateTransactionManager(sessionFactory());
	}
        private Properties hibernateProperties() {
            Properties properties = new Properties();
            properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
            properties.put("hibernate.id.new_generator_mappings", env.getProperty("hibernate.id.new_generator_mappings"));
            properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
            properties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
            return properties;        
        }	
} 
To create data source we are using BasicDataSource from commons.dbcp2 library. To create hibernate SessionFactory we need to use LocalSessionFactoryBean and for hibernate transaction we need to use HibernateTransactionManager. We are also creating a bean for spring HibernateTemplate using session factory that will be used to interact with database.

Find the database property file.
database.properties
database.driverClassName=com.mysql.cj.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/concretepage
database.username=root
database.password=

hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.id.new_generator_mappings = false
hibernate.show_sql = true 
hibernate.format_sql = true 

6. Spring MVC JavaConfig

Find the java configuration for spring MVC.
AppConfig.java
package com.concretepage.config;  
import java.util.List;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  
@Configuration 
@ComponentScan("com.concretepage") 
@EnableWebMvc   
public class AppConfig extends WebMvcConfigurerAdapter {  
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.indentOutput(true);
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }    
} 
To enable spring MVC, we need to use @EnableWebMvc annotation with @Configuration. To indent the JSON output we are using message converter. Now find web application initializer that will register DispatcherServlet.
WebAppInitializer.java
package com.concretepage.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { AppConfig.class };
	}
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return null;
	}
	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}
} 

7. Create DAO

Find the DAO class in which we have created a method to load user information that will be called to instantiate UserDetailsService.
IUserInfoDAO.java
package com.concretepage.dao;
import com.concretepage.entity.UserInfo;
public interface IUserInfoDAO {
	UserInfo getActiveUser(String userName);
} 
UserInfoDAO.java
package com.concretepage.dao;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.UserInfo;
@Repository
@Transactional
public class UserInfoDAO implements IUserInfoDAO {
	@Autowired
	private HibernateTemplate hibernateTemplate;
	@Override
	public UserInfo getActiveUser(String userName) {
		UserInfo activeUserInfo = new UserInfo();
		short enabled = 1;
		List<?> list = hibernateTemplate.find("FROM UserInfo WHERE userName=? and enabled=?",
			       userName, enabled);
		if(!list.isEmpty()) {
			activeUserInfo = (UserInfo)list.get(0);
		}
		return activeUserInfo;
	}
} 
Now find the DAO that will perform create, read, update and delete (CRUD) operation.
IArticleDAO.java
package com.concretepage.dao;
import java.util.List;
import com.concretepage.entity.Article;
public interface IArticleDAO {
    List<Article> getAllArticles();
    Article getArticleById(int articleId);
    void addArticle(Article article);
    void updateArticle(Article article);
    void deleteArticle(int articleId);
    boolean articleExists(String title, String category);
} 
ArticleDAO.java
package com.concretepage.dao;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.Article;
@Transactional
@Repository
public class ArticleDAO implements IArticleDAO {
	@Autowired
	private HibernateTemplate  hibernateTemplate;
	@Override
	public Article getArticleById(int articleId) {
		return hibernateTemplate.get(Article.class, articleId);
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<Article> getAllArticles() {
		String hql = "FROM Article as atcl ORDER BY atcl.articleId";
		return (List<Article>) hibernateTemplate.find(hql);
	}	
	@Override
	public void addArticle(Article article) {
		hibernateTemplate.save(article);
	}
	@Override
	public void updateArticle(Article article) {
		Article artcl = getArticleById(article.getArticleId());
		artcl.setTitle(article.getTitle());
		artcl.setCategory(article.getCategory());
		hibernateTemplate.update(artcl);
	}
	@Override
	public void deleteArticle(int articleId) {
		hibernateTemplate.delete(getArticleById(articleId));
	}
	@SuppressWarnings("unchecked")
	@Override
	public boolean articleExists(String title, String category) {
		String hql = "FROM Article as atcl WHERE atcl.title = ? and atcl.category = ?";
		List<Article> articles = (List<Article>) hibernateTemplate.find(hql, title, category);
		return articles.size() > 0 ? true : false;
	}
} 

8. Create Service

In our application we will perform create, read, update and delete (CRUD) operation. We have secured our service methods using @Secured.
IArticleService.java
package com.concretepage.service;
import java.util.List;
import org.springframework.security.access.annotation.Secured;
import com.concretepage.entity.Article;
public interface IArticleService {
	 @Secured ({"ROLE_ADMIN", "ROLE_USER"})
         List<Article> getAllArticles();
	 @Secured ({"ROLE_ADMIN", "ROLE_USER"})
         Article getArticleById(int articleId);
	 @Secured ({"ROLE_ADMIN"})
         boolean addArticle(Article article);
	 @Secured ({"ROLE_ADMIN"})
         void updateArticle(Article article);
	 @Secured ({"ROLE_ADMIN"})
         void deleteArticle(int articleId);
} 
ArticleService.java
package com.concretepage.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IArticleDAO;
import com.concretepage.entity.Article;
@Service
public class ArticleService implements IArticleService {
	@Autowired
	private IArticleDAO articleDAO;
	@Override
	public Article getArticleById(int articleId) {
		Article obj = articleDAO.getArticleById(articleId);
		return obj;
	}	
	@Override
	public List<Article> getAllArticles(){
		return articleDAO.getAllArticles();
	}
	@Override
	public synchronized boolean addArticle(Article article){
               if (articleDAO.articleExists(article.getTitle(), article.getCategory())) {
    	          return false;
               } else {
    	          articleDAO.addArticle(article);
    	          return true;
               }
	}
	@Override
	public void updateArticle(Article article) {
		articleDAO.updateArticle(article);
	}
	@Override
	public void deleteArticle(int articleId) {
		articleDAO.deleteArticle(articleId);
	}
} 

9. Create Controller

Find the controller class.
ArticleController.java
package com.concretepage.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.util.UriComponentsBuilder;
import com.concretepage.entity.Article;
import com.concretepage.service.IArticleService;
@Controller
@RequestMapping("user")
public class ArticleController {
	@Autowired
	private IArticleService articleService;
	@GetMapping("article/{id}")
	public ResponseEntity<Article> getArticleById(@PathVariable("id") Integer id) {
		Article article = articleService.getArticleById(id);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@GetMapping("articles")
	public ResponseEntity<List<Article>> getAllArticles() {
		List<Article> list = articleService.getAllArticles();
		return new ResponseEntity<List<Article>>(list, HttpStatus.OK);
	}
	@PostMapping("article")
	public ResponseEntity<Void> addArticle(@RequestBody Article article, UriComponentsBuilder builder) {
                boolean flag = articleService.addArticle(article);
                if (flag == false) {
        	    return new ResponseEntity<Void>(HttpStatus.CONFLICT);
                }
                HttpHeaders headers = new HttpHeaders();
                headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri());
                return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
	}
	@PutMapping("article")
	public ResponseEntity<Article> updateArticle(@RequestBody Article article) {
		articleService.updateArticle(article);
		return new ResponseEntity<Article>(article, HttpStatus.OK);
	}
	@DeleteMapping("article/{id}")
	public ResponseEntity<Void> deleteArticle(@PathVariable("id") Integer id) {
		articleService.deleteArticle(id);
		return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
	}	
}  
Since spring 4.3, we have request mapping annotation such as
@GetMapping for HTTP GET method
@PostMapping for HTTP POST method
@PutMapping for HTTP PUT method
@DeleteMapping for HTTP DELETE method

We have created following URLS for CRUD operation.
1. Create :
HTTP Method: POST, URL: /user/article

2. Read :
HTTP Method: GET, URL: /user/article/{id}
HTTP Method: GET, URL: /user/articles

3. Update :
HTTP Method: PUT, URL: /user/article

4. Delete :
HTTP Method: DELETE, URL: /user/article/{id}

Spring 4 REST Security + Hibernate 5 CRUD Example using XML Configuration

Here we will create spring 4 REST security + hibernate 5 CRUD example using XML configuration. We will create XML configuration files for spring security, database integration and MVC configuration. DAO, service classes and controller will be the same as used in in our JavaConfig based application. For REST web service client we will use RestTemplate.

1. Project Structure using XML Configuration in Eclipse

Find the project structure using XML configuration in eclipse.
Spring 4 REST Security + Hibernate 5 CRUD Example using Annotation and XML

2. Spring REST Security XML Configuration

Find the spring security configuration using XML.
security-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security.xsd">
	
	<http realm="MY APP REALM"> 
	        <csrf disabled="true"/>
		<intercept-url  pattern="/user/**" access="hasAnyRole('ROLE_ADMIN','ROLE_USER')" />
		<http-basic  entry-point-ref="basicAuthenticationEntryPoint" />
	</http>
	<beans:bean name="bcryptEncoder"
	      class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>	
	<beans:bean name="myAppUserDetailsService"
	      class="com.concretepage.service.MyAppUserDetailsService"/>
	<beans:bean class="com.concretepage.service.ArticleService"/>
	<beans:bean name="basicAuthenticationEntryPoint"
	      class="com.concretepage.service.MyAppBasicAuthenticationEntryPoint"/>		      
	<authentication-manager>
		<authentication-provider user-service-ref="myAppUserDetailsService">
		    <password-encoder ref="bcryptEncoder"/>
		</authentication-provider>
	</authentication-manager>
	<global-method-security secured-annotations="enabled" />
</beans:beans>  

3. Spring and Hibernate XML Configuration

Find the spring and hibernate integration using XML configuration.
db-config.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:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

	<context:property-placeholder location="classpath:database.properties"/> 
	<bean id="basicDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${database.driverClassName}" />
		<property name="url" value="${database.url}" />
		<property name="username" value="${database.username}" />
		<property name="password" value="${database.password}" />
	</bean>
	<bean id="localSessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
	    <property name="dataSource" ref="basicDataSource"/>
	    <property name="hibernateProperties">
			<props>
			   <prop key="hibernate.dialect">${hibernate.dialect}</prop>
			   <prop key="hibernate.id.new_generator_mappings">${hibernate.id.new_generator_mappings}</prop>
			   <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
			   <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>			   
			</props>
	    </property>
            <property name="packagesToScan" value="com.concretepage.entity"/> 
	</bean>
	<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
	    <property name="sessionFactory" ref="localSessionFactory" />
	</bean>
	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
		<constructor-arg name="sessionFactory" ref="localSessionFactory"/>  
	</bean>	
	<bean class="com.concretepage.dao.ArticleDAO" />
	<bean class="com.concretepage.dao.UserInfoDAO" />
	<tx:annotation-driven transaction-manager="txManager" /> 		
</beans>  

4. Spring MVC XML Configuration

Find the spring MVC configuration with message converter using XML configuration.
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
        
	<context:component-scan base-package="com.concretepage" />
	<bean name="jackson2ObjectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
	    <property name="indentOutput" value="true"/>
	</bean>    
	<mvc:annotation-driven>
	    <mvc:message-converters>
	        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
	            <property name="objectMapper" ref="jackson2ObjectMapper" />
	        </bean>
	    </mvc:message-converters>
	</mvc:annotation-driven>
</beans> 

5. Create web.xml

Find the web.xml file.
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_3_0.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>Spring 4 REST Security Example</display-name>
	<context-param>
	    <param-name>contextConfigLocation</param-name>
	    <param-value>
	       /WEB-INF/dispatcher-servlet.xml
	       /WEB-INF/security-config.xml
	       /WEB-INF/db-config.xml
	    </param-value>		    
	</context-param>	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
		    org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- Spring Security Configuration -->
	<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>
</web-app> 

Create REST Web Service Client using RestTemplate

To consume the REST web service, we are using RestTemplate. For authentication we will pass Base64 encoded credential as username:password token in HttpHeaders with Basic authorization.
RestClientUtil.java
package com.concretepage.util;
import java.net.URI;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
public class RestClientUtil {
    private HttpHeaders getHeaders() {
    	String credential="mukesh:m123";
    	//String credential="tarun:t123";
    	String encodedCredential = new String(Base64.encodeBase64(credential.getBytes()));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
     	headers.add("Authorization", "Basic " + encodedCredential);
    	return headers;
    }
    public void getArticleByIdDemo() {
    	HttpHeaders headers = getHeaders();  
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/spring-app/user/article/{id}";
        HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article.class, 1);
        Article article = responseEntity.getBody();
        System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
                 +", Category:"+article.getCategory());      
    }
    public void getAllArticlesDemo() {
    	HttpHeaders headers = getHeaders();  
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/spring-app/user/articles";
        HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
        ResponseEntity<Article[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article[].class);
        Article[] articles = responseEntity.getBody();
        for(Article article : articles) {
              System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
                      +", Category: "+article.getCategory());
        }
    }
    public void addArticleDemo() {
    	HttpHeaders headers = getHeaders();  
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/spring-app/user/article";
	Article objArticle = new Article();
	objArticle.setTitle("Spring REST Security using Hibernate");
	objArticle.setCategory("Spring");
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(objArticle, headers);
        URI uri = restTemplate.postForLocation(url, requestEntity);
        System.out.println(uri.getPath());    	
    }
    public void updateArticleDemo() {
    	HttpHeaders headers = getHeaders();  
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/spring-app/user/article";
	Article objArticle = new Article();
	objArticle.setArticleId(1);
	objArticle.setTitle("Update:Java Concurrency");
	objArticle.setCategory("Java");
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(objArticle, headers);
        restTemplate.put(url, requestEntity);
    }
    public void deleteArticleDemo() {
    	HttpHeaders headers = getHeaders();  
        RestTemplate restTemplate = new RestTemplate();
	String url = "http://localhost:8080/spring-app/user/article/{id}";
        HttpEntity<Article> requestEntity = new HttpEntity<Article>(headers);
        restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Void.class, 4);        
    }
    public static void main(String args[]) {
    	RestClientUtil util = new RestClientUtil();
        //util.getArticleByIdDemo();
    	util.getAllArticlesDemo();
    	//util.addArticleDemo();
    	//util.updateArticleDemo();
    	//util.deleteArticleDemo();
    }    
} 
Here we are performing create, read, update and delete (CRUD) operation. We can test the application using credentials mukesh/m123 with admin role and tarun/t123 with user role.

Run Application

To build and run the demo application, follow the steps.
1. Import database in MySQL given above on this page.
2. Download the source code from the link given below on this page.
3. Go to the root directory of the project using command prompt.
4. Build the project using gradle with following command.
gradle clean build 
We can find WAR file in the build\libs directory. If we want to build the project using maven, use following command.
mvn clean package 
We can find WAR file in the target directory.
5. Deploy the WAR file using tomcat.
6. To test the application, run RestClientUtil file with main() method. Suppose we want to perform read operation to fetch all articles, we will get following output.
Id:1, Title:Java Concurrency, Category: Java
Id:2, Title:Hibernate HQL , Category: Hibernate
Id:3, Title:Spring MVC with Hibernate, Category: Spring 

7. We can also use Postman to test the application. Find the print screen.
Spring 4 REST Security + Hibernate 5 CRUD Example using Annotation and XML


I am done now. Happy Spring learning!

Reference

Spring Security Reference

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us