Spring 4 REST Security + Hibernate 5 CRUD Example using Annotation and XML
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.
Contents
- Software Used
- Gradle and Maven to Build the Project
- MySQL Database Schema and Java Entity
- Spring 4 REST Security + Hibernate 5 CRUD Example using Annotation
- 1. Project Structure using JavaConfig in Eclipse
- 2. Implement BasicAuthenticationEntryPoint
- 3. Implement UserDetailsService
- 4. Spring REST Security JavaConfig
- 5. Spring and Hibernate JavaConfig
- 6. Spring MVC JavaConfig
- 7. Create DAO
- 8. Create Service
- 9. Create Controller
- Spring 4 REST Security + Hibernate 5 CRUD Example using XML Configuration
- 1. Project Structure using XML Configuration in Eclipse
- 2. Spring REST Security XML Configuration
- 3. Spring and Hibernate XML Configuration
- 4. Spring MVC XML Configuration
- 5. Create web.xml
- Create REST Web Service Client using RestTemplate
- Run Application
- Reference
- Download Source Code
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' }
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);
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")); } }
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; } }
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 useRestTemplate
.
1. Project Structure using JavaConfig in Eclipse
Find the project structure using JavaConfig in eclipse.2. Implement BasicAuthenticationEntryPoint
Let us know the working ofBasicAuthenticationEntryPoint
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); } }
@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; } }
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())); } }
@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 instantiateUserDetailsService
.
IUserInfoDAO.java
package com.concretepage.dao; import com.concretepage.entity.UserInfo; public interface IUserInfoDAO { UserInfo getActiveUser(String userName); }
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; } }
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); }
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); }
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); } }
@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 useRestTemplate
.
1. Project Structure using XML Configuration in Eclipse
Find the project structure using XML configuration in eclipse.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 theweb.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 usingRestTemplate
. 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(); } }
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
mvn clean package
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.
I am done now. Happy Spring learning!