Spring Boot 2.1 Building Secured Rest API using JPA -CRUD
You can download the final project from below GITHUB Repository link
Spring Boot is an awesome
module from Spring
Framework. Once you are used to it, then working with Spring is a breeze
because it takes care of all the spring container specific configurations and
allows us to focus more on our application.
Spring Boot makes it easy to create stand-alone, production-grade Spring
based Applications that you can "just run".
We take an opinionated view of the Spring platform and third-party
libraries so you can get started with minimum fuss. Most Spring Boot
applications need very little Spring configuration.
Features
·
Create stand-alone Spring applications
·
Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
·
Provide opinionated 'starter' dependencies to simplify your build
configuration
·
Automatically configure Spring and 3rd party libraries whenever possible
·
Provide production-ready features such as metrics, health checks and
externalized configuration
·
Absolutely no code generation and no requirement for XML configuration
REST
web services are very popular these days, So Let’s get our hand dirty by creating a RESTful JPA web service using Spring Boot .
Spring Boot REST Dependencies
Since web
services run on the server, apart from Spring Boot we
need to add Spring MVC to our project. I am using Eclipse
to create my basic spring boot project, but you can also use Spring Initializr.
When we use
Eclipse for creating Spring project, it actually uses Spring Initializr and
configures it. Let’s get started.
Spring Boot
REST Project
1>
Create new
Spring Starter Project as shown in below image in STS. Or if you are using Eclipse
then it should have Spring support for this, all the latest Eclipse release has
built-in Spring support.
Name:
SpringBoot2_Secured_JPA_Rest006
Packaging -> War
Package
-> com.smita.springboot
Description
->Demo project for Spring Boot2 Secured JPA Rest API
Hit on Next
3 3>
Next screen
asks to add dependencies apart from Spring Boot. Add “Web” dependencies and
click next. Select the project dependencies
a.
Web
b.
Security
c.
JPA
d.
DevTools
e.
Oracle (not available, therefore later we will
add it explicitly later in pom.xml)
4>
We could
have Hit on Finish in the earlier screen, but clicking on next provides us the
Spring Initializr URL that we can use to create this project easily through the
command line.
5>
Below image
shows the contents of the auto-generated project Structure, Most important of
these is
SpringBootRestApplication
class that is configured as Spring Boot application
and contains java main method. When we run this class, it automatically runs
our project as Spring Boot Web project.
6>
pom.xml
-> lets Add Oracle database Dependencies and repository and after that your Final
pom.xml will look like below:
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent
from repository -->
</parent>
<groupId>com.smita.springboot</groupId>
<artifactId>SpringBoot2_Secured_JPA_Rest006</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringBoot2_Secured_JPA_Rest006</name>
<description>Demo project for Spring Boot2
Secured JPA Rest API</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
</dependencies>
<!-- Repository for
ORACLE ojdbc6. -->
<repositories>
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7>
Now we will
create 2 sql files in src/main/resources folder.
a.
emp-ddl.sql (Note: delete the drop query if you want to drop the existing emp_rest Table)
/*DROP TABLE emp_rest;*/
CREATE Table emp_rest(
employee_id numeric(6)
primary key,
name varchar(30),
salary numeric(6,2));
b.
emp.dml.sql
INSERT into emp_rest VALUES
(1,'Smita',9999.00);
INSERT into emp_rest VALUES
(2,'Rita',8888.00);
INSERT into emp_rest VALUES (3,'Raj',7777.00);
8> Lets Modify the application.properties
file in -> src/main/resources
folder.
#FOR CHANGING EMBEDED TOMCAT SERVER PORT NUMBER
server.port=8082
#DATASOURCE - ORACLE
spring.datasource.schema=classpath:/emp-ddl.sql
spring.datasource.data=classpath:/emp-dml.sql
spring.datasource.initialization-mode=always
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/orahome
spring.datasource.username=system
spring.datasource.password=system
#JPA
spring.jpa.generate-ddl=false
spring.jpa.database-platform=org.hibernate.dialect.OracleDialect
spring.jpa.show-sql=true
#SECURITY
spring.mvc.dispatch-options-request=true
spring.security.user.name=smita
spring.security.user.password=smita@123
spring.security.enable-csrf=false # Enable Cross Site Request Forgery support.
#IF YOU DONT WANT DEAFULT ERROR THEN MAKE IT FALSE
server.error.whitelabel.enabled=true
9>
Now let’s do the maven build
Right click on project ->
run as -> Maven build …
10>
Now enter the Goals ->
clean package -> Run
11>
Following output you will
receive in the console after running maven build -> clean package
. ____ _ __ _ _
/\\
/ ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/
___)| |_)| | | | | || (_| | ) ) )
)
' |____| .__|_| |_|_| |_\__, | /
/ / /
=========|_|==============|___/=/_/_/_/
::
Spring Boot :: (v2.1.1.RELEASE)
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0,
Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] ---
maven-war-plugin:3.2.2:war (default-war) @ SpringBoot2_Secured_JPA_Rest006 ---
[INFO] Packaging webapp
[INFO] Assembling webapp
[SpringBoot2_Secured_JPA_Rest006] in [E:\Spring
boot\WS\SpringBoot2_Secured_JPA_Rest006\target\SpringBoot2_Secured_JPA_Rest006-0.0.1-SNAPSHOT]
[INFO] Processing war project
[INFO] Copying webapp resources
[E:\Spring boot\WS\SpringBoot2_Secured_JPA_Rest006\src\main\webapp]
[INFO] Webapp assembled in [1267
msecs]
[INFO] Building war: E:\Spring boot\WS\SpringBoot2_Secured_JPA_Rest006\target\SpringBoot2_Secured_JPA_Rest006-0.0.1-SNAPSHOT.war
[INFO]
[INFO] ---
spring-boot-maven-plugin:2.1.1.RELEASE:repackage (repackage) @ SpringBoot2_Secured_JPA_Rest006
---
[INFO] Replacing main artifact with
repackaged archive
[INFO]
------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO]
------------------------------------------------------------------------
[INFO] Total time: 37.004 s
[INFO] Finished at:
2018-12-21T16:01:04+05:30
[INFO]
------------------------------------------------------------------------
12>
Now right click on project -> Run As ->
Spring Boot App
13>
In Console you see that
a. Embedded tomcat server
will start.
b. Implicitly DataSource
will be created by HikariPool CP
(Connection Pool)
c. JPA Entity Manager initialized
d. Spring Security filter initialized
e. Magic of SpringBoot project started in just few seconds 😊
14> Now
open Browser and type -> localhost:8082
You will find that SpringBootSecurity login page will
Appear
15>
Enter the username and
password which we had set in the application.properties
file
Username: smita
Password:
smita@123
16>
Now you will see the
SpringBoot default error page as
we have not created any Controller.
17> Now that our base Spring Boot REST application is ready, it’s time
to add some endpoints and business logic to it.
We will use a java bean class for sending REST web service
response. Let’s Create a Entity, Repository, Service and RestController
18>Create Employee class in the package com.smita.springboot.entities
package com.smita.springboot.entities;
import
javax.persistence.Column;
import javax.persistence.Entity;
import
javax.persistence.GeneratedValue;
import
javax.persistence.GenerationType;
import
javax.persistence.Id;
import
javax.persistence.SequenceGenerator;
import
javax.persistence.Table;
/** @author Smita **/
@Entity //
tell JPA that this class object need to be persisted
@Table(name="emp_rest") // tell JPA
that this class object need to be mapped with this table
public class Employee {
@Id //Primary key
//@GeneratedValue(strategy=GenerationType.TABLE)
@SequenceGenerator(name="EMP_GEN"
,sequenceName="emp_master_seq",allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="EMP_GEN")
@Column(name="employee_id")
private
Long employeeId;
private
String name;
private
Double salary;
//no-arg
constr
public
Employee() {
//
TODO Auto-generated
constructor stub
}
//overloaded
constr
public
Employee(Long employeeId, String name, Double salary) {
super();
this.employeeId = employeeId;
this.name = name;
this.salary = salary;
}
public
Employee(String name, Double salary) {
super();
this.name = name;
this.salary = salary;
}
//getters
and setters
public
Long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Long employeeId) {
this.employeeId = employeeId;
}
public
String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public
Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
//toString()
@Override
public
String toString() {
return "Employee [employeeId=" + employeeId + ",
name=" + name + ", salary=" + salary + "]";
}
}
19> Create EmployeeException class in the package com.smita.springboot.exception
package com.smita.springboot.exception;
/** @author Smita **/
public class EmployeeException extends Exception {
private static final long serialVersionUID = -1648287564068549359L;
public EmployeeException() {
super();
}
public EmployeeException(String message) {
super(message);
}
}
20> Create IEmployeeDao interface in the package com.smita.springboot.dao
package com.smita.springboot.dao;
import java.util.List;
import com.smita.springboot.entities.Employee;
import com.smita.springboot.exception.EmployeeException;
/** @author Smita **/
public interface IEmployeeDao {
public Long addEmployee(Employee employee)throws EmployeeException;//C-create
public List<Employee>
getEmployeeList()throws EmployeeException;//R All Employee -retrieve
public boolean updateEmployee(Employee employee)throws EmployeeException;//U-update
public boolean deleteEmployeeById(Long empId)throws EmployeeException;//D-delete
public Employee getEmployeeById(Long empId)throws EmployeeException;//S-search
}
21> Create EmployeeDao class in the package com.smita.springboot.dao
package com.smita.springboot.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;
import com.smita.springboot.entities.Employee;
import com.smita.springboot.exception.EmployeeException;
/** @author Smita **/
//prep-work 1- @Repository
EmployeeDao
@Repository
public class EmployeeDao implements IEmployeeDao {
//prep-work 2 -> @PersistenceContext EnttityManager
Object
@PersistenceContext
private EntityManager entityManager;
@Override
public Long addEmployee(Employee employee) throws EmployeeException {
entityManager.persist(employee);
return employee.getEmployeeId();
}
@SuppressWarnings("unchecked")
@Override
public List<Employee>
getEmployeeList() throws EmployeeException {
Query
query = entityManager.createQuery("from Employee");
return query.getResultList();
}
@Override
public Employee getEmployeeById(Long empId) throws EmployeeException {
// TODO Auto-generated method stub
return entityManager.find(Employee.class, empId);
}
@Override
public boolean updateEmployee(Employee employee) throws EmployeeException {
// TODO Auto-generated method stub
return entityManager.merge(employee)!=null;
}
@Override
public boolean deleteEmployeeById(Long empId) throws EmployeeException {
Employee
employee =getEmployeeById(empId);
if(employee!=null)
return false;
else {
entityManager.remove(employee);
return true;
}
}
}
22> Create IEmployeeService interface in the package com.smita.springboot.service
package com.smita.springboot.service;
import java.util.List;
import com.smita.springboot.entities.Employee;
import com.smita.springboot.exception.EmployeeException;
/** @author Smita **/
public interface IEmployeeService {
//CRUDS Operation
public Long addEmployee(Employee employee)throws EmployeeException;//C-create
public List<Employee> getEmployeeList()throws EmployeeException;//R -retrieve
public boolean updateEmployee(Employee employee)throws EmployeeException;//U-update
public boolean deleteEmployeeById(Long empId)throws EmployeeException;//D-delete
public Employee getEmployeeById(Long empId)throws EmployeeException;//S-search
}
23> Create EmployeeService class in the package com.smita.springboot.service
package com.smita.springboot.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.smita.springboot.dao.IEmployeeDao;
import com.smita.springboot.entities.Employee;
import com.smita.springboot.exception.EmployeeException;
/** @author Smita **/
//prepwork 1- @Service
EmployeeService
@Service
public class EmployeeService implements IEmployeeService {
//prepwork 2- @Autowired
IEmployeeDao
@Autowired
private IEmployeeDao employeeDao;
@Override
@Transactional
// prepwork 3- @Transactional all method (@Transactional
we have to import from
// springFramework)
public Long addEmployee(Employee employee) throws EmployeeException {
// prepwork 4- call dao layer method and return to
Client
return employeeDao.addEmployee(employee);// auto generated emp id will
be returned
}
@Override
public List<Employee>
getEmployeeList() throws EmployeeException {
// call Dao layer method and return to Service layer
return employeeDao.getEmployeeList();
}
@Override
public Employee getEmployeeById(Long empId) throws EmployeeException {
// call Dao layer method and return to Service layer
return employeeDao.getEmployeeById(empId);
}
@Override
public boolean updateEmployee(Employee employee) throws EmployeeException {
return employeeDao.updateEmployee(employee);
}
@Override
public boolean deleteEmployeeById(Long empId) throws EmployeeException {
return employeeDao.deleteEmployeeById(empId);
}
}
Spring REST Endpoints Configuration
24>
We will create a
@RestController
and add some methods
and annotate them with @RequestMapping
. Below is our REST
Controller class that exposes few GET and POST endpoints. Create EmployeeController class in the
package com.smita.springboot.controller
package
com.smita.springboot.controller;
import
java.util.HashMap;
import java.util.List;
import java.util.Map;
import
javax.validation.Valid;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.http.HttpStatus;
import
org.springframework.http.ResponseEntity;
import
org.springframework.web.bind.annotation.CrossOrigin;
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.bind.annotation.RestController;
import
com.smita.springboot.entities.Employee;
import com.smita.springboot.exception.EmployeeException;
import
com.smita.springboot.service.IEmployeeService;
/** @author Smita **/
/*This
@CrossOrigin annotation enables cross-origin requests only for controller or
the specific method. By default, its allows all origins, all headers, the HTTP
methods specified in the @RequestMapping annotation and a maxAge of 30 minutes
is used. You can customize this behavior by specifying the value of one of the
annotation attributes: origins, methods, allowedHeaders, exposedHeaders, allowCredentials
or maxAge. In this example, we only allow http://localhost:8082 to send
cross-origin requests.*/
//prep-work
1> @CrossOrigin
@CrossOrigin(origins = "*", allowedHeaders = "*")
//prep-work
2> @RestController
@RestController
//prep-work
3> @RequestMapping
@RequestMapping("/api/employees")
public class EmployeeController {
//prep-work
4> @Autowired IEmployeeService
@Autowired private
IEmployeeService employeeService;
@GetMapping(value="",produces="application/json")
public
List<Employee> getAll() throws
EmployeeException{
return employeeService.getEmployeeList();
}
@GetMapping("/{employeeId}")
public
ResponseEntity<Employee> getEmployeeById(@PathVariable(value = "employeeId") Long employeeId) throws
EmployeeException{
System.out.println("EmployeeController
-> find : "+employeeId);
Employee employee =employeeService.getEmployeeById(employeeId);
return ResponseEntity.ok().body(employee);
}
@PostMapping("/save")
public
HttpStatus saveEmployee(@RequestBody
Employee employee) throws
EmployeeException {
return employeeService.addEmployee(employee) != null?
HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
}
@PutMapping("/{employeeId}")
public
HttpStatus updateEmployee(@PathVariable(value = "employeeId") Long employeeId,
@Valid @RequestBody Employee employeeDetails) throws
EmployeeException {
Employee employee = employeeService.getEmployeeById(employeeId);
if(employee==null)
return HttpStatus.BAD_REQUEST;
else {
employee.setName(employeeDetails.getName());
employee.setSalary(employeeDetails.getSalary());
return employeeService.updateEmployee(employee)? HttpStatus.ACCEPTED : HttpStatus.BAD_REQUEST;
}
}
@DeleteMapping("/{employeeId}")
public Map<String, Boolean> deleteEmployee(@PathVariable(value
= "employeeId") Long employeeId) throws
EmployeeException{
Employee employee = employeeService.getEmployeeById(employeeId);
Map<String, Boolean> response = new HashMap<>();
if(employee!=null) {
employeeService.deleteEmployeeById(employeeId);
response.put("deleted", Boolean.TRUE);
}
return response;
}
}
·
When we annotate the controller class with @RestController, Spring Boot scans
it to find the REST endpoints to configure.
·
@RequestMapping annotation on methods tells
Spring to use this method as handler for any client requests. This is very
important spring annotation, we can configure additional features such as HTTP
methods supported, Content-Type of request, response content type etc. By default,
GET method is supported and JSON response is returned.
That’s it, our Spring
Boot RESTful web service is ready to run and test.
1>
Auto-Generated SpringBoot2SecuredJpaRest006Application class in the package com.smita.springboot By Spring Boot Starter Project
package com.smita.springboot;
/** @author Smita **/
import
org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class
SpringBoot2SecuredJpaRest006Application {
public static void
main(String[] args) {
SpringApplication.run(SpringBoot2SecuredJpaRest006Application.class, args);
}
}
2>
Auto-Generated ServletInitializer class in the package com.smita.springboot By Spring Boot
Starter Project.
package com.smita.springboot;
/** @author Smita **/
import
org.springframework.boot.builder.SpringApplicationBuilder;
import
org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder
application) {
return application.sources(SpringBoot2SecuredJpaRest006Application.class);
//return application.sources(JavaApplication.class);//for
stand-alone java application
}
}
3>
Run As Maven-> Build
->Then finally,Now its time to Run your project as Spring Boot App.
4>
Now open Browser and type
-> localhost:8082/employees
You will find that
SpringBootSecurity login page will Appear
5>
Enter the Username: smita
Password:
smita@123
-> Login -> You can see
the List of Employees
I am using Postman Chrome app
for testing POST requests.
Spring Boot REST JSON Request Response
JSON is the
standard messaging format for REST web services, our method accept JSON
request.
Summary
In this post, we
learned how to use Spring Boot to create a RESTful JPA web service. Spring Boot
did all the configurations and we only had to focus on our business logic. You
can download the final project from below GITHUB
Repository link.
No comments:
Post a Comment